一. let命令声明变量
1. 用法:let声明的变量只在所处位置的代码块内有效
//example1.js for(var i = 0;i<2;i++){ let a = 10; var b = 2; } console.log("i="+i); console.log("a="+a); console.log("b="+b);
执行结果会报错
babel-node exmple1.js
2. 不存在变量提升
//example1.js console.log(x); console.log(y); var x = 10; let y = 10;
上面代码,变量x由var声明,会发生变量提升,即脚本运行时,变量x已存在,只是没有值,输出结果为undefined。变量y由let声明,不会发生变量提升,变量y不存在,ReferenceError报错
3. 暂时性死区
只要块级作用域内存在let
命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。因此,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError let tmp; }
4. 不允许重复说明
// 报错 function () { let a = 10; var a = 1; } // 报错 function () { let a = 10; let a = 1; }
function func(arg) { let arg; // 报错 } function func(arg) { { let arg; // 不报错 } }
二. 块级作用域
1. es5只有全局作用域和函数作用域,没有块级作用域。(例如:常用的for循环中的计数器i在循环结束后,其值为最后的计数值)
2. let声明变量为es6添加了一个块级作用域。外层块无法访问内层块的变量。
3. 因为es6的块级作用域,立即执行函数(IIFE)可由块来代替。
// 立即执行函数 (function(){ var count = 10; })(); //块代替立即执行函数的功能 { let count = 10; }
4. es5规定函数声明在顶层作用域或函数作用域中才是合法的,块里声明在严格模式下会报错。es6则允许在块级作用域里以let的行为声明函数(尽量避免在块里使用函数声明语句,如果需要,使用函数表达式)
//es5报错 "use strict"; if(true){ function count(){ console.log(1); } }
//es6不报错 "use strict"; if(true){ function count(){ console.log(1); } }
三. do表达式(使块级作用域有返回值)
四. const命令声明一个只读的常量,声明后值不会被改变。
1. 声明后改变常量的值会报错。
2. 只声明不赋值会报错。
3. 类似let的作用,只在块级作用域有效、没有变量提升、不可重复声明。
4. const命令声明的复合型变量,变量名指向数据的地址,不能保证里面的数据不变。
"use strict"; const obj = { a : 1 } obj.a =10; console.log(obj); //输出{a:10}
Object.freeze()函数可以将对象冻结。
// "use strict"; const obj = Object.freeze({ a : 1 }); obj.a =10; console.log(obj); //输出{a:1},严格模式下会报错
五. 顶层对象
es5中顶层对象(window)的属性和全局变量一致,window.a 与a是等价的,这导致了很多问题。
es6中let、const、class声明的全局变量都不属于顶层变量,顶层对象的属性逐渐与全局变量脱钩。
es5的顶层对象在各种实现里不统一,浏览器的顶层对象是window,node的顶层对象是global,浏览器和web worker里self也指向顶层对象。可以勉强使用如下方法获取准确的顶层对象。
var top = (typeof window !== "undefined" ? window :(typeof process === "object" && typeof require === "function" && typeof global === "object") ? global : this); console.log(top);