多行字符串
const str1 = `How to start learning web development?
- Learn HTML \
- Learn CSS \
- Learn JavaScript \
Use freeCodeCamp to learn all the above and much, much more !`;
解构赋值
`[a,b] = [b,a]`;
const { code, data } = result;
增强的对象字面量
const x = { ["a" + "_" + "b"]: "z" };
for-of
// 使用Object.keys方法将对象的键名生成一个数组,然后遍历这个数组
for (var key of Object.keys(someObject)) {
console.log(key + ": " + someObject[key]);
}
// 使用 Generator 函数将对象重新包装一下
function* entries(obj) {
for (let key of Object.keys(obj)) {
yield [key, obj[key]];
}
}
for (let [key, value] of entries(obj)) {
console.log(key, "->", value);
}
// 原型上添加遍历器
Object.prototype[Symbol.iterator] = function () {
let _this = this;
let index = 0;
let length = Object.keys(_this).length;
return {
next: () => {
let value = _this[index];
let done = index >= length;
index++;
return { value, done };
},
};
};
for await of
异步迭代器(for-await-of):循环等待每个 Promise 对象变为 resolved 状态才进入下一步。
function TimeOut(time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(time);
}, time);
});
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)];
for (let item of arr) {
console.log(Date.now(), item.then(console.log));
}
}
test();
for of 方法不能遍历异步迭代器,得到的结果并不是我们所期待的。
ES9 中可以用 for...await...of 的语法来操作
function TimeOut(time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(time);
}, time);
});
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)];
for await (let item of arr) {
console.log(Date.now(), item);
}
}
test();
for await of 环等待每个 Promise 对象变为 resolved 状态才进入下一步。所有打印的结果为 2000,1000,3000
String
.padStart().padEnd().trimStart().trimEnd().matchAll().replaceAll()
matchAll/replaceAll 方法返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。
Array
.includes().flat().flatMap()
首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。从方法的名字上也可以看出来它包含两部分功能一个是 map,一个是 flat(深度为 1)
const numbers = [1, 2, 3];
numbers.map((x) => [x * 2]); // [[2], [4], [6]]
numbers.flatMap((x) => [x * 2]); // [2, 4, 6]
let arr = ["今天天气不错", "", "早上好"];
arr.map((s) => s.split(""));
// [["今", "天", "天", "气", "不", "错"],[""],["早", "上", "好"]]
arr.flatMap((s) => s.split(""));
// ["今", "天", "天", "气", "不", "错", "", "早", "上", "好"]
Object
Object.is(a, b)Object.assign()Object.setPrototypeOf().values().entries().fromEntries()
const person = {
name: "Tari Ibaba",
site: "codingbeautydev.com",
color: "🔵blue",
};
const arr = Object.values(person);
// ['Tari Ibaba', 'codingbeautydev.com', '🔵blue']
console.log(arr);
const person = {
name: "Tari Ibaba",
site: "codingbeautydev.com",
color: "🔵blue",
};
const arr = Object.entries(person);
/*
[
['name', 'Tari Ibaba'],
['site', 'codingbeautydev.com'],
['color', '🔵blue']
]
*/
console.log(arr);
Object.fromEntries() 把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的。
Object.fromEntries([
["foo", 1],
["bar", 2],
]);
const course = {
math: 80,
english: 85,
chinese: 90,
};
const res = Object.entries(course).filter(([key, val]) => val > 80);
console.log(res); // [ [ 'english', 85 ], [ 'chinese', 90 ] ]
console.log(Object.fromEntries(res)); // { english: 85, chinese: 90 }
.getOwnPropertyDescriptors()获取一个对象的所有自身属性的描述符。
const obj = {
name: "kane",
age: 28,
};
const desc = Object.getOwnPropertyDescriptors(obj);
console.log(desc);
// 打印结果
{
name: {
value: 'kane',
writable: true,
enumerable: true,
configurable: true
},
age: {
value: 28,
writable: true,
enumerable: true,
configurable: true
}
}
value表示当前对象的默认值writable表示对象属性是否可以修改enumerable表示当前这个属性是否可以出现在对象的枚举属性中configurable表示当前对象的属性能否用 delete 删除
这些对象的属性可以使用 Object.defineProperty() 进行修改。
const obj = {};
Object.defineProperty(obj, "name", {
value: "kane",
writable: true,
configurable: true,
enumerable: true,
});
Object.defineProperty(obj, "age", {
value: 34,
writable: true,
configurable: true,
enumerable: true,
});
console.log(obj); // { name: 'kane', age: 34 }
// 一些属性设置为false的情况
const obj = {};
Object.defineProperty(obj, "name", {
value: "kane",
writable: false,
configurable: false,
enumerable: true,
});
console.log(obj); // { name: 'kane' }
obj.name = "kany";
console.log(obj); // { name: 'kane' }
delete obj.name;
console.log(obj); // { name: 'kane' }
设置 writable: false 和 configurable: false ,为 false 时,对象的 name 对象的值不能改变和不能被删除,打印出来还是原来的对象。
async/await
缺点:让代码看起来是同步的,在某种程度上,也使得它的行为更加地同步。这意味着代码可能会因为大量 await 的 promises 相继发生而变慢。
如何缓解这个问题:通过将 Promise 对象存储在变量中来同时开始它们,然后等待它们全部执行完毕。
// 💡 immediately invoked function expression (IIFE)
(async () => {
await wait();
console.log("WHERE ARE YOU?! 😠");
})();
function wait() {
return new Promise((resolve) => setTimeout(resolve, 10 * 1000));
}
startWorkout();
// ✅ async/await
async function startWorkout() {
try {
await goToGym();
} catch (err) {
console.log(err);
}
}
function goToGym() {
return new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
reject(new Error("I'm tired today!😴"));
}
resolve("Let's go!🏃♂️");
});
}
Promise
.prototype.finally().allSettled()
Promise.all() 具有并发执行异步任务的能力。但它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise 直接进入 reject 状态。
场景:现在页面上有三个请求,分别请求不同的数据,如果一个接口服务异常,整个都是失败的,都无法渲染出数据
我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态,这就是Promise.allSettled 的作用。
.any()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成rejected 状态,包装实例就会变成 rejected 状态。
Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成 rejected 状态而结束,必须等到所有参数 Promise 变成 rejected 状态才会结束。
幂运算符 **
可选的 Catch Binding
try {
// tryCode
} catch (err) {
// catchCode
}
// 10
try {
console.log("Foobar");
} catch {
console.error("Bar");
}
Symbol.prototype.description
Symbol 的描述只被存储在内部的 Description ,没有直接对外暴露,我们只有调用 Symbol 的 toString() 时才可以读取这个属性:
const name = Symbol("es");
console.log(name.toString()); // Symbol(es)
console.log(name); // Symbol(es)
console.log(name === "Symbol(es)"); // false
console.log(name.toString() === "Symbol(es)"); // true
// 现在可以通过 description 方法获取 Symbol 的描述:
const name = Symbol("es");
console.log(name.description); // es
name.description = "es2"; // 只读属性 并不能修改描述符
console.log(name.description === "es"); // true
// 如果没有描述符 输入undefined
const s2 = Symbol();
console.log(s2.description); // undefined
空值合并运算符(Nullish coalescing Operator) ??
与逻辑或操作符(||)不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如'',0,NaN,false)时。
可选链 Optional chaining ?.
globalThis
在以前,从不同的 JavaScript 环境中获取全局对象需要不同的语句。在 Web 中,可以通过 window、self 取到全局对象,在 Node.js 中,它们都无法获取,必须使用 global。在松散模式下,可以在函数中返回 this 来获取全局对象,但是在严格模式和模块环境下,this 会返回 undefined。以前想要获取全局对象,可通过一个全局函数
const getGlobal = () => {
if (typeof self !== "undefined") {
return self;
}
if (typeof window !== "undefined") {
return window;
}
if (typeof global !== "undefined") {
return global;
}
throw new Error("无法找到全局对象");
};
const globals = getGlobal();
console.log(globals);
BigInt
新的数据类型。表示任意大的整数。数字后面增加 n 就可以使用。
const bigInt = 9007199254740993n;
console.log(bigInt);
console.log(typeof bigInt); // bigint
BigInt 不能用于 [Math] 对象中的方法;不能和任何 [Number] 实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为 BigInt 变量在转换成 [Number] 变量时可能会丢失精度。
Dynamic Import(按需 import)
import()可以在需要的时候,再加载某个模块。
button.addEventListener("click", (event) => {
import("./dialogBox.js")
.then((dialogBox) => {
dialogBox.open();
})
.catch((error) => {
/* Error handling */
});
});
// 基于用户或变量输入加载模块
const language = 'french';
const translations = await import(`./translations/${language}.js`);
// 适合使用不再支持require()的ES模块
(
async () => {
const chalk = (await import('chalk')).default;
console.log(chalk.red('hello'));
}
)()
逻辑运算符和赋值表达式(&&=,||=,??=)
x && (x = y);
// 上面的意思是,当x为真时,x=y
let a = 1;
let b = 0;
a &&= 2;
console.log(a); // 2
b &&= 2;
console.log(b); // 0
// x ||= y 等同于:x || (x = y); 逻辑或赋值(x ||= y)运算仅在 x 为false时赋值。
const a = { duration: 50, title: "" };
a.duration ||= 10;
console.log(a.duration); // 50
a.title ||= "title is empty.";
console.log(a.title); // "title is empty"
// x ??= y 等价于:x ?? (x = y); 逻辑空赋值运算符 (x ??= y) 仅在 x 是 nullish (null 或 undefined) 时对其赋值。
const a = { duration: 50 };
a.duration ??= 10;
console.log(a.duration); // 50
a.speed ??= 25;
console.log(a.speed); // 25