var,let以及const三款声明语句的不同与相似

243 阅读5分钟

既然要说这三款声明语句的不同与相似,那就先来说说它们分别具有什么特性。

一,var

  • 1,var声明的变量会被当做全局对象 window 的属性,也就是说,使用var声明变量会为全局对象 window/global创建一个新的属性,可以使用 window. 的方式访问变量的值。
    var a = 22
    console.log(a)          // 22
    console.log(window.a)   // 22
  • 2,前面提到var声明的变量会被当做 window 的属性,下面有以下几个问题。
    • 那么在 局部作用域/函数作用域 使用 var 声明的变量 是否 也是这样呢?
    • 在局部作用域内 对 同名变量 进行赋值 会不会影响 外部的同名变量?
    • 如果 对 这个同名变量 取值,取的是哪里的值?
        var a = 22

        function A() {
            a = 30
            var b = 42
            console.log(a)	    // 30
            console.log(b)          // 42
            console.log(window.b)   // undefined
        }
        console.log(a)              // 22
        console.log(window.a)       // 22
        A()
        
        - 由上面代码可知,使用var在局部作用域创建的变量并不会添加到 全局对象上。
  	- 会影响,但影响的结果是什么样的得看 在哪里访问。本例中在函数内访问 a 结果为30,而在外部访问 a 结果为22,这里涉及到作用域链的概念。
          (在访问变量的时候,会先在 同层作用域内 查找,如果在 同层内 没有找到,则会 向外一层(或者叫做父级作用域) 继续查找,以此内推,直到查找到变量为止,
          如果到 顶层作用域 也没有查找到,则会报错 (Uncaught ReferenceError:... is not defined))
  • 3,变量提升:即未定义,也可取。(由于var是不存在块级作用域的,所以 对于 var 来说,只有 全局作用域 和 局部作用域)
        console.log(a)	// undefined
        var a = 10
        或者 这样认为这段代码
        var a
        console.log(a)	//此时a还未赋值,所以 系统给它了 undefined。
        a = 10
  • 4,重复声明:可以对同一个变量进行多次声明,会以最后一次的声明为结果
        var a = 10
        var a = 20
        var a = 30
        console.log(a)	// 30

二,let

  • 1, 不允许重复声明:不能对 同一标识符 进行 重复声明
        let a = 10
        let a = 20
        console.log(a) // Uncaught SyntaxError: Identifier 'a' has already been declared
  • 2, 不存在变量提升:变量的访问 不能 先于 声明
        if (true) {
            console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization
            let a = 10
        }
  • 3, 不属于 window全局对象:
        let a = 10
        console.log(window.a)	// undefined
  • 4,存在 暂时性死区:ES6规定,let/const 命令会使 区块 形成封闭的作用域。若在声明之前使用变量,就会报错。总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。 通俗点讲:暂时性死区 很霸道,只有把变量指定 过了 才可以使用。
        let a = 10
        if (true) {
            a = 20
            let a
        }	// Uncaught ReferenceError: Cannot access 'a' initialization
        // 在这里并不会 因为 在全局作用域下 定义了 a,就可以在 块级作用域内 对 a 进行重新赋值。
        // 因为在一个代码块内 使用 let语句声明的变量,该变量就只属于 该代码块了。
        // 在代码块内,使用 let 命令 声明变量之前,该变量都是不可用的。
        // 代码块:只要是  {} 大括号 包裹的代码 都可以称为代码块。
  • 5,块级作用域:具有两点要素,一是let/const,二是代码块。
        if (true) {
            let a = 10
        }
        console.log(a)		// Uncaught ReferenceError: a is not defined
        // 使用 let声明语句 声明变量时 产生了封闭性区域(块级作用域),外部访问不到。

   	有无块级作用域对比
        
        例一:
        for (var i = 0; i < 5; i++) {
            console.log(i)	// 0,1,2,3,4
        }
        console.log(i)		// 5
        for (let j = 0; j < 5; j++) {
            console.log(j)	// 0,1,2,3,4
        }
        console.log(j)		// Uncaught ReferenceError: a is not defined
    
    	例二:
        
        for (var i = 0; i < 5; i++) {
            setTimeout(() => {
                console.log(i)	// 5,5,5,5,5
            })
        }
        for (let j = 0; j < 5; j++) {
            setTimeout(() => {
                console.log(j)	// 0,1,2,3,4
            })
        }
        //产生这些区别的原因,就是因为 let 声明变量时 产生了块级作用域,且变量只属于 当前块级作用域,其它外部作用域访问不得。

三,const

  • 1,不允许重复声明
  • 2,不允许变量提升
  • 3,不属于 window全局对象
  • 4,暂时性死区
  • 5,块级作用域 此五点特性是与 let 类似的,不再复述。
  • 问:const 与 let 的区别是什么?
  • 答:const声明的是 常量,不可变的 量,声明的标识符必须初始化。let 声明的是变量,是可以改变的量。
        例一:
        const a = 10
        a = 20				// Uncaught TypeError: Assignment to constant variable
        
        例二:
        
        const obj = {
            a: 'aa',
            b: 'bb',
            c: 'cc'
        }
        obj.a = 'aaaaaaaaa'
        console.log(obj) 		// {a: 'aaaaaaaaa',b: 'bb', c: 'cc'}
        
        例三:
        const a				// Uncaught SyntaxError: Missing initializer in const declaration
  • 出现 例一,例二表现不一致的情况:const限制的是 它声明的变量初始化的值不能改变,而对于这个值,分为普通的值 和 引用地址。涉及到数据存储方式,栈存储 和 堆存储相关知识点,这里不再论述。

四,总结

  • const 与 let 的区别:const声明变量 必须初始化,且初始化的“值” 不可修改。日常使用中,const比较稳妥,const使用较多,尽量 避免使用 let。

  • const 和 let 的 出现主要引出了暂时性死区和块级作用域等概念,使代码的书写可更具规范性,可控性,使变量的作用范围 更加明确,避免了变量提升,重复声明等bug。