写在前面
对象与数组的解构
数组的解构
const [a, b, c] = [1, 2, 3] // a 1 b 2 c3
const [a,,c] = [1,2,3] // a 1 c 3
对象的解构
const person = { name: 'huangyanting', age: 3 }
const { name, age } = person
// name huangyanting age 3
像此处的 name 这个变量,嵌套了足足四层,此时如果我们仍然尝试老方法来提取它:
显然是不奏效的,因为 school 这个对象本身是没有 name 这个属性的,name 位于 school 对象的“儿子的儿子”对象里面。要想把 name 提取出来,一种比较笨的方法是逐层解构:
const school = {
classes: {
stu: {
name: 'Bob',
age: 24,
}
}
}
const { classes } = school
const { stu } = classes
const { name } = stu name // 'Bob'
但是还有一种更标准的做法,我们可以用一行代码来解决这个问题:
const { classes: { stu: { name } }} = school
name // 'Bob'
对象扩展运算
对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。举个例子:
const me = {
name: 'tingGe',
age: 3
}
const meCopy = { ...me }
meCopy // {name: "tingGe", age: 3}
这里的 …me 其实就等价于下面这种写法:
Object.assign({}, me)
数组扩展运算
在数组中,扩展运算可以将一个数组转为用逗号分隔的参数序列。举个例子:
console.log(...['haha', 'hehe', 'xixi'])
// haha hehe xixi
function mutiple(x, y) {
return x*y
}
const arr = [2, 3]
mutiple(...arr) // 6
合并两个数组
const arr1 = [1, 2, 3, 4]
const arr2 = [5, 6, 7, 8]
如何把两个数组合并到一个数组里去。这套题可能有很多种解题姿势,但是最好看的一种姿势莫过于用我们的扩展符:
const newArr = [...arr1, ...arr2]
rest 参数 相对更为熟悉的一些扩展符的操作。但是扩展符还有它的另一面,当它被用在函数形参上时,它还可以把一个分离的参数序列整合成一个数组:
function mutiple(...args) {
let result = 1;
for (var val of args) {
result *= val;
}
return result;
}
mutiple(1, 2, 3, 4) // 24
function mutiple(...args) {
console.log(args)
}
mutiple(1, 2, 3, 4) // [1, 2, 3, 4]
类数组的转换
类数组对象,ECMA-262对它的定义是:
1.它必须是一个对象 2.它有 length 属性
按照这个标准,只要有 length 属性的对象就是类数组对象:
const book = {
name: 'how to read a book',
age: 10,
length: 300
} // 这是一个类数组对象
类数组对象是指拥有一个 length 属性和若干索引属性的对象
const book = {
0: 'how to read a book',
1: 10,
length: 2
}
其实通常,类似数组的对象也有一些具有整数索引名的属性,不过这并非定义的要求。因此上面两个 book,都可以认为是类数组的对象。
需要注意的是类数组的转换
如何把类数组对象转换为真正的数组?
const arrayLike = {
0: 'Bob',
1: 'Lucy',
2: 'Daisy',
length: 3
}
ES5中Array原型上的slice方法—— 这个方法如果不传参数的话会返回原数组的一个拷贝,因此可以用此方法转换类数组到数组。
const arr = Array.prototype.slice.call(arrayLike);
Array.from方法——这是 ES6 新增的一个数组方法,专门用来把类数组转为数组:
const arr = Array.from(arrayLike);
扩展运算符——"…"也可以把类数组对象转换为数组,前提是这个类数组对象上部署了遍历器接口。在这个例子中,arrayLike 没有部署遍历器接口,所以这条路走不通。但一些对象,比如函数内部的 arguments 变量(它也是类数组对象),就满足条件,可以用这种方法来转换:
function demo() {
console.log('转换后的 arguments 对象:',[...arguments])
}
demo(1, 2, 3, 4)
// 转换后的 arguments 对象:[1, 2, 3, 4]
模板语法与字符串处理
let name = 'tingGE'
let career = 'coder'
let hobby = ['coding', 'writing']
let finalString = `
my name is ${name},
I work as a ${career} I love ${hobby[0]}
and ${hobby[1]}`
console.log(finalString);
// my name is tingGE, I work as a coder,
// I love coding and writing
在模板字符串中,空格、缩进、换行都会被保留 模板字符串完全支持“运算”式的表达式,你可以在${}里完成一些计算
更强的方法
除了模板语法外, ES6中还新增了一系列的字符串方法用于提升我们的开发效率,提取其中常用的部分,如下:
存在性判定:在过去,当我们想判断一个字符/字符串是否在某字符串中时,只能用 indexOf > -1 来做。现在 ES6 提供了三个方法:includes、startsWith、endsWith,它们都会返回一个布尔值来告诉你是否存在。
- includes:判断字符串与子串的包含关系:
const son = 'haha'
const father = 'xixi haha hehe'
father.includes(son) // true
- startsWith:判断字符串是否以某个/某串字符开头:
const father = 'xixi haha hehe'
father.startsWith('haha') // false
father.startsWith('xixi') // true
自动重复: 我们可以使用 repeat 方法 来使同一个字符串输出多次(被连续复制多次)
const sourceCode = 'repeat for 3 times;'
const repeated = sourceCode.repeat(3)
console.log(repeated)
// repeat for 3 times; repeat for 3 times; repeat for 3 times;
合并空运算符 ??
假设变量不存在,希望给一个默认值,一般会使用||运算符。但是在javascript中空字符串,0,false都会执行||运算符,ECMAScript2020引入合并空运算符解决该问题,只允许在值为null或undefined时使用默认值。
const name = '';
console.log(name || 'zz'); // zz;
console.log(name ?? 'zz'); // '';
可选链运算符 ?.
业务代码中经常会遇到这样的情况,a对象有个属性b,b也是一个对象有个属性c。
const a = {
b: {
c: 123,
}
}
访问c,经常会写成a.b.c,但是如果b不存在时,就会出错。
ECMAScript2020定义可选链运算符解决该问题,在.之前添加一个?将键名变成可选。
let person = {};
console.log(person?.profile?.age ?? 18); // 18
动态导入import
import('./a.js')返回一个Promise对象。
const a = 123;
export { a };
import('./a.js').then(data => {
console.log(data.a); // 123;
});
String.prototype.replaceAll()
为了方便字符串的全局替换,ES2021将支持String.prototype.replaceAll()方法,可以不用写正则表达式就可以完成字符串的全局替换。
'abc555'.replaceAll('5', '2'); // abc222
Promise.allSettled
当处理多个Promise时,特别是当它们相互依赖时,记录每个Promise所发生的事情来调试错误是很有必要的。
通过Promise.allSettled可以创建一个新的Promise,它只在所有传递给它的Promise都完成时返回一个数组,其中包含每个Promise的数据。
const p1 = new Promise((res, rej) => setTimeout(res, 1000));
const p2 = new Promise((res, rej) => setTimeout(rej, 1000));
Promise.allSettled([p1, p2]).then(data => console.log(data));
[ Object { status: "fulfilled", value: undefined},
Object { status: "rejected", reason: undefined} ]
Promise.all是当多个promise全部成功,或出现第一个失败就会结束。Promise.allSettled是所有都执行完成,无论成功失败。
Promise.any
只要有一个promise是fulfilled时,则返回一个resolved promise;所有的promise都是rejected时,则返回一个rejected promise
Promise.any([ Promise.reject(1), Promise.resolve(2) ])
.then(result => console.log('result:', result))
.catch(error => console.error('error:', error)); // result: 2
for of 支持异步迭代
在此之前想要实现异步迭代想要在for of外层嵌套一个async函数
async function () {
for (const fn of actions) {
await fn();
}
}
ES2018提供了一种新的书写方式。
async function() {
for await (const fn of actions) {
fn();
}
}