JS变量声明var、let、const详解

JavaScript 中的变量是松散类型的,可以保存任何类型数据,变量只不过是一个名称。JavaScript 中,可以声明变量的关键字有var、let和const。

一、var

使用var定义变量,可以保存任何类型的值。若不初始化变量,变量会保存undefined。

1.1函数级作用域

使用var定义的变量会成为包含它的函数的局部变量。

function func() {
    var a = 'hi'; // 局部变量
}
func();
console.log(a); // ReferenceError: a is not defined

变量a在函数内部使用var定义,调用函数func,会创建这个变量并给它赋值。函数执行结束后,变量就会被销毁,所以上述代码最后一行会报错,显示变量a未定义。

若在函数内部,不使用var操作符,直接给变量a赋值,那么a就成为了全局变量,可以在函数外部访问到。在浏览器环境下,a成为window对象的属性。

function func() {
    a = 'hi'; // 全局
}
func();
console.log(a); // hi
console.log(window.a); // hi
console.log(window.a === a); // true

1.2 变量提升

使用var声明变量,会自动提升到函数作用域顶部,如下代码:

function func() {
    console.log(a);
    var a = 1;
}
func(); // undefined

代码没有报错,输出了undefined,这是因为变量的声明被提升到了函数作用域顶部,等价于如下代码:

function func() {
    var a;
    console.log(a);
    a = 1;
}
func(); // undefined

1.3 重复声明

另外,使用var重复声明同一个变量也可以:

function func() {
    var a = 1;
    var a = 2;
    var a = 3;
    console.log(a);
}
func(); // 3

1.4 全局变量挂载到 window

浏览器环境中,全局作用域下,使用var声明的变量,会挂载到window对象上。

var a = 1;
console.log(window.a === a); // true

一道面试题:

console.log("1":a,b);
var a = 12,b="34";
function foo(){
    console.log("2":a,b);
    var a=b=12;
    console.log("3":a,b);
}
foo()
console.log("4":a,b);

答案:
1 : undefined,undefined //变量已经声明但是未赋值,这里为什么会说变量已经声明了,是因为js编译时会把所有的变量声明到最前面,其次是函数的声明
2: undefined, ‘34’ //因为下面的var a=又把a声明了一次所以,a就又是undefined,注意这里b并没有被声明,如果把var a=b=12改成,var a=12,b=12那么答案就是undefined,undefined
3: 12,12 //a,b均已声明并赋值
4: 12,12 //a,b均已声明并赋值,但是这里要和上一个区分,b=12是因为在函数中重新赋值了。就如第二条所说,如果把var a=b=12改成,var a=12,b=12那么答案就是12,“34”并且这个12是第二行赋值的。

二、let

let也可以声明变量,但和var操作符有很大的区别。

2.1 块级作用域

以下代码会报错,因为let声明的作用域,具有块级作用域,即被{}包裹的部分。

if (true) {
    let a = 10;
}
console.log(a); // a is not defined

2.2 不可重复声明

以下代码,执行到let a = 2就会报错,因为变量a在当前块级作用域中已经被声明过了,不能重复声明。

if (true) {
    let a = 1;
    let a = 2; // SyntaxError: Identifier 'a' has already been declared
    let a = 3;
}

另外,如果混用var和let声明变量,也是不允许的,下面的代码都会报错:

let a;
var a; // 报错
var a;
let a; // 报错

2.3 不存在变量提升(暂时性锁区)

使用let声明的变量,不能在声明之前访问它。

if (true) {
    console.log(a); // ReferenceError: Cannot access 'a' before initialization
    let a = 1;
}

实际上,JavaScript 也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为暂时性死区。

2.4 全局变量不会挂载到 window

和var不同,即使在全局作用域下,使用let声明的变量也不会挂载到window对象。

var a = 1;
let b = 2;
console.log(window.a === a); // true
console.log(window.b === b); // false

2.5 不依赖条件声明

if (typeof name === 'undefined') {
    let name;
}
// name 被限制在 if {} 块的作用域内
name = 'Matt'; // 全局赋值

try {
    console.log(age); // 如果 age 没有声明过,则会报错
} catch (error) {
    let age;
}
// age 被限制在 catch {}块的作用域内
age = 26; // 全局赋值

三、 const

const的特点与let基本一致,但const有一些自己的特点。

3.1 声明变量时必须同时初始化

以下声明报错,因为声明的同时没有初始化变量。

const a; // Missing initializer in const declaration

3.2 不能修改声明后的变量

使用const定义了一个变量后,不能再更改它的值:

const a = 1;
a = 2; // TypeError: Assignment to constant variable

这里有一个误区,实际上,使用const声明的变量,不能修改的是内存地址!!

具体规则如下:

  • 当const定义的常量为基本数据类型时,不能被修改。
  • 当const定义的常量为引用数据类型时,可以通过其属性进行数据修改。

基本数据类型的值就保存在内存地址中,所以const定义的基础数据类型不可被改变。 而引用数据类型指向的内存地址只是一个指针,通过指针来指向实际数据,也就是说,不可被改变的是指针,而不是数据,所以const定义的引用数据类型的常量可以通过属性来修改其数据。

例如,使用const定义了一个数组,虽然不能更改数据类型,但可以通过push等方法,修改这个数组中的数据。

const arr = [];
arr.push(1, 2, 3);
console.log(arr); // [ 1, 2, 3 ]

五、总结及最佳实践

varletconst
函数级作用域块级作用域块级作用域
重复声明不可重复声明不可重复声明
变量提升不存在变量提升不存在变量提升
值可更改值可更改值不可更改
全局变量挂载到window全局变量不会挂载到window全局变量不会挂载到window

通常,写 JavaScript 代码时,遵循以下原则:

  • 不使用var
  • const优先,let次之

一道面试题:

for (var i = 1; i <= 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, 0);
}

答案:6 6 6 6 6

  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈游戏开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值