1. 简介
ECMAScript6.0也称ES6,是JavaScript 语言的下一代标准,2015 年 6 月正式发布,目的是使JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
1.1 ES6与JavaScript的关系
ES6发布的第一个版本就成为规定了浏览器脚本语言的标准,并将这种语言称为ECMAScript,这种标准一开始就针对JavaScript语言制定,取名的原因与公司和商标有关,总之ES6和JavaScript的关系是,前者是后者的规范,后者是前者的一种实现。
1.2 Node下查看默认没有打开的ES6实验性语法
// Linux & Mac
$ node --v8-options | grep harmony
// Windows
$ node --v8-options | findstr harmony
这里就拿Windows下举例
1.3 ES6代码转ES5代码
利用Babel转换器实现代码转换,原始代码用了箭头函数,Babel将其转换普通函数。
// 转码前
input.map(item => item + 1);
// 转码后
input.map(function (item) {
return item + 1;
});
2. let和const的变量声明及特点
2.1 let的命令用法
let是ES6新增的命令,用来声明变量,方法类似于var,但所声明变量只在其规定的let命令所在代码块内有效,例如
{
var a = 1;
let b = 2;
}
console.log(a);
console.log(b);
上面代码分别用var 和 let 声明两个变量并在外调用,结果let声明变量报错,表明let只能在规定代码块内才能使用。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[2](); // 2
//a[3](); // 3
上面代码是用let声明,声明的变量仅在块级作用域内有效,所以说当前的i只在本轮循环有效,因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量
i
时,就在上一轮循环的基础上进行计算,所以每次循环的i都是一个新的变量,所以最后输出的就是对应的值。
2.2 let的变量提升情况
我们知道,如果我们使用var命令,在预解析的作用域下,会导致变量提升,详情请看我相关博客的介绍:JavaScript入门到精通(四)连载_亦世凡华、的博客-CSDN博客
ES6为了纠正这种现象,使得let命令改变了语法行为,它所声明的变量一定要在声明后,否则会报错。例如:
// var
console.log(a); // 输出undefined
var a = 1;
// let
console.log(b); // 报错ReferenceError
let b = 1;
var的声明下,由于变量提升会先声明a但不赋值,执行输出语句当然是undefined,而let声明下,由于没有变量提升,输出b前,b是不存在的,只能抛出一个错误
2.3 let的重复声明情况
let不允许在相同作用域内重复声明同一个变量;所以也不能在函数内部重新声明参数。否则报错
function fn() {
let a = 1;
let a = 2;
} // 报错
function fn() {
let a = 1;
var a = 2;
} // 报错
function fn(a) {
let a;
}
fn() // 报错
function fn(a) {
{
let a;
}
}
fn() // 不报错
2.4 let的暂时性死区
在代码块内,使用let命令声明变量之前,该变量都是不可使用的,凡是在声明之前就使用这些变量,就会报错,这在语法上,称为“暂时性死区(TDZ)”。
if (true) {
// TDZ开始
a = '张小凡'; // ReferenceError
console.log(a); // ReferenceError
let a; // TDZ结束
console.log(a); // undefined
a = '张小凡';
consle.log(a); // 张小凡
}
上面代码中,在
let
命令声明变量
a
之前,都属于变量
a
的“死区”,ES6规定暂时性死区主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的错误,这种规定显然很容易避免了这样的错误。
2.5 const的命令用法
const声明的是一个只读变量,一旦声明,变量的值无法更改,否则报错
const a = '张小凡';
console.log(a);
a = '666';
console.log(a);
const声明的变量不能改变值意味着,一旦const声明就必须进行初始化,不立即赋值会立马报错。
const a;
2.6 const的其它特点
const和let一样,只在声明所在的块级作用域内有效,声明的常量也不存在变量提升,同样存在暂时性死区,声明的常量也与let一样不可重复声明。
2.7 const的实际作用
const保证的并不是变量的值不能变动,而是变量指向的那个内存地址所保存的数据不能变动。
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
上面代码中,常量
a
是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给
a
,就会报错。
3. ES6的6种声明变量方式
常见的:var 和 function;ES6添加的 let 和 const ;以及另外两种 import 和 class 命令
4. 变量的赋值-解构
ES6允许从数组和对象中提取值,对变量进行赋值,被称为“解构”
4.1 数组的解构
以数组方式进行变量赋值属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予相对应的值,这样的赋值方式比以前的赋值方式更简单和清楚。解构不成功右边的值会是undefined;不完全解构的话,左边的模式会匹配右边相对应的部分;等号右边不是数组会报错;解构赋值允许指定默认值,最后一个表达式之所以会报错,是因为
m
用
n
做默认值时,
n
还没有声明
var[a,[[b],c]] = [1,[[2],3]];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
let [ , , d] = ["A", "B", "C"];
console.log(d); // "C"
let [x,,y] = [1, 2, 3];
console.log(x); // 1
console.log(y); // 3
let [A,B, ...C]=['a']
console.log(A) //a
console.log(B) //undefined
console.log(C) //[]
let [o] = 1; //报错
let [m = 1, n = m] = []; // m=1; n=1
let [m = 1, n = m] = [2]; // m=2; n=2
let [m = 1, n = m] = [1, 2]; // m=1; m=2
let [m =n, n = 1] = []; // ReferenceError: n is not defined
4.2 对象的解构
与数组解构不同,对象解构变量必须与属性同名,才能取到正确的值。
let { a, b } = { a: 'aaa', b: 'bbb' };
console.log(a);
console.log(b);
let { c } = { d: 'ddd', e: 'eee' };
console.log(c);
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。 说白了就是,a是匹配的模式,b才是变量,真正被赋值的是b而不是模式a
let { a: b } = { a: 'aaa', b: 'bbb' };
console.log(b);
console.log(a);
对象的解构也可以指定默认值。
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null
上面代码中,属性
x
等于
null
,因为
null
与
undefined
不严格相等,所以是个有效的赋值,导致默认值
3
不会生效。
4.3 字符串的解构
对字符串进行解构后,得到的是类似于数组的对象
const [a, b, c, d, e] = 'hello';
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);
4.4 函数参数的解构
function fun([x, y]){
return x + y;
}
add([2, 2]); // 4
函数fun的参数表面上是一个数组,但传入参数的那一刻,数组参数就被解构成变量x和y,当然函数参数也可以使用默认值。
function arr({x = 0, y = 0} = {}) {
return [x, y];
}
arr({x: 3, y: 8}); // [3, 8]
arr({x: 3}); // [3, 0]
arr({}); // [0, 0]
arr(); // [0, 0]
4.5 数值和布尔值的解构
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象,数值和布尔值的包装对象都有
toString
属性,因此变量
s
都能取到值。由于
undefined
和
null
无法转为对象,所以对它们进行解构赋值,都会报错。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
4.6 圆括号问题
ES6 的规则:只要有可能导致解构的歧义,就不得使用圆括号。
// 全部报错
let [(a)] = [1];//变量声明语句
function f([(z)]) { return z; }//函数参数
({ p: a }) = { p: 42 };//赋值语句模式
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是
p
,而不是
d
;第三行语句与第一行语句的性质一致。
4.7 注意点
(1)一个已经声明的变量用于解构赋值
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
// 正确的写法
let x;
({x} = {x: 1});
JavaScript 引擎会将
{x}
理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
(2)解构赋值允许等号左边的模式之中,不放置任何变量名。
({} = [true, false]);
({} = 'abc');
({} = []);
(3)可以对数组进行对象属性的解构。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
4.8 解构的作用
(1)交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
(2)函数参数的定义 (方便将一组参数和变量名对应起来)
function f({x, y, z}) { }
f({z: 3, y: 2, x: 1});
(3)从函数中返回多个值 (函数只能返回一个值,放在数值或对象中返回多个)
// 返回一个数组
function a() {
return [1, 2, 3];
}
let [a, b, c] = a();
console.log(a());
// 返回一个对象
function b() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = b();
console.log(b());
(4)函数参数默认值(避免了在函数体内再书写)
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
(5)输入模块的指定方法 (使输入语句非常清晰)
const { SourceMapConsumer, SourceNode } = require("source-map");
(6)遍历Map解构 (Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便)。
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
(7)提取JSON数据
let jsonData = {
id: 2022,
sex: "boy",
data: [1, 2]
};
let { id, sex, data: number } = jsonData;
console.log(id, sex, number);
呼~,因为学习,文章拖了俩天才写完,不过总算是搞完了,本文一方面是加深自己对ES6的学习和提高知识的储备;另一方面也是希望帮助看到这篇文章的人学习更多的知识。今后也会不间断的更新关于前端的知识,大家一起共勉,一起进步,不足之处,还请指正。
想学习更多前端知识,关注博主,不迷路~~~~
下一篇:
未完待续。。。。。。
版权归原作者 亦世凡华、 所有, 如有侵权,请联系我们删除。