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来输出所有修饰符 -
当使用局部匹配的时候,可以给每个匹配取名,通过这个名来访问。通过
?<named>来定义,使用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