阅读 119

ES6 块级作用域

块级作用域

1. let 关键字与 var 关键字的区别

ECMAScript 6 新增了 let 关键字用于声明变量,该变量只能在指定的代码块内有效。

(1)块级作用域与函数作用域

如下代码所示:

 {
     let a = 100;//块级作用域
     var b = 1 00;//函数作用域
 }
 console.log(b)//100
 console.log(a)//a is not defined复制代码

显而易见,结果是使用 let 声明的变量报错,var 声明的变量输出正确的值。

(2)暂时性死区(不存在声明提前)

ECMAScript 6标准明确规定,如果在一个代码块中使用 let 或 const 声明变量或常量时,当前代码块中对这些声明的变量或常量形成了一个封闭的作用域。

在这个代码块中,在使用 let 或 const 声明之前,该变量或常量都是不可用的。这种情况,在语法上被称为“暂时性死区”( Ternporal Dead Zone,简称为TDZ)。

使用 var 关键字声明变量时会出现声明提前的情况,就是变量在声明之前被访问,其值为undefined。

但 let 关键字不允许变量声明提前。

如下代码所示:

 console.log(m);//undefined
 var m = 100;
 // var 关键字声明允许声明提前
 
 console.log(v);
 let v = 100;//ReferenceError: Cannot access 'v' before initialization
 //let 关键字声明不允许声明提前复制代码

(3)let 不允许重复声明

let 关键字与 const 关键字一样,定义的变量不允许重复声明。

示例代码如下:

 // 使用关键字var允许重复声明
 var v = 100;
 console.log(v);
 var v = 1000;//重复声明 - 不报错
 console.log(v);
 
 /*
 // 使用关键字 let 不允许重复声明
 let m = 100;
 console.log(m);
 let m = 1000;//重复声明 - 报错
 console.log(m);//SyntaxError: Identifier 'm' has already been declared
 */
 
 // 使用关键字 let定义变量允许重新赋值
 let m = 100;
 console.log(m);
 m = 1000;//重复赋值
 console.log(m);//1000复制代码

值的注意的是:使用关键字 let 虽然不允许重复声明,但可以重新赋值。

(4)与函数的区别

 // 1.使用var允许声明提前
 
 /*
 var v = 100;
 function fn(){
     console.log(v);//undefined
     var v = 1000;
     console.log(v);//1000
 }
 fn();
 */
 
 // 2.使用let不允许声明提前
 /*
 let v = 100;
 function fn(){
     // 函数作用域封闭 - 全局作用域中的变量与当前函数作用域无关
     console.log(v);//ReferenceError: Cannot access 'v' before initialization
     let v = 1000;
     console.log(v);//1000
 }
 fn();
 */
 
 //3.函数作用域内
 let v = 100;//全局变量
 console.log(v);//100
 // 自调函数
 (function(){
     let v ;
     // 函数作用域
     console.log(v);//undefined
 })();
 if (true){
     console.log(v);//100
 }复制代码

(5)与函数参数的区别

 /*// 在ES6中函数的参数相当于使用let关键字定义的局部变量
 function fn(a) {
     let a = 1000;
     console.log(a);//SyntaxError: Identifier 'a' has already been declared
 }
 fn(100);*/
 
 /*function fn(a) {
     let a = 1000;
     console.log(a);//SyntaxError: Identifier 'a' has already been declared
 }
 fn(100);*/
 function fn(a) {
     a = 1000;//允许重新赋值
     console.log(a);//100
 }
 fn(100);复制代码

在 ES 6 中函数的参数相当于使用 let 关键字定义的局部变量


2.为什么需要块级作用域?

  • 在循环体中用于技术的变量泄露为全局变量

    如下示例代码所示:

      /*
     // 全局作用域
     for (var i=0;i<10;i++){
         console.log(i);
     }
     console.log(i);//10 用于计数的变量泄露为全局变量
     */
     
     // 块级作用域
     for (let i=0;i<10;i++){
         console.log(i);
     }
     console.log(i);//ReferenceError: i is not defined复制代码

上述示例代码中,关键字 var 定义的变量 i 只用于控制循环体的执行。当循环体执行结束后,变量 i 并没有释放,而是作为全局变量存在。而关键字 let 定义的变量 i 只用于控制循环体的执行。当循环体执行结束后,变量 i 释放。

  • 经典面试题(循环体与数组的关系 )

     /*
     var arr = [];
     for (var i=0;i<10;i++){
         arr[i]=function () {
             return i;
         };
     }
     console.log(arr[9]());//10 因为var关键字定义的变量i为全局变量
     */
     
     var arr = [];
     for (let i=0;i<10;i++){
         arr[i]=function () {
             return i;
         };
     }
     console.log(arr[6]());//6 因为let关键字定义的变量i为块级作用域复制代码

上述示例代码 var 关键字定义的i变量为全局变量,所有最后return的i的值都为10。

解析图如下:


3.块级作用域的函数声明

ECMAScript 5标准规定函数的声明只能在全局作用域和函数作用域中,不能在块级作用域中声明。

 /*
 if (true){
     // 块级作用域
    var fun = function(){
         console.log('this is function')
     }
 }
 // 全局作用域调用
 fun();
 */
 
 // let 关键字声明函数
 if (true){
     // 块级作用域
     let fun = function(){
         console.log('this is function');
     }
 }
 // 全局作用域调用
 fun();//ReferenceError: fun is not defined复制代码

使用var关键字声明的函数可以在全局调用,但是使用let 关键字声明的函数不能再全局调用。


作者:不一213
链接:https://juejin.cn/post/7022100132036345893


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐