ES8(ES2017)新特性

发布时间:2017年6月 ES8 新增了异步编程的关键特性,同时完善了字符串、对象等基础能力。

1. async/await

ES8 最重要的特性,让异步代码看起来像同步代码。

基本语法

async function fetchData() {
  let res = await fetch('/api/data');
  let data = await res.json();
  return data;
}

工作原理

  • async 函数总是返回一个 Promise
  • await 只能在 async 函数内使用
  • await 暂停函数执行,等待 Promise 结果

对比回调地狱和 Promise 链

// 回调地狱
getData(function(a) {
  getMoreData(a, function(b) {
    getEvenMoreData(b, function(c) {
      console.log(c);
    });
  });
});

// Promise 链
getData()
  .then(a => getMoreData(a))
  .then(b => getEvenMoreData(b))
  .then(c => console.log(c))
  .catch(err => console.error(err));

// async/await,最清晰
async function getAll() {
  let a = await getData();
  let b = await getMoreData(a);
  let c = await getEvenMoreData(b);
  console.log(c);
}

错误处理

// try...catch 方式
async function fetchData() {
  try {
    let res = await fetch('/api/data');
    let data = await res.json();
    return data;
  } catch (err) {
    console.error('请求失败:', err);
  }
}

// 也可以用 .catch()
fetchData().catch(err => console.error(err));

并行执行多个异步操作

// 串行执行(慢)
async function serial() {
  let a = await fetch('/api/a');
  let b = await fetch('/api/b');
  return [a, b];
}

// 并行执行(快)
async function parallel() {
  let [a, b] = await Promise.all([
    fetch('/api/a'),
    fetch('/api/b')
  ]);
  return [a, b];
}

立即执行

(async function() {
  let data = await fetchData();
  console.log(data);
})();

注意事项

  • await 只能等待 Promise,非 Promise 值会自动包装
  • 在循环中慎用 await(会导致串行执行)
  • 顶层 await 需要 ES2022(模块环境下)

2. Object.values()

返回对象自身所有可枚举属性值的数组:

let obj = { a: 1, b: 2, c: 3 };
Object.values(obj);  // [1, 2, 3]

使用场景

// 获取所有属性值
let scores = { math: 90, english: 85, science: 92 };
let values = Object.values(scores);  // [90, 85, 92]

// 计算平均值
let avg = values.reduce((a, b) => a + b) / values.length;  // 89

// 检查是否有某个值
Object.values(obj).includes('target');

注意

  • 只返回自身的可枚举属性,不包括继承的
  • 属性顺序与 for...in 一致
  • 字符串对象也能用
Object.values('hello');  // ['h', 'e', 'l', 'l', 'o']

3. Object.entries()

返回对象自身可枚举属性的键值对数组:

let obj = { a: 1, b: 2, c: 3 };
Object.entries(obj);  // [['a', 1], ['b', 2], ['c', 3]]

配合 for...of 遍历

for (let [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

将对象转为 Map

let map = new Map(Object.entries(obj));

使用场景

// 过滤对象属性
let filtered = Object.fromEntries(
  Object.entries(obj).filter(([k, v]) => v > 1)
);

// 映射对象值
let mapped = Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k, v * 2])
);

注意

  • Object.fromEntries() 是 ES10 才有的,ES8 只有 Object.entries()
  • 字符串对象也能用
Object.entries('ab');  // [['0', 'a'], ['1', 'b']]

4. String.prototype.padStart()

字符串头部补全:

'5'.padStart(2, '0');      // '05',补到2位
'5'.padStart(4, '0');      // '0005',补到4位
'abc'.padStart(5, 'xy');   // 'xyabc',从左补
'abc'.padStart(2);         // 'abc',超过长度不截断

语法

str.padStart(targetLength[, padString])

实际应用

// 日期格式化
let month = '5'.padStart(2, '0');   // '05'
let day = '9'.padStart(2, '0');     // '09'

// 序号格式化
'1'.padStart(3, '0');   // '001'
'42'.padStart(3, '0');  // '042'

// 卡号隐藏
'1234567890'.padStart(14, '*');  // '****1234567890'

5. String.prototype.padEnd()

字符串尾部补全:

'5'.padEnd(2, '0');      // '50'
'abc'.padEnd(5, '.');    // 'abc..'
'abc'.padEnd(5, 'xy');   // 'abcxy'
'abc'.padEnd(2);         // 'abc',超过长度不截断

实际应用

// 对齐输出
console.log('姓名'.padEnd(10, ' ') + '分数');
console.log('张三'.padEnd(10, ' ') + '90');
console.log('李四'.padEnd(10, ' ') + '85');

// 输出:
// 姓名       分数
// 张三       90
// 李四       85

注意

  • 如果补全字符串长度超过目标长度,会截断补全字符串
'abc'.padStart(6, '123456');  // '123abc',截断为'123'
'abc'.padEnd(6, '123456');    // 'abc123'

6. Object.getOwnPropertyDescriptors()

获取对象自身所有属性的描述符:

let obj = {
  name: '张三',
  get age() { return 18; }
};

Object.getOwnPropertyDescriptors(obj);
// {
//   name: { value: '张三', writable: true, enumerable: true, configurable: true },
//   age:  { get: [Function], set: undefined, enumerable: true, configurable: true }
// }

对比 getOwnPropertyDescriptor(单数)

// 单数:获取单个属性描述符(ES5)
Object.getOwnPropertyDescriptor(obj, 'name');

// 复数:获取所有属性描述符(ES8)
Object.getOwnPropertyDescriptors(obj);

实际用途:深拷贝 + 正确拷贝 getter/setter

// Object.assign 会丢失 getter/setter
let source = {
  get foo() { return 1; }
};
let copy = Object.assign({}, source);
// copy.foo = 1,变成普通值,不是 getter 了

// 正确的拷贝方式
let properCopy = Object.defineProperties(
  {},
  Object.getOwnPropertyDescriptors(source)
);
// properCopy.foo 是 getter,能正常工作

7. 函数参数末尾允许逗号

ES8 新增的是:函数定义的参数列表函数调用的参数列表也允许写尾随逗号。对象字面量和数组字面量更早以前就已经支持尾随逗号了。

// ES8 之前,对象和数组里就已经能写尾随逗号
let obj = {
  a: 1,
  b: 2,
};

let arr = [
  1,
  2,
];

// ES8 进一步允许函数参数列表写尾随逗号
function foo(
  a,
  b,
  c,
) {}

// 函数调用时也允许
foo(
  1,
  2,
  3,
);

好处

  • 添加新参数或重排参数时,git diff 更干净
  • 修改最后一项时不需要额外补逗号
  • 末尾逗号在语义上会被忽略,不影响执行

8. SharedArrayBuffer 和 Atomics

用于多线程编程。

SharedArrayBuffer

允许多个 Web Worker 共享同一块内存:

let sab = new SharedArrayBuffer(1024);  // 1KB 共享内存
let arr = new Int32Array(sab);
arr[0] = 42;

Atomics

提供原子操作,防止竞态条件:

let sab = new SharedArrayBuffer(4);
let arr = new Int32Array(sab);

// 在 Worker 中
Atomics.add(arr, 0, 5);    // 原子加5
Atomics.store(arr, 0, 10); // 原子写入
Atomics.load(arr, 0);      // 原子读取
Atomics.compareExchange(arr, 0, 10, 20); // 原子比较并交换
Atomics.wait(arr, 0, 10);  // 等待值变为10
Atomics.notify(arr, 0, 1); // 通知等待者

注意:由于安全原因(Spectre 漏洞),主流浏览器曾短暂禁用 SharedArrayBuffer,现在需要跨域隔离(Cross-Origin Isolation)才能使用。

总结

特性 说明 重要性
async/await 异步编程语法糖 ⭐⭐⭐⭐⭐ 最重要的特性
Object.values() 获取对象所有属性值 ⭐⭐⭐
Object.entries() 获取对象键值对数组 ⭐⭐⭐
String.padStart() 字符串头部补全 ⭐⭐⭐
String.padEnd() 字符串尾部补全 ⭐⭐⭐
Object.getOwnPropertyDescriptors() 获取所有属性描述符 ⭐⭐
函数参数末尾逗号 函数参数末尾允许逗号 ⭐⭐
SharedArrayBuffer/Atomics 共享内存和原子操作 ⭐(特殊场景)
ES6+新特性 文章被收录于专栏

包含ES6+新特性

全部评论
写的真的很啊
点赞 回复 分享
发布于 03-27 23:02 北京

相关推荐

03-20 20:24
已编辑
门头沟学院 前端工程师
时间:30分钟1. 自我介绍​2. HTML语义化标签及好处​3. HTML块级元素与行内元素区别​4. CSS元素隐藏方法​5. display:none、visibility:hidden、opacity:0区别​6. 触发重绘/重排的样式​7. 浏览器渲染流程​8. JS基础数据类型​9. 判断属性类型的方法​10. ES6新特性​11. Set与Map区别​12. new Set/new Map存储结构​13. ==与===区别​14. 数组去重方法​15. 对象实现数组去重思路​16. JS事件循环机制​17. Promise所属任务类型​18. Vue nextTick任务类型​19. URL输入到页面展示全过程​20. TCP三次握手交互过程​21. TCP四次挥手交互过程​22. 断开连接需四次挥手的原因​23. GET与POST请求区别​24. 前端浏览器本地缓存​25. LocalStorage、SessionStorage、Cookie作用​26. 登录校验优先使用Cookie的原因​27. Vue生命周期及各阶段作用​28. 发送网络请求的生命周期​29. Vue3中created的集成位置​30. Vue组件通信方式​31. Pinia与Vuex不同点​32. v-if与v-show本质区别​33. v-if、v-show是否触发重排​34. v-for必须加key的原因​35. v-for key绑定index的问题​36. Vue计算属性与watch区别37.项目细节38.反问:不知道是我回答的太公式还是因为眼神乱飘,面试官让我不要用ai回答
发面经攒人品
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
03-30 09:21
中车电车 技术管培 8Kx13+2Kx12=12.8W 硕士双一流
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
正在热议
更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务