在JavaScript中,变量声明是编程中非常基础的一环。随着ECMAScript 2015(ES6)的发布,JavaScript引入了新的关键字let和const,这两个新关键字改变了我们如何定义变量,并且它们与传统的var关键字存在一些本质上的差异。
var是什么意思
var是什么意思?这个问题简单,但答案却深刻。在JavaScript中,var 是一种用来声明变量的语句,它允许你为代码块中的任何地方分配一个值。使用 var 声明的变量可以被重复赋值,从而改变其原始值。此外,当 JavaScript 解释器遇到 var 关键字时,它会将该变量提升到它所在作用域的顶部。这意味着,即使你的代码结构看起来像这样:
console.log(x); // 输出: undefined
x = 10;
实际上,在执行这行代码之前,已经发生了这样的过程:
// JavaScript解释器做的事情:
if (typeof x === 'undefined') {
var x;
}
x = 10;
console.log(x); // 输出: 10
这种行为通常被称作“变量提升”或“函数级作用域”,它使得开发者必须小心地管理全局和局部范围内相同名字的变量。
let和const:新兴之星
let
let 关键字是在 ES6 中引入的一个新的声明方式,用以替代传统的 var 声明。当你使用 let 来声明一个变量时,你实际上是在创建一个有特定范围(即块级作用域)的局部变量。与 var 不同的是,让每个 block 的开始处重新初始化它,而不是整个函数体。一旦某个block结束,那么其中定义的所有 let 变量都会失效。
下面是一个例子:
{
let x = 10; // 这里是一个block, 定义了一个名为x、初始值为10 的局部变量。
console.log(x); // 输出: 10
if (true) {
let y = 20; // 在另一个block内部再次定义y。
console.log(y); // 输出: 20
y = y +1;
console.log(y); // 输出:21
}
}
console.log(x);
//输出:10
console.log(y);
//ReferenceError:y is not defined
const
const 关键词用于创建常数。这意味着一旦被赋予初值后,其绑定的不能更改。就像前面提到的 let, 它也具有块级作用域。不过,与 let 不同的是,一旦给出初始值,就不能通过直接赋值来修改它。但是,如果你试图修改包含对象或数组等可修改数据类型作为属性或元素的事物,则可以通过这些方法进行更新,因为它们自身是不可更改状态但指向可更改内容的情况。
例如,我们尝试用 const 创建并尝试修改字符串:
{
const PI = Math.PI;
try {
PI += " Pi";
throw new Error("Shouldn't reach here");
} catch(e) { }
console.assert(PI === Math.PI, "The value of PI should be unchanged");
}
当运行此段代码时,将抛出错误,因为我们企图把数字π转换成字符串"π",这是不允许对常数进行操作。在下面的示例中,我们仍然能够改变包含在对象中的属性:
{
const objA= {a :1};
try {
objA.a +=2;
throw new Error("Shouldn't reach here");
} catch(e) { }
console.assert(objA.a===3,"The value of a should have changed to the incremented number");
}
由于我们没有违反基本原则,所以不会得到异常,但是结果确实发生了变化 - 对象objA现在包含有{a :3}而不是{a :1}.
结论
总结一下,让我们回顾一下三种不同的声明方式及其含义:
使用'var'创造出的环境,是基于函数或者全局环境,不具备块级作用域。
使用'let'创造出的环境,是基于当前执行栈中的最近活动源(如function、for循环等),并且支持块级作用域。
使用'const', 类似于使用'let', 只不过对于其绑定的任何东西来说都保持不动态变化状态,即便他们可能指向动态变化数据结构,如数组或对象。如果想要让这些数据结构保持不受干扰,可以考虑浅拷贝它们,以避免意外地覆盖现有的内容。
最后,由于性能优化和最佳实践方面的问题,以及为了消除潜在bug,比起过去使用更多情况下的'declare with var', 我们应该尽可能多地采用'declare with let and const'.