新的声明方式
声明方式
var 声明语句声明一个变量,并可选地将其初始化为一个值。
语法:
1 | var varname1 = [= value1][, varname2][= value2]...[, varnameN][=valueN]; |
varname
变量名。变量名可以定义为任何合法标识符。
valueN
变量的初始化值。默认值是 undefined。
描述:
变量声明,无论发生在何处,都在执行任何代码之前进行处理。
用var声明的变量的作用域是它当前的执行上下文。
重新声明一个 JavaScript 变量,它将不会丢失其值。
将赋值给未声明变量的值在执行赋值时将其隐式地创建为全局变量(它将成为全局对象的属性)。
声明和未声明变量之间的差异是:
声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的。
1
2
3
4
5
6
7
8
9function x(){
y = 1; // 在严格模式(strict mode)下会抛出 ReferenceError 异常
var z = 2;
}
x();
console.log(y); // 打印 “1”
console.log(z); // 抛出 ReferenceError: z 未在 x 外部声明声明变量在任何代码执行前创建,而非声明变量只有在执行赋值操作的时候才会被创建。
1
2
3
4console.log(y);
y = 1;
console.log(y);
// 打印 Error: y is not defined1
2
3console.log(y); // undefined 变量的初始化值。默认值是 undefined。
var y = 1;
console.log(y); // 1声明变量是它所在上下文环境的不可配置属性,非声明变量是可配置的(如非声明变量可以被删除)。
1
2
3
4
5
6
7
8var a = 1;
b = 2;
delete this.a; // 在严格模式(strict mode)下抛出TypeError,其他情况下执行失败并无任何提示。
delete this.b;
console.log(a, b); // 抛出ReferenceError。
// 'b'属性已经被删除。由于这三个差异,未能声明变量将很可能导致意想不到的结果。因此,建议始终声明变量,无论它们是在函数还是全局作用域内。 而且,在 ECMAScript 5 严格模式下,分配给未声明的变量会引发错误。
变量提升
由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。这意味着变量可以在声明之前使用,这个行为叫做“hoisting”。“hoisting”就像是把所有的变量声明移动到函数或者全局代码的开头位置。
1 | bla = 2; |
因此,建议始终在作用域顶部声明变量(全局代码的顶部和函数代码的顶部),这可以清楚知道哪些变量是函数作用域(本地),哪些变量在作用域链上解决。
重要的是,提升将影响变量声明,而不会影响其值的初始化。当到达赋值语句时,该值将确实被分配:
1 | function do_something() { |
声明并初始化两个变量:
1 | var a = 0, b = 0; |
给两个变量赋值成字符串值:
1 | var a = "A"; |
多个变量的初始化
1 | var x = 0; |
隐式全局变量和外部函数作用域
1 | var x = 0; // x是全局变量,并且赋值为0。 |
let 语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。
语法:
1 | let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]; |
var1, var2, …, varN
变量名。必须是合法的标识符。
value1, value2, …, valueN
变量的初始值。可以是任意合法的表达式。
描述:
let 允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与 var 关键字不同的是,var 声明的变量只能是全局或者整个函数块的。 var 和 let 的不同之处在于后者是在编译时才初始化。
就像const 一样,let不会在全局声明时(在最顶部的范围)创建window 对象的属性。
作用域规则
let声明的变量只在其声明的块或子块中可用,这一点,与var相似。二者之间最主要的区别在于var声明的变量的作用域是整个封闭函数。
1 | function varTest() { |
在函数或代码顶部,let 不会在全局对象里新建一个属性。var声明会给全局对象新增属性。
1 | var x = 'global'; |
模仿私有成员
在处理构造函数的时候,可以通过 let 声明而不是闭包来创建一个或多个私有成员。
1 | var Thing; |
可以使用var创建和闭包具有相同隐私模式的局部变量,但是它们需要函数作用域(通常是模块模式中的IIFE),而不仅仅是上面示例中的块作用域。
重复声明
在同一个函数或块作用域中重复声明同一个变量会引起SyntaxError。
1 | if (x) { |
然而,需要特别指出的是,一个嵌套在 case 子句中的块会创建一个新的块作用域的词法环境,就不会产生上诉重复声明的错误。
1 | let x = 1; |
暂存死区
与通过 var 声明的有初始化值 undefined 的变量不同,通过 let 声明的变量直到它们的定义被执行时才初始化。在变量初始化前访问该变量会导致 ReferenceError。该变量处在一个自块顶部到初始化处理的“暂存死区”中。
1 | function do_something() { |
暂存死区与 typeof
与通过var声明的变量, 有初始化值 undefined和只是未声明的变量不同的是,如果使用typeof检测在暂存死区中的变量, 会抛出ReferenceError异常:
1 | // prints out 'undefined' |
const
常量是块级作用域,很像使用 let 语句定义的变量。常量的值不能通过重新赋值来改变,并且不能重新声明。
语法:
const name1 = value1 [, name2 = value2 [, … [, nameN = valueN]]];
nameN
常量名称,可以是任意合法的标识符。
valueN
常量值,可以是任意合法的表达式。
描述:
此声明创建一个常量,其作用域可以是全局或本地声明的块。 与var变量不同,全局常量不会变为窗口对象的属性。需要一个常数的初始化器;也就是说,您必须在声明的同一语句中指定它的值(这是有道理的,因为以后不能更改)。
const 声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(例如,其参数)。
一个常量不能和它所在作用域内的其他变量或函数拥有相同的名称。
示例
1 | // 注意: 常量在声明的时候可以使用大小写,但通常情况下全部用大写字母。 |
总结归纳
使用var声明建议
建议始终在全部代码的顶部和函数代码的顶部声明变量.
使用var需要注意:
声明提前/变量提升。(变量声明在任意代码执行之前处理)
未声明的变量是全局变量,未声明的变量赋值才会被创建。
全局声明时,创建 window 对象的属性
1 | var a; |
使用let需要注意:
同一个函数或块作用域不能重复声明。
暂存死区(通过 let 声明的变量直到它们的定义被执行时才初始化)。
不会创建window 对象的属性
1 | console.log(typeof undeclaredVariable); // undefined |
使用const建议:
建议变量名全部用大写字母。例如MY_FAV
使用const需要注意:
同一个函数或块作用域不能重复声明。
不能重新赋值。
声明同时指定值,值只读引用,值是对象时可改变。
以上是我对下列视频及文章的归纳和总结。
ES6 免费视频教程
参考资料:
MDN var
MDN let
MDN var
ECMAScript 6 入门-let和const 命令
ES6的开发环境搭建
相关代码仓库:
ES6
install_url
to use ShareThis. Please set it in _config.yml
.