var let const 声明变量的不同

1,414 阅读3分钟

这是我的第一篇博客,作者水平有限,共同成长 ——杨炯亮写于2020.9.18

一、ES6声明变量并不是只有var let const

​ ES5仅提供 varfunction 2个关键字用于变量的声明, 在此需要注意的是,javascript声明变量的方式不仅仅只有***var,let,const,ES6声明变量的关键词分别有,varletconstfunction*** ,importclass

​ 今天这篇文章的主题是关于 varletconst 声明变量的不同

二、var 声明变量

variable:变量

var是javascript的设计缺陷之一,出现以下几个问题:

  1. var声明的变量不存在块作用域
  2. var声明的全局变量会自动变成window对象的属性
  3. var声明的变量会提升
1.var声明的变量不存在块作用域

​ 或者说,ES5是不存在块级作用域

{
    var foo = 1;
}
console.log(foo)    // 1,仍然可以访问到 {} 内的 foo 

​ 编程题:定义10个函数,并且第1个函数执行时输出1,第2个函数执行时输出2......

var bar = []; 			 // 定义一个数组
for(var i = 0;i < 10;i++){
    bar[i] = function(){   // 每个数组元素定义为一个函数
        console.log(i)	 // 函数体
    }
}
bar[1]();	// 10
bar[2]();	// 10,都是输出10,深入理解需要掌握“预编译”和“作用域”的知识,
		// 思考方向 => 函数执行前,存在函数预编译AO(Activation Object)对象

​ 也就是说,上面的代码不能解决问题,下面给出这个问题的解决方案(给自己加鸡腿)

var bar = []; 
for (var i = 0; i < 10; i++) {
    bar[i] = (function(i){
        var j = i;
        return function(){
            console.log(j);
        }
    })(i)
}
bar[1]();	// 1
bar[2]();	// 2	涉及到javascript闭包,关键在于作用域的巧妙设置(改变变量的查找方式)
			//	    立即执行函数(IIFE)的存在使得
			// 		每个i变量值都能够得到保存在外部函数的作用域的j变量中
2.var声明的全局变量会自动变成window对象的属性
var foo = 123;
console.log(window.foo) //123,全局变量foo自动变成window对象的属性
3.var声明的变量会提升(declaration hoisting)
console.log(foo)  // undefined,声明提前而赋值不会提前
var foo = 111

二、let 声明变量

​ 关键词let的出现解决了var以上出现的问题

  1. let声明的变量在块级作用域外不会被访问
  2. let声明的变量不会成为window的属性
  3. let不存在变量提升
1.let声明的变量在块级作用域外不会被访问

​ 或者说,从ES6开始,存在块级作用域(还珠格格是这么唱的,“自从有了你,世界变得好美丽”)

{
    var foo = 1;
}
console.log(foo)    //  Uncaught ReferenceError: foo is not defined

let 的这个性质特别适合for循环,解决var中出现的编程题简洁有效:

​ 编程题:定义10个函数,并且第1个函数执行时输出1,第2个函数执行时输出2......

var bar = [];
for(let i = 0;i<10;i++){
    bar[i] = function(){
        console.log(i)
    }
}
bar[1]();	// 1
bar[2]();	// 2  文采不好,就是卧槽

​ 而上面循环的代码:

for(let i = 0;i<10;i++){
    bar[i] = function(){
        console.log(i)
    }
}

​ 实际效果是这样的 \downarrow

{
    let i = 0;
    bar[i] = function(){
        console.log(i)
    }
}
{
    let i = 2;
    bar[i] = function(){
        console.log(i)
    }
}
......
{
    let i = 10;
    bar[i] = function(){
        console.log(i)
    }
}
2.let声明的变量不会成为window的属性
let foo = 9527;
console.log(window.foo);   //undefined
3.let不存在变量提升
console.log(foo);
let foo = 9527;   //Uncaught ReferenceError: foo is not defined
4. 暂时性死区

​ 在ES6中,let和const声明的变量若出现在区块{...}内,无论出现在区块内哪里,则两者构成一种绑定的关系,并由此出现**暂时性死区(TDZ temporal dead zone)**这个语法概念,即在区块内,只有到声明变量那一行才可以访问变量,在区块中,在let声明foo变量之前,均属于foo变量的“死区”,在此之前访问该变量程序会报错。

var foo = 123;
{
    console.log(foo);	//Uncaught ReferenceError: foo is not defined
    let foo = 9527;
}

​ 暂时性死区示意如下:

var foo = 123;
{
    //TDZ start
    console.log(foo);	//Uncaught ReferenceError: foo is not defined
    let foo = 9527;
    //TDZ end
    console.log(foo)
}
5. typeof操作符

​ let 和 const 出现之前,一个未经声明的变量通过typeof操作符并不会报错

typeof(foo)	// 不会报错

​ let 和 const的出现也让typeof操作符不再是一个安全的操作。

typeof(foo)
let foo = 9527;	//Uncaught ReferenceError: foo is not defined
6. 变量重复声明

 var声明的变量在同一个作用域下可以被重复声明,而let 和 const 则不被允许,否则报错。

let foo = 9527;
let foo = 9527;	 //Uncaught SyntaxError: Identifier 'foo' has already been declared

三、const 声明变量

constant:常量

​ 顾名思义,const 关键词用于声明一个只读变量,或者说,一旦声明,必须赋值,并且值无法修改,除了这一点,其他和 let 一样。

const bar = 9527;
const foo;	//Uncaught SyntaxError: Missing initializer in const declaration
const foo = 9527;
foo = 123;	//Uncaught TypeError: Assignment to constant variable.

使用 const 的误区解析:

​ 对于简单数据类型,变量的值就是声明时对应的值,而对于引用数据类型,变量的值是声明对象对应的引用值,或者理解为指向该对象的指针,在javascript中,对象的引用存放在栈中,对象本身存放在堆中,而const声明变量的值指的是引用,而不是引用指向的对象,因此const声明的变量指向的对象时,可以修改对象的属性。

const foo = {name:'作者'};
foo.name = '帅帅囧';	// 修改foo指向的对象,没有报错
foo = 9527;			  // 修改foo,报错,Uncaught TypeError:Assignment to constant variable.

建议:在ES6开发时,优先使用const,只有需要改变某标识符时才使用 let

四、总结

业精于勤荒于嬉,行成于思毁于随