Open YvetteLau opened 5 years ago
let 和 const 都是块级声明的一种。 块级声明用于声明在指定块的作用域之外无法访问的变量。 let 和 const 不同于 var 的特点如下:
let 和 const 的区别: const 用于声明常量,其值一旦被设定不能再被修改,否则会报错。 此外,const 声明不允许修改绑定,但允许修改值。这意味着可以修改const声明的对象中的属性。
var的作用: a:可以声明变量以及常量 b:可以变量提升,默认为undefined,当运行到给变量赋值才会赋值 c:作用域为函数作用域 d:允许在相同作用域内, 重复声明一个变量
let与const:
相同点: a:作用域为块作用域 b:没有函数提升 c:不允许在相同作用域内, 重复声明一个变量
异同点: a:let一般声明的是变量(也可以弄为常量,不建议);const声明的是常量(必须初始化),当为对象的时候属性的值是可以改变的
let和const声明都在代码块内有效。不存在变量提升。相同作用域内,不能重复命名。 const声明的是只读常量,指向的内存地址不能改动。一旦声明,必须立即初始化。 var用于声明在函数作用域内有效,允许变量提升。相同作用域内,可以重复声明
全局声明的var变量会挂载到window上,而let和const不会; var声明变量存在变量提升,let和const不会; let,const的作用范围是块级作用域,而var的作用范围是函数作用域; 同一作用域下let和const不能同时声明同名变量,而var可以; 同一作用域下在let和const声明前使用会存在暂时性死区; 对于const来说:一旦声明必须赋值,不能使用null占位,声明后不能再修改,如果声明的是复合类型数据,可以修改其属性
let和const都是作用于代码块的声明,var 的作用域是当前 scope 的所有子作用域,包括当前作用域中声明或调用的函数或是 while / for / if / try-catch 语法区块。let和const都是es5,es6新版本的js语言规范出来的定义,在这以前定义一个变量只能用var。var存在变量提升,let,const不存在。let,const不允许重复声明同一变量,而var可以
var [ECMAScript 1st Edition (ECMA-262)规范]
let [ECMAScript 2015 (6th Edition, ECMA-262)规范]
const[ECMAScript 2015 (6th Edition, ECMA-262)规范]
var
let
const
var
声明在在方法内为全局变量,声明在方法外为局部变量;let/const
无法声明为全局变量。var
存在变量提升,在赋值前为undefined
;let
存在暂时性死区,块级作用域中使用了let
声明就会'绑定'区域,声明前不能使用;const
声明时必须赋值。var
不存在块级作用域;let/const
存在。var
时,只存在一个变量;let/const
每次循环都是一个新的变量,与循环体为不同作用域。var
可重复声明,let/const
在作用域中不允许重复声明。var会进行变量提升,let和const不会进行提升
因为var会进行变量提升,所以可以在声明之前访问,不会形成暂存死区。let 和const 不会进行变量提升,在声明之前不能使用,形成暂存死区
var可以进行重复声明,但是let和const不能进行重复声明
var不会形成块作用域,let和const可以形成块作用域
var和let声明的变量可以重新赋值,const不可以。如果const 声明的变量存储的是引用地址, 是可以修改这个引用对应的对象的值的,但是这个变量不能被赋予其他值
var | let | const | |
---|---|---|---|
变量提升 | Y | N | N |
覆盖全局变量 | Y | N | N |
重复声明 | Y | N | N |
暂时性死区 | N | Y | Y |
块作用域 | N | Y | Y |
只声明不初始化 | Y | Y | N |
重新赋值 | Y | Y | N |
js本身只有全局作用域和函数作用域,let和const的出现,使得js有了块级作用域。 1、var 声明的变量可以重复,而let、const则不可以; 2、var 声明的变量可以提升,而let、const则不可以; 3、let声明的变量的值可以更改,而const声明的是常量,则不可以,如果const声明的一个对象,则对象中的属性值可以改变; 4、for循环中用var 声明的变量可以在for循环外访问到,而let则不可以。
for(var i = 0; i < 10; i++) {
}
console.log(i) // 10
for(let j = 0; j < 10; j++) {
}
console.log(j) // Uncaught ReferenceError: j is not defined
let 和 const都是ES6新增的 在let和const没有出来的时候,JS没有块级作用域,只有全局作用域和函数作用域。
for(var i=0;i<10;i++){
var a = 'a';
}
console.log(a);
比如上面这个例子,已经不在for循环中了,已经跳出这个块了,我们还是能打印出 a
再看下面这个例子
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000);
}
3 3 3
而不是 1 2 3
循环本身以及三次timeout回调共享了变量i
let的出现让变量拥有块级作用域,把上面的var
换成 let
可以完美解决问题。
我们总结一下var ,let, const 的区别 1.变量提升 var
console.log(a);//undefined
var a=2;
let
console.log(a);//Uncaught ReferenceError: Cannot access 'a' before initialization
var a=2;
const
console.log(a);//Uncaught ReferenceError: Cannot access 'a' before initialization
const a=2;
2.暂时性死区 作用域中声明了let变量,但是let变量的使用却在声明之前,这通常叫做变量提升。 但是let并不像var一样,var变量声明前使用,会打印出undefined.但是let变量直到被赋值才会被初始化。 在变量被初始化前访问这个变量会报reference error.我们称这个变量在作用域开始到被初始化之间为暂时性死区。
function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2;
}
3.重复声明
let a=1;
let a=2;
//报错
const a=1;
const a=2;
//报错
var a=1;
var a=2;
//不报错
4.重新赋值
var和let可以重新赋值,但是const不可以,而且const 必须声明的时候就初始化。
1、var和let声明一个变量, const 声明一个只读的常量; const保存对象时保存的是一个地址的指针,所以可以修改对象的值:
2、const必须在声明的时候就初始化,var和let不用;
3、var可以重复声明,let和const不可以;
4、var会声明提前,let和const不会声明提前,let 和 const 存在暂时性死区, 凡是在声明之前使用这些变量就会报错;
----暂时性死区:当程序的控制流程在新的作用域进行实例化时,在此作用域中用let/const声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定(对声明语句进行求值运算),所以不能被访问(访问就会抛出错误)。所以在这运行流程进入作用域创建变量,到变量开始被访问之间的一段时间,就称之为temporal dead zone,简称TDZ。
5、let和const 是块级作用域,var不是
6、var声明最外层是在全局下建一个变量,let和const不会
7、let和const 是ES6新命令
(本来也想画个图发现前面的图已经很好了果然都是大佬。。。)
var
声明的变量会提升, 而let
和const
不会提升变量
console.log(a) // 打印的是undefined
var a = 10
console.log(b) // 直接报错
let b = 10
console.log(c) // 直接报错
const c = 10
var
声明的变量的没有块级作用域
, 而使用的let
和const
是有块级作用域的
{
var a = 10
}
console.log(a) // 10
{
let b = 10
}
console.log(a) // 直接报错 b 未定义
{
const c = 10
}
console.log(c) // 和let一样
var
可以相同的作用域中重复定义的一个变量,而let
和const
使用不可以的let
声明的变量是可以重新的赋值的, 而使用的const
声明的变量时候就给变量赋值, 之后也不能重新赋值
{
let a = 100;
a = 10;
console.log(a) // 10
}
{ const b; // 直接报错 console.log(b) const c = 10; c = 100 ;// 直接报错 }
let 声明一个变量,仅可在声明变量的块级作用域使用
const 声明一个只读常量,不可修改,与 let 同存在块级作用域
var 声明一个变量,变量可提升,在声明前就可以使用,变量可重复声明
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i) // 0,1,2 如果用var 打印出来就是333
}, 1000);
}
作用域 let 声明的变量 和 const 声明的常量只在声明所在的块级作用域内有效;var 声明的变量的作用域是函数作用域。
if (true) {
const MAX = 5;
let a = 10;
var b = 1;
MAX // 5
a // 10
b // 1
}
MAX // Uncaught ReferenceError: MAX is not defined
a // ReferenceError: a is not defined.
b // 1
重复声明 let 和 const 不允许在相同作用域内重复声明;var 可以。
let foo;
let foo; // TypeError thrown.
声明提前(变量提升) var 声明会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined;let 和 const 不会。
暂时性死区 let 和 const 存在暂时性死区, 凡是在声明之前使用这些变量就会报错;var 不存在。
function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError: foo is not defined
var bar = 1;
let foo = 2;
}
ES6 规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。 暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
重新赋值 let 和 var 声明的变量可以重新赋值; const 声明的是常量,不得改变值,这意味着,const一旦声明,就必须立即初始化,不能留到以后赋值。
const foo;
// SyntaxError: Missing initializer in const declaration
// 对于const来说,只声明不赋值,就会报错。
let 和 const 作为 ES6 新增的命令,相较 var 有更多的特性,更多内容可以点击下面链接查看: var - JavaScript | MDN let - JavaScript | MDN const - JavaScript | MDN let 和 const 命令 - ECMAScript 6 入门
var是ES5提出的,let和const是ES6提出的。
var声明的变量存在变量提升(将变量提升到当前作用域的顶部)。即变量可以在声明之前调用,值为undefined。 let和const不存在变量提升。即它们所声明的变量一定要在声明后使用,否则报错。
let和const存在暂时性死区。即只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。 总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
var允许重复声明变量。let和const在同一作用域不允许重复声明变量。
var不存在块级作用域。let和const存在块级作用域。 到底什么叫块级作用域呢, JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域。块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
var和let可以。 const声明一个只读的常量。一旦声明,常量的值就不能改变。const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
let 局部作用域变量,有暂时性死区特性 const 局部作用域常量,有暂时性死区特性 var 变量提升特性
let const 是es6引入的新的语法。 var 存在语法提升,会造成内存泄漏 并且 在一个函数总var 可以声明多个一样的变量 eg:var a=1, a=2, a=3; let 在函数中声明的时候不存在语法提升,不会造成内存泄漏 并且存在块级作用域,只有在块级作用域中才能生效 let 的语法比较严格,如果是声明的相同的变量就会报错(如果是在不同的块级作用域中,即使声明一样的也不会报错) eg://想了个简单的例子,不知道妥不妥当 :-) function hello() { let a = 0; console.log(a, 'hello') if (true) { let a = 0; console.log(a, 'obj') } } let b = new hello() console.log(b) const定义的变量不可以修改,而且必须初始化 如果const 声明的是对象,那么是可以改变的 const obj ={ name:'Hello', age:18 } obj.name='Hello world' console.log(obj)
1、var声明的变量会存在变量提升,let和const不存在变量提升 2、var声明的变量会挂载在windows上,let和const声明的变量不会 3、同一个作用域下let和const声明的变量不能同名,但是var可以 4、const一旦声明就必须赋值不能使用null占位,并且声明的不能被修改 5、let和const声明的变量会形成块作用域
var 和 let 用来声明变量,const 只能声明一个只读的常量 let 和 const 具有块级作用域,在作用域之外不可被访问 var 声明的变量存在变量提升,let和const的不存在变量提升 ,在声明之前访问用var定义的变量返回undefined,let和const会直接报错 var 定义的变量可以重复多次声明,后者会覆盖前者,let 和 const 重复声明会报错
var 和 let都是用来定义变量的,而const 是用来定义常量的
consle.log(a) // 可以直接打印
var a = 10; =》 会直接提升为
var a ;
a=10;
consolelog(a);
console.log(b) // 直接是报错,没有提升变量,没有定义,直接报错 let b = 1; // const同样
- 2.作用域不同:var声明变量没有块级作用域,let和const有
fun () { var a = 1; let b = 2; const c = 3; } console.log(a); // 1 console.log(b); // 访问不到报错 console.log(c); // 访问不到报错
- 3.重新赋值
var a = 1; let b = 2; const c = 3;
var a = 10; //ok let b = 20; // 不可以 const c = 30; // 不可以
- 4.只声明不初始化 var、let可以,const不可以
var a; // 可 let b; // 可 const c; //不可以 定义常量
var、 let 用来声明变量,const 声明一个只读的常量 ①let 和 const 在作用域之外不可被访问。 ②var 声明的变量会让变量声明提前,let和const的不存在。 ③在声明之前访问用var定义的变量返回undefined,let和const会直接报错 ④var 定义的变量可以重复多次声明,let 和 const 不能重复声明
1.js本身只有全局作用域和函数作用域,let和const的出现,使得js有了块级作用域。 2.var和let可以用来申明变量,const是申明一个只读的常量。 3.let 和 const 在块级作用域可以获取到对象,出了这个范围就会报错。 4.var 声明的变量可以重复,而let、const则不可以; 5.var 声明的变量可以提升,而let、const则不可以; 6.let声明的变量的值可以更改,而const声明的是常量,则不可以,如果const声明的一个对象,则对象中的属性值可以改变;
let是es6 新增的语法,类似var,却跟var 有所不同
const 是es6新增语法,用来声明常量。
关键点: const声明的值不能改变?不一定。const保证的是变量指向的内存地址的值不变。如果const变量指向的是内存地址的值是string等基本数据类型,那么值是不变的;如果指向的是一个指针(存放着一个地址),那么const变量的值,就有可能发生改变。
function fn() { var a = 5; if (true) { var a = 10; } console.log(a); // 10 } fn() var 声明的结果就10 因为 var 是全局的 如果是let const 声明就存在块级作用 只存在于当前代码块
var a = []; for (let i = 0; i < 10; i++) { a[i] = function() { console.log(i); } } a[1](); //1 此时的值会是1 如果是var 声明的 新值 会覆盖旧值 最后结果会为10 let不存在变量提升,一定要在声明后才能使用,不然会报错
快级作用域内存在let命令,它所声明的变量就绑定在这个区域,不再受外部影响,如果在在块级作用内声明一个局部变量就会报错 var arg = "123"; if (true) { arg = '456'; let arg; console.log(arg); }
let和const声明的变量不存在变量提升,而var会 let,var声明的变量能重新赋值,const用来声明常量,不能重新赋值 let和const有自己的作用域,且不能重复声明
Evilsay和ChasLui两位回答的最简单立体,作为通用知识点,图像更利于分点记忆。
我现在已经养成看东西直接去MDN看的习惯,var的文档在这里。
变量声明,无论发生在何处,都在执行任何代码之前进行处理。用 var 声明的变量的作用域是它当前的执行上下文,它可以是嵌套的函数,也可以是声明在任何函数外的变量。如果你重新声明一个 JavaScript 变量,它将不会丢失其值。
将赋值给未声明变量的值在执行赋值时将其隐式地创建为全局变量(它将成为全局对象的属性)。声明和未声明变量之间的差异是:
由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。这意味着变量可以在声明之前使用,这个行为叫"hoisting"."hoisting"就像是把所有的变量声明移动到函数或者全局代码的开头位置。 类似于:
var bla;
bla = 2;
建议始终在做用用顶部声明变量(全局代码的顶部和函数代码的顶部),这可以清楚知道哪些变量是函数作用域(本地), 哪些变量在作用域链上解决。 重要的是,提升将影响变量声明,而不会影响其值的初始化。当到达赋值语句时,该值被分配。
let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,var声明的变量只能是全局或者整个函数块的。 使用let可以使代码更简单,在某些情景下能代替闭包来实现需求 在同一个函数或块作用域中重复声明同一个变量会引起SyntaxError。
let声明的变量自在其声明的块或子块中可用,这一点,与var相似。二者之间最主要的区别在于var声明的变量的作用域是整个封闭函数。
function varTest() {
var x = 1;
if (true) {
var x = 2; // 同样的变量!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // 不同的变量
console.log(x); // 2
}
console.log(x); // 1
}
let 被创建在包含该声明的(块)作用域顶部,一般被称为“提升”。与通过 var 声明的有初始化值 udefined 的变量不同, 通过let 声明的变知道它们的定义被执行时猜才初始化。在变量初始化之前访问该变量会导致 ReferenceError。该变量处在一个自块顶部到初始化处理的”暂存死区“中
function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2;
}
let的作用域是块,而var的作用域是函数
let块提供了一种在块的范围内获取变量的值,而不会影响块外面名字相同的变量的值的方法。
var x = 5;
var y = 0;
let (x = x + 10, y = 12) {
console.log(x + y); // 27
}
console.log(x + y); // 5
const是块级作用域,很像使用let语句定义的变量。变量的值不能通过重新赋值来改变,并且不能重新声明。
此声明创建一个常量,其作用域可以是全局或本地声明的块。 与var变量不同,全局常量不会变为窗口对象的属性。需要一个常数的初始化器;也就是说,您必须在声明的同一语句中指定它的值(这是有道理的,因为以后不能更改)。
const声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(例如,其参数)。
关于“暂存死区”的所有讨论都适用于let和const。
let和const es6新增了let命令,使用方式类似var ,均用作声明变量,但是let和var也是有很大的区别的。 1.var存在变量提升,let不存在。会存在暂时性死区 2.var不声明使用,相当于在全局声明变量。let不声明使用会报错。 3.let声明为块级作用域,es5中只有全局作用域和函数作用域,没有块级作用域。 4.let不能重复声明回报错。var重复声明时,会去内存中查找声明的这个变量,如果找到了就把值覆盖,没找到就开辟内存来存放这个变量。 使用let可以解决闭包的问题 , const命令是常量的声明,声明时就要赋值,一旦声明则不能改变,对于基本类型则是不能改变值,对于复杂数据类型如object类型数据,则是不能修改地址。
1、let/const是es6的新属性,只在所在的代码块内有效,即暂时性死区,凡是在声明之前就使用这些变量,就会报错。var命令声明的,在全局范围内都有效。
2、let/const不存在变量提升,一定要在声明后使用,否则报错。而var存在变量提升,即变量可以在声明之前使用,值为undefined。
3、let/const不允许在相同作用域内,重复声明同一个变量。而var可以。
4、const在声明时必须赋值,对于简单类型的数据,变量指向的那个内存地址所保存的数据不可改,即常量。而对于复杂型的数据,如对象和数组,保存的是指针,const只能保证指针是固定的,但数据结构可变。
复习下MDN
var:(声明语句声明一个变量,并可选地将其初始化为一个值),存在变量提升(无论发生在何处,都在执行代码之前进行处理),在函数作用域内都可以重复声明,作用域范围是函数作用域
let:(声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。),不存在变量提升,在同一块级作用域内不能重复声明,存在暂存死区,作用域范围是块级作用域
const :声明变量的物理地址不能变,不能通过重新赋值来改变其值,在声明的同时必须要初始化,不存在变量提升,在同一块级作用域内不能重复声明,存在暂存死区,作用域范围是块级作用域
var,let声明变量,const声明常量,var能重复声明 let,const重复声明会报错 let,const都是声明后使用,不会变量提升 const赋值会报错,如果const声明的是对象,改变对象的属性不会报错。
首先var,let,const都是定义变量的方式, 其实const是定义常量,当定义常量的时候,就不能对常量的值进行改变, let就是定义块级作用域。 (微信名:RUN)
console.log(a); // undefined
var a = 8;
console.log(b); let b = 10; //Uncaught ReferenceError: Cannot access 'b' before initialization
2. let存在暂时性死区,即只要块级作用域存在let,那么let就会绑定到这个块级作用域里面不收外界的影响。var则不会。
var tmp = 123;
if (true) { tmp = 'abc'; // ReferenceError let tmp; }
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。
3. let 不允许在相同作用域内,重复声明同一个变量。而 var 则可以
let a = 10; let a = 20; // Uncaught SyntaxError: Identifier 'a' has already been declared
var b = 10; var b =20;
### const 与 let、var的区别?
1. const声明一个只读的常量。一旦声明,常量的值就不能改变。
2. const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
3. const的作用域与let命令相同:只在声明所在的块级作用域内有效。
4. const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
最后附上:
[阮一峰老师的let,const](http://es6.ruanyifeng.com/#docs/let)
var
声明的变量会存在变量提升
let
有块级作用域的概念
const
声明的变量不能被改变,而且必须要初始化
const b; // 错误
const b=2; // 正确
下面看一道经典的例子
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000);
}
// 3 3 3
改成
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000);
}
// 0 1 2
三次setTimeout 的回调共享同一变量,循环结束的时候i为3,let 就是解决这个问题
let
var
定义一个变量const
定义一个常量let
const
声明在代码块有效,不存在变量提升,相同作用域中,不能重复声明var
声明在函数作用域内有效,存在变量提升,相同作用域中,可以重复声明const
一旦声明,必须立即初始化var
let
声明则不需要var 声明的变量存在变量提升,也就是说 var 声明的变量可以在声明之前使用; let 和 const 声明的变量不存在变量提升,使用 let 和 const 声明的变量都必须先声明后使用,在声明之前使用都会报错(暂时性死区)。
var 命令可以重复声明同名变量,然后覆盖掉之前声明的变量; let 和 const 命令不允许重复声明同名变量。
var 和 let 命令在声明变量时可以赋值,也可以不赋值,赋值后还可以修改; const 命令在声明变量时必须要赋值,否则报错;严格来说 const 声明的是一个常量,赋值后不允许修改。
var 命令声明的变量不存在块级作用域,即在大括号 { } 中声明会变量提升到当前作用域(全局作用域或函数作用域)的头部; let 和 const 命令声明的变量存在块级作用域,在大括号({})中声明变量会绑定在当前的作用域内,外部访问不到; 另外,for 循环中的 ( ) 使用 let 声明也会形成块级作用域,与 for 循环体中的 { } 块级作用域是父子关系。
es5中只有全局作用域和函数作用域,并没有块级作用域,因此在es6中就增加了 let和const两个命令来改善var的一些不合理,不严谨的地方。下面我就就进行一一的对比,比较一些他们之间的区别 (step-by-step) let 命令 - 不存在变量提示 如果不知道什么是变量提升,可以具体看下,艳的昨天的问题,js的执行上下文,里面有详细的解释,简单的例子
console.log(a1)
console.log(a2)
var a1 = 1;
let a2 = 2;
- 作用域是块级作用域 es5中只有函数作用域和全局作用域,let声明的变量只在所声明的代码块内有效。块级作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
if (true) {
var b1 = 1;
let b2 = 2;
}
console.log(b1)
console.log(b2)
- let不允许在同一作用域内重复声明同一个变量 在同一作用域内,如果使用var声明同一个变量,则后面的覆盖前面的,但是用let 重复声明同一个变量会发什么什么呢,请看代码
var c1 = 1;
var c1 = 2;
console.log(c1); // 2
let c2 = 1;
let c2 = 2;
console.log(c2); // 报错 “Identifier 'c2' has already been declared”
let c3 = 3
if (true) {
let c3 = 33; // 没有在同一作用域是可以的
}
console.log(c3); // 3
- 存在暂时性死区 暂时性死区的本质就是,只要一进入当前作用域,所使用的变量就已存在,但是不可获取,只有等到声明变量的哪一行代码的出现,在可以获取和使用该变量。 // 理解暂时性死区
let d = 10;
function fn() {
// console.log(d);
let d = 5;
}
fn(); // ReferenceError: Cannot access 'd' before initialization
const 命令 const命令和let相似,但也有不同之处 - const用来声明常量,一旦声明,其值就不能更改
const f1 = 1;
var f1 = 2;
console.log(f1); // Identifier 'f1' has already been declared
那么如果使用const声明对象呢?
const obj = {
name:"xixi",
age :28
}
obj.name = "xiaxia"
console.log(obj.name + obj.age) // xiaxia28
我们可以看到,使用const声明的对象的属性是可以修改。 因为Object类型是引用类型。用const声明常量保存的是对象的地址,不可变的是地址,在上面的代码中就是,不能把 b指向另一个对象。而修改对象的属性,并不会改变对象的地址,因此用const声明对象的属性是可以修改的
a = 10;
var a; //正常
a = 10;
let a; //ReferenceError
let a = 10;
var a = 20;
//抛出异常:SyntaxError: Identifier 'a' has already been declared
这里有一个非常重要的点即是:复杂数据类型,存储在栈中的是堆内存的地址,存在栈中的这个地址是不变的,但是存在堆中的值是可以变得。有没有相当常量指针/指针常量~
const a = 20;
const b = {
age: 18,
star: 500
}
一图胜万言,如下图所示,不变的是栈内存中 a 存储的 10,和 b 中存储的 0x0012ff21(瞎编的一个数字)。而 {age: 18, star: 200} 是可变的。思考下如果想希望一个对象是不可变的,应该用什么方法?
{
let a = 10;
const b = 20;
var c = 30;
}
console.log(a); //ReferenceError
console.log(b); //ReferenceError
console.log(c); //30
在 let/const 之前,最早学习JS的时候,也曾被下面这个问题困扰:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
虽然后来知道了为什么,但是想要得到自己需要的结果,还得整个闭包,我...我做错了什么,要这么对我...
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function(j){
return function () {
console.log(j);
}
})(i)
}
a[6](); // 6
有了 let 之后,终于不要这么麻烦了。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
美滋滋,有没有~
美是美了,但是总得问自己为什么吧~
第一个 var i
为什么输出的是 10,这是因为 i 在全局范围内都是有效的,相当于只有一个变量 i,等执行到 a[6]()
的时候,这个 i 的值是什么?请大声说出来。
再看 let , 我们说 let 声明的变量仅在块级作用域内有效,变量i是let声明的,当前的 i 只在本轮循环有效,所以每一次循环的 i 其实都是一个新的变量。有兴趣的小伙伴可以使用看一下 babel 编译后的代码。
var a = 10;
console.log(window.a);//10
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
var a = 10;
if (true) {
a = 20; // ReferenceError
let a;
}
在代码块内,使用 let/const 命令声明变量之前,该变量都是不可用的,也就意味着 typeof 不再是一个百分百安全的操作。
console.log(typeof b);//undefined
console.log(a); //ReferenceError
let a = 10;
const
只能保证这个指针是固定的, 对于它指向的数据结构就不能控制