跳到主要内容

ES8 (ES2017)

· 阅读需 7 分钟

ES2017(ES8)引入了一些关键特性,尤其是 async/await,极大简化了异步编程的难度。除此之外,新增的对象和字符串方法也为开发者提供了更强大的工具来操作数据。这些改进使 JS 代码更简洁、高效和易于维护。

  1. Async Functions
  2. Object.entries
  3. Object.values
  4. String.prototype.padStart
  5. String.prototype.padEnd
  6. Object.getOwnPropertyDescriptors
  7. Trailing Commas

1. Async Functions

async 函数使得异步操作变得更加简洁,await 可以暂停 async 函数的执行,等待一个 Promise 被解决,并返回结果。这大大简化了基于 Promise 的异步代码,使代码的可读性更好,结构上更像同步代码。

对比示例:找到韩梅梅的班主任,有三张表

  1. 学生表:通过学生表找到学生所在班级 id
  2. 班级表:通过班级表找到该班级的班主任 id
  3. 教师表:通过班主任 id 查询到班主任名称

Promise:

fetch("./stu.json")
.then((response) => response.json())
.then((data) => {
// 找出韩梅梅所在的班级id
let classId = null;
for (let student of data.student) {
if (student.name === "韩梅梅") {
classId = student.classId;
break;
}
}
// 返回班级ID
return classId;
})
.then((classId) => {
// 根据班级ID获取班级信息
return fetch("./classes.json")
.then((response) => response.json())
.then((data) => {
let teacherId = null;
for (let cls of data.classes) {
if (cls.id === classId) {
teacherId = cls.teacherId;
break;
}
}
// 返回老师ID
return teacherId;
});
})
.then((teacherId) => {
// 根据老师ID获取老师信息
return fetch("./teacher.json")
.then((response) => response.json())
.then((data) => {
for (let teacher of data.teachers) {
if (teacher.id === teacherId) {
console.log(`韩梅梅的班主任为${teacher.name}`);
break;
}
}
});
})
.catch((error) => {
console.error("发生错误:", error);
});

async:

// 使用 fetch 获取韩梅梅的班级 ID
function getClassId() {
return fetch("./stu.json")
.then((response) => response.json())
.then((data) => {
// 找出韩梅梅所在的班级id
for (let i of data.student) {
if (i.name === "韩梅梅") {
return i.classId; // resolve with classId
}
}
});
}

// 使用 fetch 获取班级对应的老师 ID
function getTeacherId(classId) {
return fetch("./classes.json")
.then((response) => response.json())
.then((data) => {
for (let i of data.classes) {
if (i.id === classId) {
return i.teacherId; // resolve with teacherId
}
}
});
}

// 使用 fetch 获取老师名字
function getTeacherName(teacherId) {
return fetch("./teacher.json")
.then((response) => response.json())
.then((data) => {
for (let i of data.teachers) {
if (i.id === teacherId) {
return i.name; // resolve with teacherName
}
}
});
}

async function getInfo(){
try{
let classId = await getClassId();
let teacherId = await getTeacherId(classId);
let teacherName = await getTeacherName(teacherId);
}catch(e){
console.log(e);
}
}

2. Object.entries

Object.entries( ) 返回一个给定对象自身可枚举属性的键值对数组,其顺序与 for...in 循环一致(区别是 for...in 枚举原型链上的属性)。

const obj = {
name: "张三",
age: 18,
};

console.log(Object.entries(obj)); // [['name', '张三'], ['age', 18]]

当你需要遍历对象的键值对时非常有用。

和 for... in 的区别如下:

  1. 是否遍历原型链上的属性:
    • for...in 会遍历对象自身的可枚举属性以及其原型链上的可枚举属性。
    • Object.entries( ) 只返回对象自身的可枚举属性,不会遍历原型链上的属性。
  2. 返回的结果:
    • for...in 只遍历对象的键(属性名)。
    • Object.entries( ) 返回的是键值对数组,每个元素是一个数组,包含键和值。
function Person() {
this.name = "张三";
this.age = 18;
}
Person.prototype.test = "test";
Person.prototype.say = function () {
console.log("Hello");
};

const p = new Person();

for (const key in p) {
console.log(key);
}

console.log(Object.entries(p));

3. Object.values

Object.values( ) 返回一个给定对象自身可枚举属性值的数组,同样,Object.values( ) 只返回对象自身的可枚举属性值,不会遍历原型链上的属性

const obj = {
name: "张三",
age: 18,
};

console.log(Object.values(obj)); // [ '张三', 18 ]
console.log(Object.keys(obj)); // [ 'name', 'age' ]
console.log(Object.entries(obj)); // [ [ 'name', '张三' ], [ 'age', 18 ] ]

4. String.prototype.padStart

padStart( ) 方法用于在当前字符串的开头填充指定的字符,直到字符串达到指定的长度。不指定填充字符会自动用空格补齐。

console.log("5".padStart(3, "0"));
console.log("123".padStart(10, "*"));
console.log("123".padStart(10));

应用场景:格式化数字、字符串,例如为日期、时间或编号填充前导零。

5. String.prototype.padEnd

padEnd( ) 方法用于在当前字符串的末尾填充指定的字符,直到字符串达到指定的长度。不指定填充字符会自动用空格补齐。

console.log("5".padEnd(3, "0"));
console.log("123".padEnd(10, "*"));
console.log("123".padEnd(10), "test");

应用场景:用于创建固定宽度的输出,在报告生成或格式化输出时有用。

// 商品数据
const products = [
{ name: "Apple", price: 1.5, stock: 120 },
{ name: "Banana", price: 0.8, stock: 60 },
{ name: "Watermelon", price: 5.0, stock: 10 },
{ name: "Grapes", price: 2.7, stock: 30 },
];

// 打印表头
console.log("Product".padEnd(15) + "Price".padEnd(10) + "Stock".padEnd(10));

// 打印表格内容
products.forEach((product) => {
console.log(
product.name.padEnd(15) +
product.price.toString().padEnd(10) +
product.stock.toString().padEnd(10)
);
});

6. Object.getOwnPropertyDescriptors

Object.getOwnPropertyDescriptors( ) 方法返回一个对象的所有自身属性的描述符。

const obj = {
name: "张三",
age: 18,
// 访问器属性
get getAge() {
return this.age;
},
};

const describs = Object.getOwnPropertyDescriptors(obj);
console.log(describs);

/*
输出:
{
name: { value: '张三', writable: true, enumerable: true, configurable: true },
age: { value: 18, writable: true, enumerable: true, configurable: true },
getAge: {
get: [Function: get getAge],
set: undefined,
enumerable: true,
configurable: true
}
}
*/

应用场景:在进行对象的浅拷贝或深拷贝时,保留属性的可配置性、可枚举性和可写性信息。

7. Trailing Commas

允许在函数参数列表和调用中的最后一个参数后面添加逗号。虽然这只是一个小的语法改进,但它提高了代码的一致性和可读性,特别是在使用多行参数时,未来更改时不容易出错。

function foo(param1, param2, ) {
// 这里的最后一个参数后允许有逗号
}

foo("a", "b", );

-EOF-