zoukankan      html  css  js  c++  java
  • js块级作用域和let、const、var的区别

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

    1. 块作用域

    js中作用域有:全局作用域、函数作用域。没有块作用域的概念。ES6中新增了块级作用域。块级作用域由{ }包括if语句和for语句里面的{ }也属于块作用域。
    我们都知道在javascript里面是没有块级作用域的,而ES6添加了块级作用域,会计作用能改变什么呢?为什么会新增块级作用域呢?那就要先知道ES5没有块级作用域时出现了哪些问题。

    在if或者for循环中声明变量会泄露成全局变量
    for (var i=0;i<=5;i++){
      console.log("hello");
    }
      console.log(i); //6
    
    内层变量可能会覆盖外层变量
    var ss=new Date()
    function f() {
          console.log(ss);
          if(true){
            var ss="hello"
     }
    f() //undifined
    

    不管最后是否执行if语句,都会输出undifined,因为ss会提升到函数顶部,因此覆盖了外部的ss变量。而let和const命令,它们所声明的变量只在所在的代码块内有效,即为js添加了块作用域。

    允许块级作用域任意嵌套
    {{{let temp="hello world"}}}
    
    外层作用域无法读取到内层作用域的变量
    {{{
    	{let temp='hello world'}
    	console.log(temp)
    }}}  
    
    内层作用域可以定义与外层作用域同名的变量
    {{{
      let temp="111"
      {let temp="2222"}
    }}}
    

    函数本身的作用域在其所在的块级作用域内

    function f() {console.log("111");}
       (function () {
         console.log(f);
         if(false) {function f() {console.log("222");}}
         console.log(f);}
         f()
       ())
    

    这里我是这样理解的,ES5中虽然存在函数声明式提升,但是如果函数的声明放在了条件语句中且条件为false的时候,虽然进行了函数提升将其顶到了作用的最顶层,此时第一个console.log(f)执行结果为undefined,但是到执行false的时候,由于条件为false,所以函数并没有被声明,因此第二个console.log(f)执行结果也为undefined,在作用域内执行函数作用内f()时会报错,因为f()时没有被声明的。而在ES6中执行的话则会执行最外层的f()输出111。

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

    //立即执行函数
    (function(){
    	var temp="hello world"
    })
    //块级作用域
    {
    	var temp="hello world"
    }
    
    1. var let和const的区别

      js中作用域有:全局作用域、函数作用域。没有块作用域的概念。ES6中新增了块级作用域。块级作用域由{ }包括if语句和for语句里面的{ }也属于块作用域。
      我们都知道在javascript里面是没有块级作用域的,而ES6添加了块级作用域,会计作用能改变什么呢?为什么会新增块级作用域呢?那就要先知道ES5没有块级作用域时出现了哪些问题。
    在if或者for循环中声明变量会泄露成全局变量
    for (var i=0;i<=5;i++){
      console.log("hello");
    }
      console.log(i); //6
    
    内层变量可能会覆盖外层变量
    var ss=new Date()
    function f() {
          console.log(ss);
          if(true){
            var ss="hello"
     }
    f() //undifined
    

    不管最后是否执行if语句,都会输出undifined,因为ss会提升到函数顶部,因此覆盖了外部的ss变量。而let和const命令,它们所声明的变量只在所在的代码块内有效,即为js添加了块作用域。

    允许块级作用域任意嵌套
    {{{let temp="hello world"}}}
    
    外层作用域无法读取到内层作用域的变量
    {{{
    	{let temp='hello world'}
    	console.log(temp)
    }}}  
    
    内层作用域可以定义与外层作用域同名的变量
    {{{
      let temp="111"
      {let temp="2222"}
    }}}
    

    函数本身的作用域在其所在的块级作用域内

    function f() {console.log("111");}
       (function () {
         console.log(f);
         if(false) {function f() {console.log("222");}}
         console.log(f);}
         f()
       ())
    

    这里我是这样理解的,ES5中虽然存在函数声明式提升,但是如果函数的声明放在了条件语句中且条件为false的时候,虽然进行了函数提升将其顶到了作用的最顶层,此时第一个console.log(f)执行结果为undefined,但是到执行false的时候,由于条件为false,所以函数并没有被声明,因此第二个console.log(f)执行结果也为undefined,在作用域内执行函数作用内f()时会报错,因为f()时没有被声明的。而在ES6中执行的话则会执行最外层的f()输出111。

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

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

    2. let、const、var的区别

    1. var定义的变量,没有块的概念,可以跨块访问,不能跨函数访问,由变量提升
    2. let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升
    3. const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域块里访问,而且不能修改,无变量提升,不可以重复注明,注意:const常量,指的是常量对应的内存地址不能改变,而不是对应的值不能改变,这一点要搞清楚,把所有应用类型的数据设置为常量,其内部的值是可以改变的 记住.
      let声明的变量只在块级作用域内有效
    function f() {
          if(true){
            let i=6
            console.log(i);//6
          }
          console.log(i); //报错 i is not defined
        }
        f()
    

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

    function f() {
          if(true){
            console.log(i);//报错 let没有变量提升
             let i=6
          }
        }
        f()
    

    在let声明变量前,使用该变量,它是会报错的,而不是像var那样会"变量提升". 准确来说let没有"变量提升"的特性这样说是不正确的,应该说它提升了,但是在ES6中规定了在let声明变量前不能使用该变量.

    var test=1
        function f() {
          console.log(test); //报错
          let test=2
        }
        f()
    

    如果let声明的变量没有变量提升,应该输出1外部的test的结果才对,而它缺是报错,只是规定了不能在其声明之前使用而已,所以称let的这一特性为"暂时性死区",且这一特性,仅仅针对块级作用域有效(let const)

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

     //使用闭包实现给数组中的每个元素赋值为方法
     var arr=[]
        for(var i=0;i<10;i++){
          arr[i]=(function (i) {
            return function f() {
              return i
            }
          })(i);
        }
       console.log(arr[3]()+"  "+arr[1]());
      
      //let实现闭包原理
       var arr=[]
        for(let i=0;i<10;i++){
          arr[i]=function(){
          	return i
          }
        }
       console.log(arr[3]()+"  "+arr[1]());
    

    剩下const命令了!

    const和let的使用规范一样,与之不同的是:

    const声明的是一个常量,且这个常量必须赋值(即必须初始化),否则会报错

    function f() {
          const PI
          PI=3.14
          console.log(PI); //报错 Missing initializer in const(即没有初始化)
        }
        f()
    
  • 相关阅读:
    Android开发之Sqlite的使用
    ZOJ 3607 Lazier Salesgirl
    ZOJ 3769 Diablo III
    ZOJ 2856 Happy Life
    Ural 1119 Metro
    Ural 1146 Maximum Sum
    HDU 1003 Max Sum
    HDU 1160 FatMouse's Speed
    Ural 1073 Square Country
    Ural 1260 Nudnik Photographer
  • 原文地址:https://www.cnblogs.com/gesh-code/p/14119735.html
Copyright © 2011-2022 走看看