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()
    
  • 相关阅读:
    安全购买数码相机的诀窍!(1)
    获得网卡MAC地址和IP地址
    用Asp.net实现基于XML的留言簿之二
    安全购买数码相机的诀窍!(2)
    使用Flash读取COOKIE
    数码常识:CCD的原理
    ACE 5.5 Make in RedHat AS 4 Update 4 Issue
    Eclipse Plugins 开发 (1)
    RedHat AS4 Update4 DNS (bind 9) 配置
    Maven2 & Continuum 持续整合 (1)
  • 原文地址:https://www.cnblogs.com/gesh-code/p/14119735.html
Copyright © 2011-2022 走看看