ECMAScript求索 · 块级作用域

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块级作用域中所遇到的知识点,如有理解和描述不正确的地方,还请不吝赐教!

0x06.参考资料

let 和 const 命令 - 《ECMAScript 6 入门》——阮一峰

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值