0x01.定义
ES6规定由一对大括号{}包裹的部分为一个块级作用域。在块级作用域下,var关键字和function关键字定义的变量和方法不受作用域影响,let关键字和const关键字定义的变量和常量受到块级作用域影响,是当前作用域私有的。
下面代码段中,使用var和function定义的变量a和方法test可以在大括号外边被访问,而使用let和const定义的变量和常量无法在大括号外面被访问。如下:
{
var a = 1;
let b = 2;
const c = 3;
function test(){
console.log('123');
}
}
console.log(a); // 1;
console.log(b); // Uncaught ReferenceError: b is not defined
console.log(c); // Uncaught ReferenceError: c is not defined
test(); // test方法可以正常执行
0x02.对象的变化
由于引入了块级作用域的概念,{}若要表示对象,不可以放在行首,解释器将会给出错误信息:Uncaught SyntaxError: Unexpected token :,因此无法再定义像下面代码段所实的匿名对象,
{name: 'Mocha', age: 18} // Uncaught SyntaxError: Unexpected token :
在定义对象时,必须使用一个变量接收,或使用小括号运算符()包裹匿名对象:
// 定义对象
let o = {name: 'Mocha', age: 18};
// 定义匿名对象
({name: 'Mocha', age: 18});
同理,在使用eval()函数时同样不能直接执行一段{}开头的字符串,在eval方法中,可以是用var定义一个变量接收对象,但无法使用let接收。
eval("{name: 'Mocha', age: 18}"); // 这样执行同样会引起解释器报错
eval("({name: 'Mocha', age: 18})");
eval("var o = {name: 'Mocha', age: 18}"); // 这里可以执行将对象赋值给变量o的操作
eval("let obj = {name: 'Mocha', age: 18}"); // 这里由于let不提升变量,故之后无法取到被定义的变量。
console.log(o.name); // Mocha
console.log(obj.name); // obj is not defined
0x03.if(){}中的块级作用域
根据在变量提升中学到的知识,我们知道用function关键字定义的变量会被整个提升到当前作用域的最前端,但是如果方法的定义在if(){}的大括号范围内,方法仅仅声明被提升到了最前端,而方法体只有当条件成立的时候才会被定义,如条件不成立,则方法体不会被定义,这是和之前所说的function变量提升有所不同的地方,如下所示:
if(true){
function test1(){
console.log(1);
}
}
if(false){
function test2(){
console.log(2);
}
}
console.log(test1); // function test1(){ console.log(1); }
console.log(test1); // undefined
0x04.for(){}使用let
之前使用JavaScript中for循环绑定事件时,无法直接使用自增量。举例如下:
HTML:
<!DOCTYPE html>
<html>
<head>
<title>for</title>
</head>
<body>
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</body>
</html>
JavaScript:
var list = document.getElementById('list').getElementsByTagName('li');
for(var i=0;i<list.length;i++){
list[i].onClick = function() {
alert(i);
}
}
此时由于循环已经执行结束,故i的值为5,因此点击每个li都会弹出5,之前的解决方法可以将索引值在循环执行时作为属性保存在每个list[i]对象中,点击事件触发时,不使用自增量,而使用自身的属性,例子中使用的是index:
var list = document.getElementById('list').getElementsByTagName('li');
for(var i=0;i<list.length;i++){
list[i].index = i;
list[i].onClick = function() {
alert(this.index);
}
}
而使用let的情况下,由于每次执行循环时都是一个私有的作用域,故可以直接使用自增量的值而不用在定义额外的属性,如下:
var list = document.getElementById('list').getElementsByTagName('li');
for(let i=0;i<list.length;i++){
list[i].onClick = function() {
alert(i);
}
}
0x05.总结
以上就是在学ES6块级作用域中所遇到的知识点,如有理解和描述不正确的地方,还请不吝赐教!