Fork me on GitHub

ES6增加的扩展

ECMAScript是什么

JavaScript是JavaScript的重要组成部分。简单一句话,ESMAScript是JavaScript的语法规范。与DOM,BOM成为JavaScript的3驾马车。不仅如此,它还定义了语法,类型,原型和继承及内置对象和函数标准库。

ECMAScript 和 JavaScript 的关系

ECMAScript是JavaScript的基础标准部分,前者是后者的规格,后者是前者的一种实现。

ES6 与 ECMAScript 2015 的关系

ES6是一个泛指,是5.1版以后的 JavaScript 的下一代标准,涵盖了ES2015、ES2016、ES2017等.而ES2015 则是正式名称,特指该年发布的正式版本的语言标准。

let命令

1
2
3
{var a=10; let b=1;}
a //10
b // ReferenceError: b is not defined.

表明let只在它所在的代码块起作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
//i在全局范围内部都有效
var b=[];
for(let i=0;i<10;i++){
b[i] = function () {
console.log(i)
}
}
b[6](); // 6
//i只在本轮循环中有效
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
//输出了3次abc。表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

let不存在变量提升

var命令的变量可在声明前使用,值为undefined
let命令的变量必须先声明在使用。

1
2
3
4
5
6
console.log(foo);
var foo=2;
//undefined
console.log(bar);
let bar=2;
//ReferenceError: bar is not defined

暂时性死区

ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

只要块级作用域中存在let命令,所声明的变量就绑定之歌区域,不再受外部影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//使用let命令声明变量之前,该变量不可用
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
// 不报错
var x = x;
// 报错
let x = x;
// ReferenceError: x is not defined

小结

ES6 规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

用let声明的变量只在块级作用域起作用,适用于for循坏。在同一个代码块中,不可声明相同的变量,不可重复声明函数内的参数。

不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 报错
function () {
let a = 10;
var a = 1;
}
// 报错
function () {
let a = 10;
let a = 1;
}
function func(arg) {
let arg; // 报错
}
function func(arg) {
{
let arg; // 不报错
}
}

块级作用域

存在原因一:内层变量可能会覆盖外层变量。

1
2
3
4
5
6
7
8
9
var tmp=new Date();
function f(){
console.log(tmp);
if(false){
var tmp="hello wrold!";
}
}
f();
//由于变量提升,导致内层变量覆盖外层变量,使得输出结果为undefined

存在原因二:用来计数的循环变量泄露为全局变量。

1
2
3
4
5
6
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
//变量i用于控制循环,但循环结束后,并没有消失,而成为了全局变量。

ES6块级作用域

1
2
3
4
5
6
7
8
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
//表示外层代码块不受内层块级代码快的影响,若使用var声明,结果为10

const 命令

const声明一个只读的常量。一旦声明,常量的值就不能改变。要注意声明引用类型的常量时,是传址赋值

1
2
3
4
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.

小结:

  • 对于const来说,只声明不赋值,就会报错。
  • const的作用域与let命令相同:只在声明所在的块级作用域内有效。
  • const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
  • const声明的常量,也与let一样不可重复声明。

本质:

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

顶层对象的属性

顶层对象,在浏览器环境指的是window对象,在Node指的是global对象。ES5之中,顶层对象的属性与全局变量是等价的。

var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性,换言之,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。

1
2
3
4
5
6
var a = 1;
window.a // 1
let b = 1;
window.b // undefined
//以上可看出全局变量a由var命令声明,所以它是顶层对象的属性;全局变量b由let命令声明,所以它不是顶层对象的属性,返回undefined。

不断加深理解并加以完善。。。

据说帅的人都赏给博主几块钱零花钱。