ES6学习——新的语法:let

73 篇文章 23 订阅

let的主要用途就是声明块级作用域的变量,看一下规范是怎么说的,请仔细看红字部分,后边TDZ章节会详细讲这点:

13.3 let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. 


我们知道如果在全局范围内用var去声明变量,那么这个变量将会被定义在window上,但是如果在全局范围内用let或者const去声明变量,这个变量不会被放到window上,看例子:

'use strict';	
	
let s1 = 1;
var w1 = 1;
	
console.log(window.s1);//undefined
console.log(window.w1);//1


在使用var去声明一个循环变量的时候,经常会遇到一个闭包的问题:

	var arr = [];
	for(var i=0;i<3;i++){
		arr.push(function(){
			console.log(i);
		});
	}
	
	arr.forEach(function(val,i){
		val();// 3 3 3
	});

上面打印出来的都是3,如果用let去声明i,结果就是正确的:

	var arr = [];
	for(let i=0;i<3;i++){
		arr.push(function(){
			console.log(i);
		});
	}
	
	arr.forEach(function(val,i){
		val();// 0 1 2
	});


解决var声明的方法有很多种,网上都有,自己去搜,这里我们主要从规范中探究一下为什么会这样。在规范的13.7.4.7中定义了for循环的几种形式,其中第二种是var形式定义循环变量,第三种是let形式定义循环变量:

IterationStatement : for ( var VariableDeclarationList ; Expressionopt ; Expressionopt ) Statement

3. Return ForBodyEvaluation(the first Expression, the second Expression, Statement, « », labelSet).
IterationStatement : for ( LexicalDeclaration Expressionopt ; Expressionopt ) Statement

9. If isConst is false, let perIterationLets be boundNames otherwise let perIterationLets be « ».
10. Let bodyResult be ForBodyEvaluation(the first Expression, the second Expression, Statement, perIterationLets, labelSet).

规范中的主要区别在调用ForBodyEvaluation( test, increment, stmt, perIterationBindings, labelSet )的时候,var循环的perIterationBindings没有传参,而let循环则传入了boundNames。


这个规范看起来很复杂,我自己的理解是这样的:


var循环:循环变量只创建一次,循环体内的函数闭包持有的都是这个循环变量(注意这里是持有的循环变量,不是变量的值),我们知道,闭包内访问外层作用域变量时,会导致这些变量不被释放,所以,当循环体结束时,var循环变量的值就是循环结束时的值。此后在执行这些函数的时候,打印出来的都是同一个值。


let循环:我们知道let声明的是块级作用域变量,循环体每执行一次,相当于又声明了一次变量,即又创建了一个变量,只不过名字一样,但是值不一样,每次对循环变量重新赋值(参考规范13.7.4.9),这样循环体内的函数闭包相当于持有的是这次循环创建的let变量,所以循环结束之后,打印出来的值是正确的。


*上面是个人对规范的理解,有不正确的地方还请读者及时指出

下面看段代码,可以简单验证一下:

	var arr = [];
	for(var i=0;i<3;i++){
		let j = i;
		arr.push(function(){
			console.log(i,j);
		});
	}
	
	arr.forEach(function(val,i){
		val();//打印结果是:3 0,3 1,3 2
	});


还有一个问题是在函数体内,let声明变量名称不能和函数函数名重复,但是在函数体内的块级作用域内可以重复。

function f1(x){
    let x;//Uncaught SyntaxError: Identifier 'x' has already been declared
}
注意上面是语法错误,会导致整个js代码都不执行


function f2(x){
		{	
			let x;
			console.log(x);//undefined
		}
	}

当然了,let声明的变量名也不能重复:

function(){
    let tmp;
    let tmp;//Uncaught SyntaxError: Identifier 'tmp' has already been declared
}



下面看一些简单的用法:

let a = 2;
if (a > 1) {
    let b = a * 3;
    console.log( b ); // 6
    for (let i = a; i <= b; i++) {
        let j = i + 10
        console.log( j );
    }
    // 12 13 14 15 16
    let c = a + b;
    console.log( c ); // 8
}

如果浏览器对let已经支持了,其实绝大部分情况下var都可以被替换成let,以后尽量用let,不要用var


*以上全部代码在Chrome 47下通过测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值