let and const
相同点:
let与const用来声明变量,用法与var类似,但是let与const声明的变量只在它们命令所在的代码块中有效;
let与const声明的变量不存在变量提升,所以必须在声明后使用,否则会报错,没有赋值会输出undefined;
//变量声明前调用会报错
console.log(a)//报错
let a=0;
console.log(a)//0
//变量声明未赋值返回Undefined
let a;
console.log(a)//undefined
如果在块级作用域中存在用 let和const声明的变量,那么这些变量必须在let和const声明后执行,否则就会报错;阮一峰老师称之为“暂时性死区”
let tmp=0;
if(true){
//在本作用域中已有tmp的声明,需要在声明后使用,否则报错;
tmp=5;//报错
let tmp;
console.log(tmp)//undefined
tmp=123;
console.log(tmp)//123
}
let和const不允许在同一作用域中,重复声明同一个变量
{
//重复声明会报错
let a=0;
var a=5;//Identifier 'a' has already been declared
let b=0;
b=5;//Identifier 'a' has already been declared
}
不同点:
const声明一个只读的常量,一旦声明常量值不能改变;用const声明必须马上赋值 否则报错;
//const 必须声明后必须马上赋值 不然会报错
const a;//Missing initializer in const declaration
//声明后对于简单数据类型来说,值是不能改变的(常量),否则就会报错;
const a=10;
a=20;//Assignment to constant variable.
const所声明的变量对于简单的数据类型(数值,字符串,布尔值)来说算是固定的常量,但是对于复合类型的数据(对象,数组)来说,const只能保证这个变量指向的内存地址不变,对象的值与数组的值还是可以修改的。
const foo={};
foo.prop=123;
console.log(foo.prop)//123
上面代码就是修改了foo这个变量的prop属性的值,因为prop属性属于foo这个对象,使用的是foo的内存地址,所以const不会报错;
但是,如果试图去修改foo对象的话就会报错;
const foo={};
foo={};//TypeError: Assignment to constant variable.
数组同理
//调用属性不会报错
const arr=[];
arr.push('hello');
arr.length=0;
//想要修改对象就会报错
const arr=[];
arr=[];//TypeError: Assignment to constant variable.
let&for循环
for循环中 如果用var来初始化i的值,声明的是一个全局的变量i;
用let来声明i,每次循环都会创建一个新的变量i;
//使用var初始化变量
var arr=[];
for(var i=0;i<10;i++){
arr[i]=function (){
console.log(i)
}
}
arr[6]()//10
上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是10。
如果使用let,声明的变量仅在块级作用域内有效,最后输出的是6。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
上面代码正确运行,输出了3次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
(上面是学习阮一峰老师的ES6入门记录下来的)