ES6-10
定义
let
- 声明的变量具有全局作用域
- 不能使用全局对象的属性来访问
- 不能重复定义
- 不能进行变量声明提升
const
除了 let
的属性之外,它只能声明常量,不能被更改
Array
-
from用于转化伪数组,首先它按照索引方式传输数据,二是它有
length
属性,比如{0:'a',1:'b',length: 5}
, 可以通过Array.from({length:3})
直接创建一个长度为 3 的值为undefined
的数组, 它还能接受一个函数,每次遍历都会执行,可以创建一个每个值为 1 的数组Array.from({length:3},function(){return 1})
-
of传入参数用于创建数组
-
fill填充数组
Array(5).fill(1)
,第二个参数可以指定开始的索引,第三个参数可以指定结束的索引
let array = [1, 2, 3, 4, 5];
console.log(array.fill(8, 2, 4)); // [1, 2, 8, 8, 5]
includes
数组是否包含某个元素
flat(ES10)
可以按照可指定的深度进行扁平化, flatMap
相当于扁平化直接加上 map
操作
正则
-
y
修饰符,用于保证字符串连续匹配,有点像是^
-
u
修饰符,用于处理多个字节的,比如中文
let s = "吉";
let s2 = "\uD842\uDFB7";
console.log(/^\uD842/.test(s2)); // true
console.log(/^\uD842/u.test(s2)); // false
console.log(/吉{2}/u.test("吉吉")); // true
-
.
在原来不能匹配一些字符,比如四个字符的 utf-16 字符,行中止符(回车,换行)。此时可以使用s
修饰符,这样.
就能匹配所有字符。使用RegExp.dotAll
来判断是否开了dotAll
模式,或者使用RegExp.flags
来输出所有修饰符 -
当使用局部匹配的时候,可以给每个匹配取名,通过这个名来访问。通过
?<namd>
来定义,使用match
后通过groups
属性来访问
const t = "2019-06-07".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
console.log(t.groups.year); // '2019'
- 先行断言和后行断言,也就是根据前后字符串来进行匹配
let test = "hello world";
// 它会先匹配 hello 之后再看后面的内容是否匹配
console.log(test.match(/hello(?=\sworld)/));
// 检查前面的条件是否匹配
console.log(test.match(/(?<=hello\s)world/));
- 在之前,
exec
方法只会匹配一次
let str = `"foo" and "bar" and "bar"`;
function select(regExp, str) {
const matches = [];
while (true) {
const match = regExp.exec(str);
if (match === null) break;
matches.push(match[1]);
}
return matches;
}
console.log(select(/"([^"]*)"/g, str)); // ["foo", "bar", "bar"]
// 而 match 方法只会返回完整的匹配内容
str.match(/"([^"]*)"/g); // [""foo"", ""bar"", ""bar""]
// 使用 replace 方法也可以实现
function select(regExp, str) {
const matches = [];
str.replace(regExp, function (all, first) {
matches.push(first);
});
return matches;
}
console.log(select(/"([^"]*)"/g, str)); // ["foo", "bar", "bar"]
// ES10
// string.matchAll 可以捕获所有的匹配元素
function select(regExp, str) {
const matches = [];
for (const match of str.matchAll(regExp)) {
matches.push(match[1]);
}
return matches;
}
Reflect
反射,是在编译阶段不知道哪个类被加载,而是在运行的时候才加载
它是一个内置对象,它提供拦截 Javascript 操作的方法。这些方法与 proxy handlers
的方法相同。它不是一个函数对象,因此它是不可构造的,不能使用 new
进行构造,同时它的所有属性和方法都是静态的。现阶段这些方法存在于 Object
和 Reflect
对象上,未来只存在于 Reflect
对象上,也就是说,从 Reflect
对象上可以拿到语言内部的方法
它的意义有四个
- 从
Reflect
对象上拿到语言内部的方法 - 操作对象出现报错时返回 false
- 让操作对象都变为函数式编程
- 保持和 proxy 对象的方法——对象
Reflect
对象一共有 13 个静态方法。
Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
Proxy
中介能够很好的保证原始信息安全,第一个参数是代理对象,第二个是干什么,我们可以用它来进行一些字段的验证,比如邮箱或是电话号码,还可以进行监控用户操作,上报问题,将报错和上报结耦
// 设定对象只能读,不能写
const dog = {
name: 'xiaoming',
price: 190
}
// 使用 proxy,这里自己其实还是可以进行写操作
const d = new Proxy(o, {
get(target, key) {
return target[key]
}
set(target, key, value) {
return false
}
})
// ES5 自己都不能进行写操作,除非重新配置
for (let [key] of Object.entries(o)) {
Object.defineProperty(o, key, {
writable: false
})
}
// 我们希望每个组件有自己的 ID,能够只能读
class Component {
constructor() {
// this.id = Math.random().toString(36).slice(-8)
this.proxy = new Proxy({
id: Math.random().toString(36).slice(-8)
}, {})
}
get id() {
return this.proxy.id
}
}
使用 Proxy.revocable
方法可以用来创建一个可撤销的代理对象。该方法的返回值是一个对象,其结构为: {"proxy": proxy, "revoke": revoke}
,其中:
-
proxy
表示新生成的代理对象本身,和用一般方式
new Proxy(target, handler)
创建的代理对象没什么不同,只是它可以被撤销掉。 -
revoke
撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象。
一旦某个代理对象被撤销,它将变得几乎完全不可调用,在它身上执行任何的可代理操作都会抛出 TypeError
异常(注意,可代理操作一共有 14 种
,执行这 14 种操作以外的操作不会抛出异常)。一旦被撤销,这个代理对象便不可能被直接恢复到原来的状态,同时和它关联的目标对象以及处理器对象都有可能被垃圾回收掉。再次调用撤销方法 revoke()
则不会有任何效果,但也不会报错。
Generator
迭代器通过生成器生成
function* gen() {
let val;
val = yield [1, 2, 3]; // val 的值为 [1, 2, 3]
val = yield* [1, 2, 3]; // 会对数组进行迭代
console.log(val);
}
// 年会抽奖
function draw(first = 1, second = 3, third = 5) {
let firstPrize = ["1A", "1B", "1C", "1D", "1E"];
let secondPrize = ["2A", "2B", "2C", "2D", "2E", "2F", "2G", "2H"];
let thirdPrize = [
"3A",
"3B",
"3C",
"3D",
"3E",
"3F",
"3G",
"3H",
"3I",
"3J",
"3K",
"3L",
];
let result = [];
let random;
function getPrize(luckyNum, prizeType) {
for (let i = 0; i < luckyNum; i++) {
// 随机抽取中奖者
random = Math.floor(Math.random() * prizeType.length);
// 把中奖者放入结果中并从一等奖中把奖励去除
result = result.concat(prizeType.splice(random, 1));
}
}
// 一等奖
getPrize(first, firstPrize);
getPrize(second, secondPrize);
getPrize(third, thirdPrize);
return result;
}
// ES6 使用 generator
function* draw(first = 1, second = 3, third = 5) {
let firstPrize = ["1A", "1B", "1C", "1D", "1E"];
let secondPrize = ["2A", "2B", "2C", "2D", "2E", "2F", "2G", "2H"];
let thirdPrize = [
"3A",
"3B",
"3C",
"3D",
"3E",
"3F",
"3G",
"3H",
"3I",
"3J",
"3K",
"3L",
];
let count = 0;
let random;
while (1) {
if (count < first) {
random = Math.floor(Math.random() * firstPrize.length);
yield firstPrize[random];
count++;
firstPrize.splice(random, 1);
} else if (count < first + second) {
random = Math.floor(Math.random() * secondPrize.length);
yield secondPrize[random];
count++;
secondPrize.splice(random, 1);
} else if (count < first + second + third) {
random = Math.floor(Math.random() * thirdPrize.length);
yield thirdPrize[random];
count++;
thirdPrize.splice(random, 1);
} else {
return false;
}
}
}
let d = draw();
console.log(d.next().value);
console.log(d.next().value);
console.log(d.next().value);
// ...
// 将对象的遍历方法挂载到对象上,这样可增强维护性
let authors = {
allAuthors: {
fiction: ["Agla", "Skks", "LP"],
scienceFiction: ["Neal", "Arthru", "Ribert"],
fantasy: ["J.R.Tole", "J.M.R", "Terry P.K"],
},
};
authors[Symbol.iterator] = function () {
let allAuthors = this.allAuthors;
let keys = Reflect.ownKeys(allAuthors);
let values = [];
// 必须返回一个对象,它必须有一个 next 方法,它也必须返回一个对象
// 有 done 属性和 value 属性
return {
next() {
if (!values.length) {
if (keys.length) {
values = allAuthors[keys[0]];
keys.shift();
}
}
return {
done: !values.length,
value: values.shift(),
};
},
};
};
// 或者直接定义一个迭代器
authors[Symbol.iterator] = function* () {
let allAuthors = this.allAuthors;
let keys = Reflect.ownKeys(allAuthors);
let values = [];
while (1) {
if (!values.length) {
if (keys.length) {
values = allAuthors[keys[0]];
keys.shift();
yield values.shift();
} else {
return false;
}
} else {
yield values.shift();
}
}
};
let r = [];
for (let v of authors) {
r.push(v);
}
console.log(r);
其他
-
2 ** 3
表示次方,原来是Math.pow(2, 3)
-
padStart
字符串方法,接受两个参数,第一个为位数,第二个参数为如果位数不够而在从开头补充的字符串,相反效果的为padEnd
-
for await of
用来进行异步逻辑的遍历
function Gen(timer) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(time);
}, time);
});
}
async function test() {
for await (let item of arr) {
console.log(Date.now(), item);
}
}
test(); // 时间戳,异步结果
-
Promise
的finally
方法,用于兜底 -
JSON.stringify()
对0xD800-0xDFFF
之间的字符会因为无法编码成utf-8
导致显示错误,ES10
之后会将其以非编码的方式存在console.log(JSON.stringify('\u{D800}'))
-
string.trim()
,string.trimStart()
,string.trimLeft()
和string.trimRight()
,string.trimEnd()
用于选择去除空格 -
Object.fromEntries
可以将数组变为对象进行遍历
const arr1 = [
["foo", 1],
["bar", 2],
];
const obj = Object.fromEntries(arr);
console.log(obj.bar); // 2
-
BigInt
用于处理大于2 ^ 52
的数,只用在数字后面加n
-
动态导入,现在导入可以分配给变量
elem.addEventListener("click", async () => {
const module = await import(`./api-script/button-click.js`);
module.clickEvent();
});
Symbol.description
是一个只读属性,它返回Symbol
对象的可选描述
let mySymbol = "My Symbol";
let symObj = Symbol(mySymbol);
symObj; // Symbol(My Symbol)
symObj.description; // 'My Symbol'
- ES10 添加了
globalThis
对象,现在开始这个对象可以在任何平台访问全局作用域
// 类似于ES5 之前的 window.v = { flag: true }
globalThis.v = {
flag: true,
};
console.log(globalThis.v); // {flog: true}
Function.toString()
之前函数的toString
方法是通过原型链查找到Object.toString()
,而现在函数有自己的toString