var let const 声明变量的不同
这是我的第一篇博客,写于2020.9.18 ——杨炯亮
一、ES6声明变量并不是只有var let const
ES5仅提供 var 和 function 2个关键字用于变量的声明, 在此需要注意的是,javascript声明变量的方式不仅仅只有var,let,const,ES6声明变量的关键词分别有,var,let,const,function,import 和 class。
今天这篇文章的主题是关于 var,let,const 声明变量的不同
二、var 声明变量
variable:变量
var是javascript的设计缺陷之一,出现以下几个问题:
- var声明的变量不存在块作用域
- var声明的全局变量会自动变成window对象的属性
- 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以上出现的问题
- let声明的变量在块级作用域外不会被访问
- let声明的变量不会成为window的属性
- 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.