声明变量:var,const,let
var声明:
使用var操作符定义的变量会成为包含它的函数的局部变量,如:使用var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
1 | function test() { |
这里,message 变量是在函数内部使用 var 定义的。函数叫 test(),调用它会创建这个变量并给
它赋值。调用之后变量随即被销毁,因此示例中的最后一行会导致错误。不过,在函数内定义变量时省
略 var 操作符,可以创建一个全局变量:
1 | function test() { |
去掉之前的 var 操作符之后,message 就变成了全局变量。只要调用一次函数 test(),就会定义
这个变量,并且可以在函数外部访问到。
var声明提升:
使用var时,下面代码不会报错。这是因为使用这个关键字声明的变量会自动提升到函数作用域顶部:
1 | function foo() { |
上述代码等同于:
1 | function foo() { |
let声明:
let声明和var声明的作用差不多,但有着非常重要的区别。最明显的区别就是,let声明的范围是作用域,而var声明的范围是函数作用域。
例如:
1 | if (true) { |
在这里,age变量之所以不能在if块外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于var的作用域限制同样也适用于let。
let不允许同一个块作用域中出现冗余声明。这样会导致报错。
1 | let age; |
对声明冗余报错不会因混用 let 和 var 而受影响。这两个关键字声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在。
1 | var name; |
暂时性死区:
let不会在作用中被提升
1 | // name 会被提升 |
在解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前不能以任何方式来引用未声明的变量。在 let 声明之前的执行瞬间被称为“暂时性区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出 ReferenceError。
全局变量:
与 var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声
明的变量则会)。
1 | var name = 'Matt'; |
不过,let 声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了避免 SyntaxError,必须确保页面不会重复声明同一个变量。
条件声明:
在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它。
为此,对于 let 这个新的 ES6 声明关键字,不能依赖条件声明模式。
const声明:
const声明变量时必须同时初始化变量,且尝试修改const声明的变量会导致运行时错误, const 也不允许重复声明,const 声明的作用域也是块。
如:
1 | const age = 26; |
const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量引用的是一个对象,
那么修改这个对象内部的属性并不违反 const 的限制。
1 | const person = {}; |
JavaScript 引擎会为 for 循环中的 let 声明分别创建独立的变量实例,虽然 const 变量跟 let 变量很相似,但是不能用 const 来声明迭代变量(因为迭代变量会自增):
1 | for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值 |