js块级作用域和let,const,var区别

1. 块作用域{ }

JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域。
块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

我们都知道在javascript里是没有块级作用域的,而ES6添加了块级作用域,块级作用域能带来什么好处呢?为什么会添加这个功能呢?那就得了解ES5没有块级作用域时出现了哪些问题。

       ES5在没有块级作用域的情况下出现的问题:

       一。在if或者for循环中声明的变量会泄露成全局变量

for(var i=0;i<=5;i++){
      console.log("hello");
}
console.log(i); //5

      二。内层变量可能会覆盖外层变量

var temp = new Date();
function  f(){
     console.log(temp);
     if(false){
         var temp = "hello";
    }
}
f(); //undefined

     不管最后是否执行if语句,都会输出undefined,因为temp会提升到函数顶部,因此覆盖了外部的变量temp。

     上一篇介绍的let和const命令,它们所声明的变量只在所在的代码块内有效,即为js添加了块级作用域。

           【1】允许块级作用域任意嵌套;

{{{let tmp = "hello world"}}}

           【2】外层作用域无法读取内层作用域的变量;

{{{
   {let tmp = "hello world";}
   console.log(tmp);  //error
}}}

           【3】内层作用域可以定义外层作用域的同名变量

{{{
   let tmp = "hello world";
   {let tmp = "hello world";}
}}}

           【4】函数本身的作用域在其所在的块级作用域之内。

复制代码
function f(){
    console.log("outside");
}
(function(){
    if(false){
        function f(){
            console.log("inside");
        }
    }
   f();
}());
复制代码

这段代码如果是在ES5中运行,那么会输出inside,因为在ES5中,函数会提升到作用域的顶部,如果是在ES6中运行,则会输出outside,因为在ES6中函数无法提升,所以访问到的f()是外层的f()。

         【5】在ES5中,因为没有块级作用域,获得广泛运用的是立即执行函数。现在ES6增加了块级作用域,那么立即执行函数就不再必要了。ES6以前变量的作用域是函数范围,有时在函数内局部需要一些临时变量,因为没有块级作用域,所以就会将局部代码封装到IIEF(立即执行函数)中,这样达到了想要的效果又不引入多余的临时变量。而块作用域引入后,IIEF当然就不必要了!临时变量被封装在IIFE中,就不会污染上层函数;而有块级作用域,就不用封装成IIEF,直接放到一个块级中就好。更简单的说法是,立即执行匿名函数的目的是建立一个块级作用域,那么现在已经有了真正的块级作用域,所以立即执行匿名函数就不需要了。

//立即执行函数
(function(){
    var temp = "hello world";
}());
//块级作用域
{
   var temp = "hello world";
}

2. var、let、const的区别

  1. var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问,有变量提升。
  2. let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明。
  3. const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改,无变量提升,不可以重复声明。注意:const常量,指的是常量对应的内存地址不得改变,而不是对应的值不得改变,所有把应用类型的数据设置为常量,其内部的值是可以改变的,例如:const a={}; a.b=13;//不会报错 const arr=[]; arr.push(123);//不会报错
  4. let 声明的变量只在块级作用域内有效

    'use strict';
    function func(args){
        if(true){
            let i = 6;
            console.log('inside: ' + i);  //不报错
        }
        console.log('outside: ' + i);  // 报错 "i is not defined"
    };
    func();

    不存在变量提升,而是“绑定”在暂时性死区

    // 不存在变量提升
    'use strict';
    function func(){
        console.log(i);
        let i;
    };
    func(); // 报错

    在let声明变量前,使用该变量,它是会报错的,而不是像var那样会‘变量提升’。
    其实说let没有‘变量提升’的特性,不太对。或者说它提升了,但是ES6规定了在let声明变量前不能使用该变量。

    'use strict';
    var test = 1;
    function func(){
        console.log(test);
        let test = 2;
    };
    func();  // 报错

    如果let声明的变量没有变量提升,应该打印’1’(func函数外的test);而它却报错,说明它是提升了的,只是规定了不能在其声明之前使用而已。我们称这特性叫“暂时性死区(temporal dead zone)”。且这一特性,仅对遵循‘块级作用域’的命令有效(let、const)。

    let使用经典案例:let命令代替闭包功能
    闭包实现:

    var arr = [];
    for(var i = 0; i < 2; i++){
        arr[i] = (function(i){
            return function(){
                console.log(i);
            };
        }(i));
    };
    arr[1]();
    let 实现:
    
    'use strict';
    var arr = [];
    for(let i = 0; i < 2; i++){
        arr[i] = function(){
            console.log(i);
        };
    };
    arr[1]();

    剩下 const 命令了!
    const 与 let 的使用规范一样,与之不同的是:
    const 声明的是一个常量,且这个常量必须赋值,否则会报错。

    'use strict';
    function func(){
        const PI;
        PI = 3.14;
        console.log(PI);
    };
    func(); // 报错“Missing initializer in const declaration”
posted @ 2019-06-06 15:32  野生夜神月  阅读(10056)  评论(2编辑  收藏  举报