
ES6系列目录
- 1 let 和 const命令
- 2 变量的解构赋值
- 3 字符串的拓展
- 4 正则的拓展
- 5 数值的拓展
- 6 函数的拓展
- 7 数组的拓展
- 8 对象的拓展
- 9 Symbol
- 10 Set和Map数据结构
- 11 Proxy
- 12 Promise对象
- 13 Iterator和 for...of循环
- 14 Generator函数和应用
- 15 Class语法和继承
- 16 Module语法和加载实现
所有整理的文章都收录到我《Cute-JavaScript》系列文章中,访问地址:http://js.pingan8787.com
1 let 和 const命令
在ES6中,我们通常实用 let 表示变量, const 表示常量,并且 let 和 const 都是块级作用域,且在当前作用域有效不能重复声明。
1.1 let 命令
let 命令的用法和 var 相似,但是 let 只在所在代码块内有效。
基础用法:
-
{ -
let a = 1; -
let b = 2; -
}
并且 let 有以下特点:
- 不存在变量提升:
在ES6之前,我们 var 声明一个变量一个函数,都会伴随着变量提升的问题,导致实际开发过程经常出现一些逻辑上的疑惑,按照一般思维习惯,变量都是需要先声明后使用。
-
// var -
console.log(v1); // undefined -
var v1 = 2; -
// 由于变量提升 代码实际如下 -
var v1; -
console.log(v1) -
v1 = 2; -
// let -
console.log(v2); // ReferenceError -
let v2 = 2;
- 不允许重复声明:
let 和 const 在相同作用域下,都不能重复声明同一变量,并且不能在函数内重新声明参数。
-
// 1. 不能重复声明同一变量 -
// 报错 -
function f1 (){ -
let a = 1; -
var a = 2; -
} -
// 报错 -
function f2 (){ -
let a = 1; -
let a = 2; -
} -
// 2. 不能在函数内重新声明参数 -
// 报错 -
function f3 (a1){ -
let a1; -
} -
// 不报错 -
function f4 (a2){ -
{ -
let a2 -
} -
}
1.2 const 命令
const 声明一个只读的常量。
基础用法:
-
const PI = 3.1415926; -
console.log(PI); // 3.1415926
注意点:
-
const 声明后,无法修改值;
-
const PI = 3.1415926; -
PI = 3; -
// TypeError: Assignment to constant variable.
-
const 声明时,必须赋值;
-
const a ; -
// SyntaxError: Missing initializer in const declaration.
-
const 声明的常量, let 不能重复声明;
-
const PI = 3.1415926; -
let PI = 0; -
// Uncaught SyntaxError: Identifier 'PI' has already been declared
2 变量的解构赋值
解构赋值概念:在ES6中,直接从数组和对象中取值,按照对应位置,赋值给变量的操作。
2.1 数组
基础用法:
-
// ES6 之前 -
let a = 1; -
let b = 2; -
// ES6 之后 -
let [a, b] = [1, 2];
本质上,只要等号两边模式一致,左边变量即可获取右边对应位置的值,更多用法:
-
let [a, [[b], c]] = [1, [[2], 3]]; -
console.log(a, b, c); // 1, 2, 3 -
let [ , , c] = [1, 2, 3]; -
console.log(c); // 3 -
let [a, , c] = [1, 2, 3]; -
console.log(a,c); // 1, 3 -
let [a, ...b] = [1, 2, 3]; -
console.log(a,b); // 1, [2,3] -
let [a, b, ..c.] = [1]; -
console.log(a, b, c); // 1, undefined, []
注意点:
- 如果解构不成功,变量的值就等于
undefined。
-
let [a] = []; // a => undefined -
let [a, b] = [1]; // a => 1 , b => undefined
- 当左边模式多于右边,也可以解构成功。
-
let [a, b] = [1, 2, 3]; -
console.log(a, b); // 1, 2
- 两边模式不同,报错。
-
let [a] = 1; -
let [a] = false; -
let [a] = NaN; -
let [a] = undefined; -
let [a] = null; -
let [a] = {};
指定解构的默认值:
基础用法:
-
let [a = 1] = []; // a => 1 -
let [a, b = 2] = [a]; // a => 1 , b => 2
特殊情况:
-
let [a = 1] = [undefined]; // a => 1 -
let [a = 1] = [null]; // a => null
右边模式对应的值,必须严格等于 undefined,默认值才能生效,而 null不严格等于 undefined。
2.2 对象的解构赋值
与数组解构不同的是,对象解构不需要严格按照顺序取值,而只要按照变量名去取对应属性名的值,若取不到对应属性名的值,则为 undefined 。
基础用法:
-
let {a, b} = {a:1, b:2}; // a => 1 , b => 2 -
let {a, b} = {a:2, b:1}; // a => 2 , b => 1 -
let {a} = {a:3, b:2, c:1};// a => 3 -
let {a} = {b:2, c:1}; // a => undefined
注意点:
- 若变量名和属性名不一致,则需要修改名称。
-
let {a:b} = {a:1, c:2}; -
// error: a is not defined -
// b => 1
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
上面代码中, a 是匹配的模式, b才是变量。真正被赋值的是变量 b,而不是模式 a。
- 对象解构也支持嵌套解构。
-
let obj = { -
a:[ 1, { b: 2}] -
}; -
let {a, a: [c, {b}]} = obj; -
// a=>[1, {b: 2}], b => 2, c => 1
指定解构的默认值:
-
let {a=1} = {}; // a => 1 -
let {a, b=1} = {a:2}; // a => 2, b => 1 -
let {a:b=3} = {}; // b => 3 -
let {a:b=3} = {a:4}; // b = >4 -
// a是模式,b是变量 牢记 -
let {a=1} = {a:undefined}; // a => 1 -
let {a=1} = {a:null}; // a => null -
// 因为null与undefined不严格相等,所以赋值有效 -
// 导致默认值1不会生效。
2.3 字符串的解构赋值
字符串的解构赋值中,字符串被转换成了一个类似数组的对象。 基础用法:
-
const [a, b, c, d, e] = 'hello'; -
a // "h" -
b // "e" -
c // "l" -
d // "l" -
e // "o" -
let {length:len} = 'hello';// len => 5
2.4 数值和布尔值的解构赋值
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined和 null无法转为对象,所以对它们进行解构赋值,都会报错。
-
// 数值和布尔值的包装对象都有toString属性 -
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
2.5 函数参数的解构赋值
基础用法:
-
function fun ([a, b]){ -
return a + b; -
} -
fun ([1, 2]); // 3
指定默认值的解构:
-
function fun ({a=0, b=0} = {}){ -
return [a, b]; -
} -
fun ({a:1, b:2}); // [1, 2] -
fun ({a:1}); // [1, 0] -
fun ({}); // [0, 0] -
fun (); // [0, 0] -
function fun ({a, b} = {a:0, b:0}){ -
return [a, b]; -
} -
fun ({a:1, b:2}); // [1, 2] -
fun ({a:1}); // [1, undefined] -
fun ({}); // [undefined, undefined] -
fun (); // [0, 0]
2.6 应用
- 交换变量的值:
-
let a = 1,b = 2; -
[a, b] = [b, a]; // a =>2 , b => 1
- 函数返回多个值:
-
// 返回一个数组 -
function f (){ -
return [1, 2, 3]; -
} -
let [a, b, c] = f(); // a=>1, b=>2, c=>3 -
// 返回一个对象 -
function f (){ -
return {a:1, b:2}; -
} -
let {a, b} = f(); // a=>1, b=>2
- 快速对应参数: 快速的将一组参数与变量名对应。
-
function f([a, b, c]) {...} -
f([1, 2, 3]); -
function f({a, b, c}) {...} -
f({b:2, c:3, a:1});
- 提取JSON数据:
-
let json = { -
name : 'leo', -
age: 18 -
} -
let {name, age} = json; -
console.log(name,age); // leo, 18
- 遍历Map结构:
-
const m = new Map(); -
m.set('a', 1); -
m.set('b', 2); -
for (let [k, v] of m){ -
console.log(k + ' : ' + v); -
} -
// 获取键名 -
for (let [k] of m){...} -
// 获取键值 -
for (let [,k] of m){...}
- 输入模块的指定方法: 用于按需加载模块中需要用到的方法。
-
const {log, sin, cos} = require('math');
3 字符串的拓展
3.1 includes(),startsWith(),endsWith()
在我们判断字符串是否包含另一个字符串时,ES6之前,我们只有 typeof方法,ES6之后我们又多了三种方法:
- includes():返回布尔值,表示是否找到参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
-
let a = 'hello leo'; -
a.startsWith('leo'); // false -
a.endsWith('o'); // true -
a.includes('lo'); // true
并且这三个方法都支持第二个参数,表示起始搜索的位置。
-
let a = 'hello leo'; -
a.startsWith('leo',1); // false -
a.endsWith('o',5); // true -
a.includes('lo',6); // false
endsWith 是针对前 n 个字符,而其他两个是针对从第 n个位置直到结束。
3.2 repeat()
repeat方法返回一个新字符串,表示将原字符串重复 n次。
基础用法:
-
'ab'.repeat(3); // 'ababab' -
'ab'.repeat(0); // ''
特殊用法:
- 参数为
小数,则取整
-
'ab'.repeat(2.3); // 'abab'
- 参数为
负数或 Infinity,则报错
-
'ab'.repeat(-1); // RangeError -
'ab'.repeat(Infinity); // RangeError
- 参数为
0到-1的小数或 NaN,则取0
-
'ab'.repeat(-0.5); // '' -
'ab'.repeat(NaN); // ''
- 参数为
字符串,则转成 数字
-
'ab'.repeat('ab'); // '' -
'ab'.repeat('3'); // 'ababab'
3.3 padStart(),padEnd()
用于将字符串头部或尾部补全长度, padStart()为头部补全, padEnd()为尾部补全。
这两个方法接收2个参数,第一个指定字符串最小长度,第二个用于补全的字符串。
基础用法 :
-
'x'.padStart(5, 'ab'); // 'ababx' -
'x'.padEnd(5, 'ab'); // 'xabab'
特殊用法:
- 原字符串长度,大于或等于指定最小长度,则返回原字符串。
-
'xyzabc'.padStart(5, 'ab'); // 'xyzabc'
- 用来补全的字符串长度和原字符串长度之和,超过指定最小长度,则截去超出部分的补全字符串。
-
'ab'.padStart(5,'012345'); // "012ab"
- 省略第二个参数,则用
空格补全。
-
'x'.padStart(4); // ' x' -
'x'.padEnd(4); // 'x '
3.4 模版字符串
用于拼接字符串,ES6之前:
-
let a = 'abc' + -
'def' + -
'ghi';
ES6之后:
-
let a = ` -
abc -
def -
ghi -
`
拼接变量:
在反引号(`)中使用 ${}包裹变量或方法。
-
// ES6之前 -
let a = 'abc' + v1 + 'def'; -
// ES6之后 -
let a = `abc${v1}def`
4 正则的拓展
4.1 介绍
在ES5中有两种情况。
- 参数是字符串,则第二个参数为正则表达式的修饰符。
-
let a = new RegExp('abc', 'i'); -
// 等价于 -
let a = /abx/i;
- 参数是正则表达式,返回一个原表达式的拷贝,且不能有第二个参数,否则报错。
-
let a = new RegExp(/abc/i); -
//等价于 -
let a = /abx/i; -
let a = new RegExp(/abc/, 'i'); -
// Uncaught TypeError
ES6中使用:
第一个参数是正则对象,第二个是指定修饰符,如果第一个参数已经有修饰符,则会被第二个参数覆盖。
-
new RegExp(/abc/ig, 'i');
4.2 字符串的正则方法
常用的四种方法: match()、 replace()、 search()和 split()。
4.3 u修饰符
添加 u修饰符,是为了处理大于 uFFFF的Unicode字符,即正确处理四个字节的UTF-16编码。
-
/^\uD83D/u.test('\uD83D\uDC2A'); // false -
/^\uD83D/.test('\uD83D\uDC2A'); // true
由于ES5之前不支持四个字节UTF-16编码,会识别为两个字符,导致第二行输出 true,加入 u修饰符后ES6就会识别为一个字符,所以输出 false。
注意:
加上 u修饰符后,会改变下面正则表达式的行为:
- (1)点字符 点字符(
.)在正则中表示除了换行符以外的任意单个字符。对于码点大于 0xFFFF的Unicode字符,点字符不能识别,必须加上 u修饰符。
-
var a = "𠮷"; -
/^.$/.test(a); // false -
/^.$/u.test(a); // true
- (2)Unicode字符表示法 使用ES6新增的大括号表示Unicode字符时,必须在表达式添加
u修饰符,才能识别大括号。
-
/\u{61}/.test('a'); // false -
/\u{61}/u.test('a'); // true -
/\u{20BB7}/u.test('𠮷'); // true
- (3)量词 使用
u修饰符后,所有量词都会正确识别码点大于 0xFFFF的 Unicode 字符。
-
/a{2}/.test('aa'); // true -
/a{2}/u.test('aa'); // true -
/𠮷{2}/.test('𠮷𠮷'); // false -
/𠮷{2}/u.test('𠮷𠮷'); // true
- (4)i修饰符 不加
u修饰符,就无法识别非规范的 K字符。
-
/[a-z]/i.test('\u212A') // false -
/[a-z]/iu.test('\u212A') // true
检查是否设置 u修饰符:使用 unicode属性。
-
const a = /hello/; -
const b = /hello/u; -
a.unicode // false -
b.unicode // true
4.4 y修饰符
y修饰符与 g修饰符类似,也是全局匹配,后一次匹配都是从上一次匹配成功的下一个位置开始。区别在于, g修饰符只要剩余位置中存在匹配即可,而 y修饰符是必须从剩余第一个开始。
-
var s = 'aaa_aa_a'; -
var r1 = /a+/g; -
var r2 = /a+/y; -
r1.exec(s) // ["aaa"] -
r2.exec(s) // ["aaa"] -
r1.exec(s) // ["aa"] 剩余 '_aa_a' -
r2.exec(s) // null
lastIndex属性:
指定匹配的开始位置:
-
const a = /a/y; -
a.lastIndex = 2; // 从2号位置开始匹配 -
a.exec('wahaha'); // null -
a.lastIndex = 3; // 从3号位置开始匹配 -
let c = a.exec('wahaha'); -
c.index; // 3 -
a.lastIndex; // 4
返回多个匹配:
一个 y修饰符对 match方法只能返回第一个匹配,与 g修饰符搭配能返回所有匹配。
-
'a1a2a3'.match(/a\d/y); // ["a1"] -
'a1a2a3'.match(/a\d/gy); // ["a1", "a2", "a3"]
检查是否使用 y修饰符:
使用 sticky属性检查。
-
const a = /hello\d/y; -
a.sticky; // true
4.5 flags属性
flags属性返回所有正则表达式的修饰符。
-
/abc/ig.flags; // 'gi'











