【ES6】ES6特性笔记

ES6已经出现很长时间了,现在系统一下知识点,查漏补缺。

变量

let

  • let 声明的变量只在其所在的代码块中起作用。
  • 使用 let 声明变量之前。该变量是不可用的 - 暂时性死区
  • let 不允许在同一个作用域内重复声明同一个变量。
  • 在块级作用域内函数声明类似于 let,在块级作用域之外不可引用。

const

  • const 声明一个只读变量,一旦声明常量不可变。
  • const 实际上保证的是变量指向的那个内存地址不得改动,引用类内部属性还是可变的。

获取顶层对象

1
2
3
4
5
6
function getGlobal(){
if ( typeof self !== 'undefined' ) { return self; }
if ( typeof window !== 'undefined' ) { return window; }
if ( typeof global !== 'undefined' ) { return global; }
throw new Error("unable to locate global object !!! ");
}

结构赋值 - 按照一定的模式从数组或者对象中提取值,然后对变量进行赋值。

字符串

Unicode(utf-8/utf-16)字符表示方法:\u{0061} \u{20BB7}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
var buf = "𠮷a";
// codePointAt() 能够正确处理 utf-16 字符。
buf.codePointAt(0).toString(16); // 20bb7
buf.codePointAt(1).toString(16); // 61
// fromCodePoint() 通过码点获取正确 utf-16 字符。
String.fromCodePoint(0x20bb7); // 𠮷
// 字符串遍历器 for...of 有效识别 utf-16
for(let c of buf){
console.log(c); // 𠮷 、 a
}
// at() 返回给定位置的字符
'abc'.at(0); // a
// normalize() 正规化 - 针对某些语言的合成词
// includes() 是否包含
// startsWith() 是否开头
// endsWith() 是否结尾
// repeat() 重复
// padStart() 在开始补全
'x'.padStart(5, 'yz'); // yzyzx
'x'.padStart(4, 'yz'); // yzyx
// padEnd() 在结尾补全
'x'.padEnd(5, 'yz'); // xyzyz
'x'.padEnd(4, 'yz'); // xyzy
// 模板字符串
var template = `this is an template String ${buf}`;
// 模板编译函数
function compile(template){
let evalExpr = /<%=(.+?)%>/g;
let expr = /<%=([\\s\\S]+?)%>/g;
template = template
.replace(evalExpr, '`); \\n echo( $1 ); \n echo(`')
.replace(expr, '`); \n $1 \\n echo(`');
template = 'echo(`'+ template +'`);';
var script =
`(function parse(data){
let output = "";
function echo(html){
output += html;
}

${ template }

return output;
})`;
return script;
}
// 使用模板编译
let parse = eval(compile(template));
let html = parse(data);
// raw() 模板字符串处理函数 用于转义模板字符串中的内容

正则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 创建方式
new RegExp('xyz','i');
new RegExp(/xyz/i);
/xyz/i;
new RegExp(/xyz/ig,"i"); // ig 会被 i 覆盖 仅支持es6
// match()
// replace()
// search()
// split()
// u 修饰符 处理 utf-16
// y 修饰符 下一次匹配必须在开始位置
// 正则的 sticky 属性 与y修饰符相匹配
// 正则的 flags 属性 返回正则的修饰符
// s 修饰符 .号不匹配行终止符 需要加此修饰符进行匹配 dotAll模式
  • 先行断言:x只有在y前面才能匹配 /x(?=y)/
  • 先行否定断言: x只有不在y前面才能匹配 /x(?!y)/
  • 后行断言:x只有在y后边才能匹配 /(?<=y)x/
  • 后行否定断言:x只有不在y后面才能匹配 /(?<!y)x/

匹配Unicode \p{...} 或者 \P{...}

具名组匹配 ?<name>

1
2
3
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year;

数值

二进制前缀 0b
八进制前缀 0o
十六进制前缀 0x

Number 对象

1
2
3
4
5
6
7
Number.isFinite() // 检查数值是否是有限的
Number.isNaN() // 检查数值是否为 NaN
Number.parseInt() // 转换 int
Number.parseFloat() // 转换 float
Number.isInteger() // 判断是否为整数
Number.EPSILON // 极小的常量 浮点的误差范围
Number.isSafeInteger() // 整数是否在安全范围内

Math 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Math.trunc() // 去除小数部分
Math.sign() // 判断是正数 负数 还是 零 返回:1、-1、0、-0、NaN
Math.cbrt() // 计算一个数的立方根
Math.clz32() // 返回一个数的32位无符号整数形式有多少个前导0
Math.imul() // 返回两个数的乘积 保证溢出后的低位精度
Math.fround() // 返回单精度浮点数
Math.hypot() // 返回所有参数的平方和的平方根
// 对数
Math.expm1() // 返回 e^x - 1 即 Math.exp(x) - 1
Math.log1p() // 返回 ln(1 + x) 即 Math.log(1 + x) 如果x小于-1返回NaN
Math.log10() // 返回以10为底的x的对数 如果x<0则返回NaN
Math.log2() // 返回以2为底的x的对数 如果x<0则返回NaN
// 双曲函数
Math.sinh() // 双曲正弦
Math.cosh() // 双曲余弦
Math.tanh() // 双曲正切
Math.asinh() // 反双曲正选
Math.acosh() // 反双曲余弦
Math.atanh() // 反双曲正切

Math.signbit() // 符号位是否已经设置
// 指数运算符 **

// Integer数值类型需要以n结尾

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
function log(x,y='World'){
console.log(x,y);
}
function log({x = 'Hello',y = 'World'}={}){
console.log(x,y);
}
function log({x,y} = {x:'Hello',y:'World'}){
console.log(x,y);
}

// 函数的length属性,代表返回参数个数

// 参数不存在就抛出异常
function throwMissing(param){
throw new Error("Missing parameter " + param );
}
function log(x = throwMissing('x'),y='World'){
console.log(x,y);
}

// 扩展运算符 ...y 必须在末尾
// 数组与参数的逆运算
function log(x, ...y){}

// 箭头函数 =>
let sum = (x, y) => x + y ;

// 函数绑定运算符 :: 左边的对象绑定到右边的函数上,使函数中this指向左边的对象。

// 尾调用优化
function f(x){
return g(x);
}

// 蹦床函数 尾递归优化 将递归转化为循环
function tco(f){
var value;
var active = false;
var accumulated = [];

return function accumulator(){
accumulated.push(arguments)l
if(!active){
active = true;
while(accumulated.length){
value = f.apply(this, accumulated.shift());
}
active = false;
return value;
}
};
}

var sum = tco(function(x,y){
if(y>0){
return sum(x + 1,y - 1);
}else{
return x;
}
});

sum(1,100000); // 100001

// 尾逗号
function abc(a,b,c,){

}

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 扩展运算符 ...
// 合并数组
arr = [1]
arr2 = [2,3]
arr3 = [4,5]
[...arr, ...arr2, ...arr3] // [1,2,3,4,5]
[first, ...rest] = [1,2,3,4,5] // first = 1 ;rest = [2,3,4,5]
Array.from() // 转化为真正数组
Array.of() // 将一组值 转化为数组
arr.copyWithin() // 当前数组内的指定位置复制到其他位置
arr.find() // 返回符合条件的数组
arr.findIndex() // 返回符合条件的数组成员的位置
arr.fill() // 使用给定的值填充一个数组
arr.entries() // 键值对遍历用 for...of
arr.keys() // 键遍历用 for...of
arr.values() // 值遍历用 for...of
arr.includes() // 包含

// 数组空位 会明确的作为undefined处理

对象

1
2
3
4
5
6
7
8
Object.is() // 判断两个值相等
Object.assign(target, ...sources) // 将源对象的可枚举属性复制到目标对象
function clone(origin){
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto),origin);
}
Object.getOwnPropertyDescriptor(); // 属性描述
// for ... in/Object.keys/JSON.stringify/Object.assign 会忽略枚举属性为false的值

对象遍历

  1. for…in 遍历自身和继承的可枚举属性(不含Symbol属性)
  2. Object.keys(obj) 遍历自身(不含继承)的可枚举属性(不含Symbol属性)
  3. Object.getOwnPropertyNames(obj) 遍历自身的所有属性(不含Symbol属性)
  4. Object.getOwnPropertySymbols(obj) 遍历自身所有Symbol属性
  5. Reflect.ownKeys(obj) 遍历自身所有属性
1
2
3
4
5
6
7
8
9
10
11
12
// __proto__ 属性 - 内部属性,不建议使用
Object.setPrototypeOf(object, prototype) // 写操作
Object.getPrototypeOf() // 读操作
Object.keys(object) // 遍历自身(不含继承)的可枚举属性(不含Symbol属性)
Object.values(object) // 参数对象自身的(不含继承的)所有可遍历属性的键值
Object.entries(object) // 参数对象自身的(不含继承的)所有可遍历属性的键值数组
Object.getOwnPropertyDescriptor(object, 'propName') // 返回某个对象属性的描述对象
Object.getOwnPropertyDescriptors(object) // 同上

// Null传导运算符
var a = b?.c?.d?.e;
// b c d 有一个是 undefined 或者 null 都会直接返回

Symbol 独一无二的值

七种数据类型:UndefinedNullBooleanStringNumberObjectSymbol

使用方式:

1
2
3
4
5
let s = Symbol();
// 接受参数作为描述 在控制台显示区分
let s = Symbol('abc');
// 如果参数是一个对象 就会调用对象的toString方法
// 每次生成的Symbol都不相等

Symbol 作为属性名,可以用于构建枚举量或者内部方法。

1
2
Symbol.for() // 检索已经存在的量 不存在则新建
Symbol.keyFor() // 返回Symbol的key值

对象的11个内置Symbol

  1. Symbol.hasInstance
  2. Symbol.isConcatSpreadable
  3. Symbol.species
  4. Symbol.match
  5. Symbol.replace
  6. Symbol.search
  7. Symbol.split
  8. Symbol.iterator
  9. Symbol.toPrimitive
  10. Symbol.toStringTag
  11. Symbol.unscopables

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// #1
class MyClass{
[Symbol.hasInstance](p){
return p instanceof Array;
}
}
[1, 2, 3] instanceof new MyClass(); // true

// #2
let obj = {length:2, 0:'c', 1:'d'};
['a','b'].concat(obj,'e'); // a b obj e

obj[Symbol.isConcatSpreadable] = true; // 需要手动设置
['a','b'].concat(obj,'e'); // a b c d e

// #3

Set Map

  • Set - add delete has clear size
  • WeakSet - 成员只能是对象
  • Map - size set get has delete clear
  • WeakMap - 仅接受对象作为键名 没有size属性
  • WeakMap 很适合实现listener 和 部署私有属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Map转对象
function strMapToObj(strMap){
let obj = Object.create(null);
for(let [k,v] of strMap){
obj[k] = v;
}
return obj;
}
// 对象转Map
function objToStrMap(obj){
let strMap = new Map();
for(let k of Object.keys(objs)){
strMap.set(k,obj[k]);
}
return strMap;
}
// Map转JSON
function strMapToJson(strMap){
return JSON.stringify(strMapToObj(strMap));
}
function mapToArrayJson(strMap){
return JSON.stringify([...strMap]);
}
// JSON转Map
function jsonToStrMap(jsonStr){
return objToStrMap(JSON.parse(jsonStr));
}
function jsonToMap(sonStr){
return new Map(JSON.parse(jsonStr));
}

Proxy 修改某些操作的默认行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 实例方法
get()
set()
apply()
has()
construct()
deleteProperty()
defineProperty()
getOwnPropertyDescriptor()
getPrototypeOf()
isExtensible()
ownKeys()
preventExtensions()
setPrototypeOf()
Proxy.revocable()

Reflect 类似 Proxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 13个静态方法
Reflect.apply
Reflect.construct
Reflect.get
Reflect.set
Reflect.defineProperty
Reflect.deleteProperty
Reflect.has
Reflect.ownKeys
Reflect.isExtensible
Reflect.preventExtensions
Reflect.getOwnPropertyDescriptor
Reflect.getPrototypeOf
Reflect.setPrototypeOf

Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// 使用实例
var promise = new Promise(function(resolve,reject){
// ... some code

if(/*异步操作成功*/){
resolve(value);
}else{
reject(error);
}
});
promise.then(function(value){
// 成功
},function(error){
// 失败
}).catch(console.error);
// 推迟执行
function timeout(ms){
return new Promise((resolve,reject) => {
setTimeout(resolve, ms, 'done');
});
}
timeout(100).then((value) => console.log(value));
// 异步加载图片
function loadImageAsync(url){
return new Promise((res,rej)=>{
let image = new Image();
image.onload = function(){
res(image);
};
image.onerror = function(){
rej(new Error("Could not load image at " + url));
};
image.src = url ;
});
}
// Promise 实现 ajax
function getJSon(url){
return new Promise((res, rej)=>{
let client = new XMLHttpRequest();
client.open("GET",url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
function handler(){
if(this.readyState !== 4){
return ;
}
if(this.status === 200){
res(this.response);
}else{
rej(new Error(this.statusText));
}
}
});
}
// Promise.all 全部状态改变才改变
var a = Promise.all([new Promise(),new Peomise()]);
// Promise.race() 有一个改变就返回
var a = Promise.race([new Promise(),new Peomise()]);
// Promise.resolve() 将普通方法转换为Promise方法
// Promise.reject()

// done()
Promise.prototype.done = function(onFulfilled, onRejected){
this.then(onFulfilled, onRejected).catch(function(reason){
setTimeout(function(){throw reason;},0);
});
}
// finally()
Promise.prototype.finally = function(callback){
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason})
);
}
// Promise.try() catch 方法仅捕捉异步错误 所以需要try捕捉更多问题

Iterator 和 for … of

Genertor函数 异步编程解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function* gen(){
yield "hello";
yield "world";
yield "ending";
}
var g = gen();
g.next(); // { value : "hello", done: false}
g.next(); // ...

// Generator.prototype.return()

function* clock(){
while(true){
console.log("tick!");
yield;
console.log("tock!");
yield;
}
}
// 协程

// Thunk函数 自动执行Gen函数
//es5
var Thunk = function(fn){
return function(){
var args = Array.prototype.slice.call(arguments);
return function (callback){
args.push(callback);
return fn.apply(this, args);
};
};
};
//es6
const Thunk = function(fn){
return function(...args){
return function(callback){
return fn.call(this, ...args,callback);
};
};
};

// Thunkify 模块(建议生产环境用这个)
// co 模块 自动执行gen程序 ***

async 改进 gen函数

1
2
3
4
5
6
// 实例
async function funcName(){
var f1 = await readFile();
// ...
}
funName();

Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Point{
constructor(x,y){
this.x = x;
this.y = y;
this.__a = 123;
console.log('point run');
}
set prop(str){
console.log(str);
}
get prop(){
return "123";
}
toString (){
return "hello";
}
static say(){
console.log(this.__a);
}
}
Point.prop = 1;// 静态属性

class ColorPoint extends Point{
constructor(){
super(1,1);
console.log('color point run');
}
}

修饰器

Module语法

1
2
3
4
5
import {stat, exist, readFile} from 'fs';
var a = 1;
var b = 2;
export const A = 1; // 输出常量
export {a as c, b};