let与var的区别
基本用法
如下代码:
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
上面的代码很明显的表明,let申明的变量只在当前的代码块中有效。
var和let在for循环中的区别
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
这里for循环中用var申明的i是一个全局变量,当循环完后i就变成了10.所以当调用a数组中的函数打印i时,结果为10
而当改为let申明变量i时,最后打印的i就是当轮循环的值。所以每一次循环的i其实都是一个新的变量,所以最后输出的是6
另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
var 和let 在变量提升上的区别
var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
foo变量通过var申明,会发生变量提升,所以当在申明前使用时,变量foo实际上已经存在,但是没有值,所以会输出undefined
bar变量通过let申明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。
不允许重复声明
let不允许在相同作用域内,重复声明同一个变量。
// 报错
function func() {
let a = 10;
var a = 1;
}
// 报错
function func() {
let a = 10;
let a = 1;
}
所以,不能在函数内部重新声明参数。
function func(arg) {
let arg;
}
func() // 报错
const 与var
基本用法
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI =3.1415;
PI // 3.1415
PI =3;
// TypeError: Assignment to constant variable.
上面代码表明改变常量的值会报错。
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const foo;
// SyntaxError: Missing initializer in const declaration
上面代码表示,对于const来说,只声明不赋值,就会报错。
const 同let一样 不存在变量提升,存在暂时性死区,只能在声明后后使用。同时一样的也不能重复声明
本质
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心
const foo ={};
// 为 foo 添加一个属性,可以成功
foo.prop =123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo ={};// TypeError: "foo" is read-only
参考
https://www.bookstack.cn/read/es6-3rd/spilt.1.docs-let.md 本文是摘抄的阮一峰的es6教程文档,做一个归纳总结