ES6新增let 和 const,这里记录一些疑难点理解的思路。
let声明的变量,只在当前代码块中生效,很适合用在for循环上
for(let i = 0; i < 10; i++) {
console.log(i);
}
console.log("代码块外", i);
代码块外会报错,这里注意,let定义的i只在本轮循环生效,每轮循环的i都是不同的,但是计算循环的值是JS引擎在上一轮的基础上进行计算的,所以不会遗忘上一轮的值而无法计算下一轮的值。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
上面这一段会输出3个abc,是因为for循环存在两个作用域,一个是定义循环变量的父级作用域,一个是循环体内部的子作用域。
变量提升即是未定义也能输出undefined:
console.log(a);
var a = 1;
这时候会输出undefined,脚本运行变量已存在,但是未赋值。
console.log(a);
let a = 1;
这时候输出的错误就是ReferenceError(引用未存在的变量错误)。
总而言之,言而总之,就是定义了再用,不要搞那么多骚操作。
下面记录一个大头问题,我也不知道算理解没有。。总之遇到的话应该能够识别解决吧。
暂时性死区:
块级作用域中只要存在,那么它所声明的变量就绑定该代码块,不受外部影响。
var a = 123;
if (true) {
a = 1;
let a;
}
像这块,if代码块中的let a让变量a绑定了该代码块,所以进行赋值的时候他并不能取到代码块外的a,即是在赋值之前加入console语句也打印不了,被锁死在了这块代码块中。
var temp = '123';
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
这一段,死区(TDZ)到tmp的let定义结束,之前都是死区,任何对temp的操作都会报出 ReferenceError,只有在定义之后才能使用。
// 不报错
var x = x;
// 报错
let x = x;
// ReferenceError: x is not defined
这一段放在一起执行的话会提醒重复定义(处在同一代码块)。。所以分开来执行,第一句的话是不会报错的,第二句用let声明的就会出问题了,相当于 let x = {x}; 这样将x锁死在了代码块中,而赋值的x并没有定义,所以会抛出错误。
块级作用域:
注意代码块层级关系
(function a(){
let b = 5;
if(b == 5) {
let c = b * 2;
}
console.log(c);
})()
这里会报C未定义,主讲这里的匿名函数。
这个函数相当于:
function a(){
let b = 5;
if(b == 5) {
let c = b * 2;
}
console.log(c);
}
a();
块级作用域出现后,就不用这么写了,而是如下
{ let tmp = 1; console.log("块级作用域" + tmp) } (function() { let tmp = 1; console.log("IIFE" + tmp) })();
同时,ES6的块级作用域支持声明函数,
{ function f() { console.log('2333'); } let a = 1; let c = function() { return a; } }
只执行一次的函数可以这么做,需要多次调用则提取至公共区域。
const声明的变量不能改变,在所定义的块级作用域中生效,存在暂时性死区,不能重复定义,对于简单的数据类型,const声明的变量指向的内存地址存储的便是值本身;对于复合数据(对象、数组...),变量指向的内存地址,保存的是一个指针,指针固定,但其指向的数据结构不确定,如果存储的是一个对象,我们可以对对象的属性进行编辑:
{ const a = {}; a.name = "Tom"; console.log(a.name); }
数组的话我们可以对其定义的本身的数组进行增删操作,却不能将另一个数组再次赋值给声明的变量。
顶层对象:浏览器中指的是window对象,在node中是global对象,ES5中,顶层对象‘属性’和全局变量等价。
顶层对象属性和全局变量等价带来了许多问题,最典型的便是我们只有在运行后才知道变量的未声明错误,不能在编译期就报错,是因为全局变量可能是顶层对象属性创建的,而属性的创建是动态的。
到了ES6,let、const命令声明的变量不属于顶层对象的属性,但是var和function仍是:
var a = 1; console.log(window.a); const b = 1; console.log(window.b);第一个打印能打印出1,第二个undefined。