JS进阶之路之——作用域(三)

块作用域

尽管函数作用域是最常见的作用域单元,当然也是现行大多数 JavaScript 中最普遍的设计 方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可 以实现维护起来更加优秀、简洁的代码。

  • try...catch 非常少有人会注意到 JavaScript 的 ES3 规范中规定 try/catch 的 catch 分句会创建一个块作用域, catch 的参数变量仅在 catch 内部有效。


try{    
    throw undefined;
}catch(a){    
        a = 2;    
        console.log(a); // 2
    }
console.log(a);  // ReferenceError

ES6的标准使我们能够简单的创建块作用域,其中一个变量定义方式是let关键词定义。

let定义的变量具有以下的特点:

  1. let隐形的创建块作用域({...})

  2. let声明的变量不能进行变量提升,因此只能先定义,后使用


{    let a = 1;    
 console.log(a); // 1
}
console.log(a);  // ReferenceError

let一个典型的应用就是在for循环里

我们看下面两个例子:


// 每秒输出一个5
for( var i = 0; i < 5 ; i++ ) {    
    setTimeout(() => {        
        console.log( i );    
    }, i *1000)}
// 依次输出0,1,2,3,4,时间间隔位1秒
for( let i = 0; i < 5 ; i++ ) {    
    setTimeout(() => {        
        console.log( i );    
    }, i *1000)}

其原因就是let形成了5个块作用域,使每次输出的变量都从本次循环的块作用域中获取。

当然我们还可以有其他方式做到第二种效果,我们将在 闭包,是真的美中说道。

除了 let 以外,ES6 还引入了 const,同样可以用来创建块作用域变量,但其值是固定的 (常量)。之后任何试图修改值的操作都会引起错误。

扫描二维码关注公众号,回复: 1910690 查看本文章
var fn = true;if (foo) {     
    var a=2;    
    const b = 3; // 包含在 if 中的块作用域常量    a=3;//正常!    b=4;//错误! 
}console.log( a ); 
// 3console.log( b ); // ReferenceError!

作用域链

作用域链是由当前作用域与上层一系列父级作用域组成,作用域的头部永远是当前作用域,尾部永远是全局作用域。作用域链保证了当前上下文对其有权访问的变量的有序访问。

var a = 2;
function bar() {    
    function fn() {        
        console.log(a);    
    } 
}bar(); // 2

上面代码是由3层作用域气泡组成,fn气泡中试图打印变量a,引擎在fn气泡中未找到a变量,于是去其父作用域气泡bar中寻找...以此类推直到找到全局作用域气泡,发现有变量a,将其值打印出来。如若没找到,报ReferenceError错误。

猜你喜欢

转载自blog.csdn.net/wwwxuewen/article/details/80897796
今日推荐