let与var的区别
2017-12-11 19:18
218 查看
let
语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。
语法
let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];
参数
var1,
var2, …,
varN变量名。可以是任意合法的标识符。
value1,
value2, …,
valueN变量的初始值。可以是任意合法的表达式。
描述
let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,它声明的变量只能是全局或者整个函数块的。
这里解释了我们为什么选取“let”这个名字。
作用域规则
let声明的变量只在其声明的块或子块中可用,这一点,与
var相似。二者之间最主要的区别在于
var声明的变量的作用域是整个封闭函数。
function varTest() { var x = 1; if (true) { var x = 2; // 同样的变量! console.log(x); // 2 } console.log(x); // 2 } function letTest() { let x = 1; if (true) { let x = 2; // 不同的变量 console.log(x); // 2 } console.log(x); // 1 }
简化内部函数代码
当用到内部函数的时候,let会让你的代码更加简洁。
var list = document.getElementById('list'); for (let i = 1; i <= 5; i++) { let item = document.createElement('li'); item.appendChild(document.createTextNode('Item ' + i)); item.onclick = function(ev) { console.log('Item ' + i + ' is clicked.'); }; list.appendChild(item); } // to achieve the same effect with 'var' // you have to create a different context // using a closure to preserve the value for (var i = 1; i <= 5; i++) { var item = document.createElement('li'); item.appendChild(document.createTextNode('Item ' + i)); (function(i){ item.onclick = function(ev) { console.log('Item ' + i + ' is clicked.'); }; })(i); list.appendChild(item); }
以上示例的工作原理是因为(匿名)内部函数的五个实例引用了变量
i的五个不同实例。注意,如果你将
let替换为
var,则它将无法正常工作,因为所有内部函数都将返回相同的
i:6的最终值。此外,我们可以通过将创建新元素的代码移动到每个循环的作用域来保持循环更清晰。
在程序或者函数的顶层,
let并不会像
var一样在全局对象上创造一个属性,比如:
var x = 'global'; let y = 'global'; console.log(this.x); // "global" console.log(this.y); // undefined
模仿私有接口
在处理构造函数的时候,可以通过let绑定来共享一个或多个私有成员,而不使用闭包:
var Thing; { let privateScope = new WeakMap(); let counter = 0; Thing = function() { this.someProperty = 'foo'; privateScope.set(this, { hidden: ++counter, }); }; Thing.prototype.showPublic = function() { return this.someProperty; }; Thing.prototype.showPrivate = function() { return privateScope.get(this).hidden; }; } console.log(typeof privateScope); // "undefined" var thing = new Thing(); console.log(thing); // Thing {someProperty: "foo"} thing.showPublic(); // "foo" thing.showPrivate(); // 1
let
暂存死区的错误
在相同的函数或块作用域内重新声明同一个变量会引发SyntaxError。
if (x) { let foo; let foo; // TypeError thrown. }
在 ECMAScript 2015 中,
let绑定不受变量提升的约束,这意味着
let声明不会被提升到当前执行上下文的顶部。在块中的变量初始化之前,引用它将会导致
ReferenceError(而使用
var 声明变量则恰恰相反,该变量的值是 undefined )。该变量处于从块开始到初始化处理的“暂存死区”。
function do_something() { console.log(bar); // undefined console.log(foo); // ReferenceError: foo is not defined var bar = 1; let foo = 2; }
在
switch声明中你可能会遇到这样的错误,因为它只有一个块.
switch (x) { case 0: let foo; break; case 1: let foo; // TypeError for redeclaration. break; }
但是,重要的是要指出嵌套在case子句内的块将创建一个新的块作用域的词法环境,这不会产生上面显示的重新声明错误。
let x = 1; switch(x) { case 0: { let foo; break; } case 1: { let foo; break; } }
与词法作用域结合的暂存死区
由于词法作用域,表达式(foo + 55)内的标识符“foo”会解析为if块的foo,而不是覆盖值为33的foo。在这一行中,if块的“foo”已经在词法环境中创建,但尚未达到(并终止)其初始化(这是语句本身的一部分):它仍处于暂存死区。
function test(){ var foo = 33; if (true) { let foo = (foo + 55); // ReferenceError } } test();
这种现象可能会使您陷入以下情况。指令
let n of n.a已经在for循环块的私有范围内,因此标识符“n.a”被解析为位于指令本身的第一部分(“let n”)中的'n'对象的属性'a' ,由于尚未达成和终止其声明,因此仍处于暂存死区。
function go(n) { // n here is defined! console.log(n); // Object {a: [1,2,3]} for (let n of n.a) { // ReferenceError console.log(n); } } go({a: [1, 2, 3]});
其他情况
当在块中使用时,let将变量的作用域限制为该块。注意
var的作用域在它被声明的函数内的区别。
var a = 1; var b = 2; if (a === 1) { var a = 11; // the scope is global let b = 22; // the scope is inside the if-block console.log(a); // 11 console.log(b); // 22 } console.log(a); // 11 console.log(b); // 2
相关文章推荐
- es6中的let声明变量与es5中的var声明变量的区别,局部变量与全局变量
- JavaScript中const、var和let区别浅析
- Js中var、let、const的区别
- ES6----var与let的区别
- js中let和var定义变量的区别
- JavaScript中const,var,let的区别
- var、let、const 的一些区别
- es6中的let 和 var 的区别
- ES6中let与var的区别
- var和let,var和const的区别
- 深入理解ES6之var,let,const区别
- js中let和var的区别
- js中const、var、let的区别
- js中var,const,let区别
- js变量中有var定义和无var定义的区别,es6中let命令和const命令
- ts和js中let和var定义变量的区别
- var与ES6中const、let声明的变量的区别
- js中const,var,let区别
- js中const,var,let区别
- 微信开发之JavaScript变量var和let的区别