let命令
基本用法
ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
for循环的计数器,就很合适使用let命令。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6 //E5用var 结果就是10//变量i是let声明的,当前的i只在本轮循环有效。每一次循环的i其实都是一个新的变量,所以最后输出的是6。 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
用ES5如何正确实现?(梁涛注)
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function (i) {
return function(){ //闭包
console.log(i);
}
})(i);//立即执行函数
}
a[6](); // 6//运行步骤:先把a[0]到a[9]全部赋值一遍(返回闭包),存于内存中。当执行到a[6]()时,输出结果。//闭包容易导致内存泄露
不存在变量提升
var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。
let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
console.log(a) // ReferenceError: a is not defined. (梁涛注)实际运行结果也是undefined。只有let a在对象内部时,在外面调用a,才会报ReferenceError错误。console.log(b) // undefined
let a = 10; var b = 1;
不允许重复声明
let不允许在相同作用域内,重复声明同一个变量
// 报错
function func() {
let a = 10;
var a = 1;
}
// 报错
function func() {
let a = 10;
let a = 1;
}
function func(arg) {//不能在函数内部重新声明参数
let arg;
}
func() // 报错
块级作用域
块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。
// IIFE 写法
(function () {
var tmp = ...;
...
}());
ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
// 报错
if (true) let x = 1; //正确写法 if(true){let x=1}
const命令
基本用法
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415; PI // 3.1415 PI = 3; // TypeError: Assignment to constant variable.
const一旦声明变量,就必须立即初始化。
const的作用域与let命令相同:只在声明所在的块级作用域内有效。
const声明的常量,也与let一样不可重复声明。
ES6 声明变量的六种方法
ES5 只有两种声明变量的方法:var命令和function命令。ES6 除了添加let和const命令,还有import命令和class命令。
顶层对象的属性
顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。
ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
var a = 1; // 如果在 Node 的 REPL 环境,可以写成 global.a // 或者采用通用方法,写成 this.a window.a // 1 let b = 1; window.b // undefined