当前位置:嗨网首页>书籍在线阅读

06-变量屏蔽

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

7.5 变量屏蔽

在JavaScript开发中,有一个常常引发混淆的场景是,不同作用域中存在相同名字的变量或常量。而当作用域一个挨着一个的时候,这种场景会显得相对直观一些:

{
    // block 1 
    const x = 'blue';
    console.log(x);             // 打印 "blue"
}
console.log(typeof x);          // 打印"undefined"; x 不在作用域内
{
    // block 2          
    const x = 3; 
    console.log(x);             // 打印"3"
}
console.log(typeof x);          // 打印 "undefined"; x 不在作用域内

这个例子非常容易理解:有两个相互独立的变量,在不同的作用域中都以x命名。那么,如果作用域嵌套在一起有会发生什么呢?

{
    // outer block
    let x = 'blue';
    console.log(x);             // 打印 "blue"
    {
        // inner block
        let x = 3;
        console.log(x);        // 打印"3" 
    }
    console.log(x);            // 打印 "blue"
}
console.log(typeof x);         // 打印 "undefined"; x 不在作用域内

这个例子演示了变量屏蔽。在内部块中, x 是一个独立于外部块的(同名)变量,这样实际上屏蔽(或隐藏)了外部块定义的 x

这里有一个关键的地方需要理解,当执行到内部块时,一个新的变量 x 被定义,两个变量都在作用域内:只是没有办法访问外部块的变量(因为具有相同的名字)。相对而言,在前一个例子中,一个变量 x 进入作用域,然后退出,接着第二个变量x做了相同的事情。

为了更好地理解这点,看下面例子:

{
    // outer block
    let x = { color: "blue" };
    let y = x;                           // y 和 x 引用同一个对象
    let z = 3;
    {
         // inner block
         let x = 5;               // 外部 x 被屏蔽
         console.log(x);          // 打印 5
         console.log(y.color);    // 打印 "blue"; y(以及x在外部作用域)
                                     指向的对象仍然在
                                  // 作用域内 
         y.color = "red";
         console.log(z);          // 打印 3; 因为z没有被屏蔽
    }
    console.log(x.color);         // 打印"red"; 因为object在内部作用域被修改
    console.log(y.color);         // 打印"red"; 因为x和y指向同一个对象
    console.log(z);               // logs 3
}
变量屏蔽有时候也叫变量阴影(即一个相同名字的变量会将外部作用域的变量屏蔽起来)。作者不喜欢这个术语,因为阴影通常不会将事物完全隐藏,只是使之变得灰暗。而当一个变量被屏蔽时,这个被屏蔽的变量就无法再通过名字去访问了。

到目前为止,大家应该清楚了解了作用域的层次结构了:可以在原有的作用域中进入一个新的作用域。此时会建立一个作用域链来决定哪些变量在作用域中:当前作用域链中的所有变量都在作用域内,并且(只要它们没有被屏蔽)都是可以被访问的。