前言
现在 ES6 已经非常普及了,基本上前端新出的框架都用上了ES6的语法。作为新兴时代的前端,如果你还对 ES6 不了解那就真的过分了,兄弟们赶紧撸起袖子搞起来吧!附上阮一峰写的书 ECMAScript 6 入门
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言
ECMAScript 和 JavaScript 的关系
ECMAScript 是 Javascript 的规范,Javascript 是 ECMAScript 的实现
声明的新方式 let / const
使用ES6,我们需要全面使用let/const替换var,我们常常使用let来声明一个值会被改变的变量,而使用const来声明一个值不会被改变的变量,也可以称之为常量。
1. let
不同于 var,let 声明的变量只在 let 命令所在的代码块内有效
1 2 3 4 5 6 7
| { let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1
|
for 循环的计数器,就很合适使用let命令
下面的代码使用 var 声明 i,console 里面的 i 是全局声明的,会随着循环而变化最后为 10,使得 a[0] , a[1] … a[9] 函数里面的 i 都是 10,所以最后 a6 结果也是 10
1 2 3 4 5 6 7
| var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10
|
而使用 let 声明的变量仅在块级作用域内有效,如下,当前的 i 只在本轮循环有效,所以每一次 console 的 i 其实都是一个新的变量,所以输出是 6
1 2 3 4 5 6 7
| var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
|
let 不存在变量提升
var 声明的变量,可以在声明之前使用,值为undefind
而 let 声明的变量一定要在声明后使用,否则报错
1 2 3 4 5 6 7
| // var 的情况 console.log(foo); // 输出undefined var foo = 2; // let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
|
暂时性死区
只要块级作用域内存在 let 命令,它所声明的变量就“绑定”这个区域,不再受外部的影响。在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
1 2 3 4 5 6 7 8 9 10 11
| if (true) { // TDZ开始 tmp = 'dota'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ结束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123 }
|
不允许重复声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function () { let a = 10; var a = 1;// 报错 } function () { let a = 10; let a = 1;// 报错 } function func(arg) { let arg; // 报错 } function func(arg) { { let arg; // 不报错 } }
|
2. 块级作用域
ES5
1 2 3 4 5 6 7 8 9 10
| var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; // if代码块内var变量提升,导致内层的tmp变量覆盖了外层的tmp变量。 } } f(); // undefined
|
ES6
1 2 3 4 5 6 7
| function f1() { let n = 5; if (true) { let n = 10; // if代码块内声明了新的n变量,外层代码块不受内层代码块的影响 } console.log(n); // 5 }
|
块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了
1 2 3 4 5 6 7 8 9 10 11
| // IIFE 写法 (function () { var tmp = ...; ... }()); // 块级作用域写法 { let tmp = ...; ... }
|
3. const
const声明一个只读的常量。一旦声明,常量的值就不能改变。
1 2 3
| const COUNT = 10 COUNT = 11; console.log(COUNT) //Uncaught TypeError: Assignment to constant variable.
|
对于const来说,只声明不赋值,就会报错。
1 2
| const foo; // SyntaxError: Missing initializer in const declaration
|
const 声明与 let 基本相同
- 只在声明所在的块级作用域内有效。
- const命令声明的常量也是不提升
- 同样存在暂时性死区,只能在声明的位置后面使用。
- const声明的常量,也与let一样不可重复声明。
const本质
const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const 只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const foo = {}; // 可以为 foo 添加一个属性 foo.prop = 123; foo.prop // 123 // 但是如果将 foo 指向另一个对象,就会报错 foo = {}; // TypeError: "foo" is read-only const a = []; a.push("1") console.log(a) // ["1"] const a = []; a = [1,2,3] console.log(a) // 报错
|
4. 顶层对象的属性
顶层对象,在浏览器环境指的是window对象,在Node指的是global对象。ES5之中,顶层对象的属性与全局变量是等价的。
ES6一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。
1 2 3 4 5
| var a = 1; window.a // 1 let b = 1; window.b // undefined
|