ES新特性合集


异步函数

使用 async 关键字声明的函数称为异步函数。

asyncawait 关键字可以使用更简洁的方式写出基于 Promise 的异步行为,而无需刻意地链式调用 promise。

举例:

const fetchUser = async (id) => {
    try {
        const user = await fetchData(id);
        console.log('User:', user);
    } catch (error) {
        console.error('Error:', error);
    }
};
fetchUser(123);

async 语法

特征是在 function 名字前加 async 关键字。

1、Async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。

async function helloAsync() {
    return 'Hello, async!';
}
console.log(helloAsync()); // Promise { <state>: "pending" }

helloAsync().then(result => {
    console.log(result)
});
// Hello, async!

2、async 函数执行时遇到 await 关键字就先暂停执行,等到触发的异步操作完成,再恢复 async 函数的执行并返回解析值。

await 关键字仅在 async 函数中有效。

function testAwait() {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('testAwait');
            resolve();
        }, 1000);
    });
}

async function helloAsync() {
    await testAwait();
    console.log('helloAsync');
}

helloAsync();
// testAwait
// helloAsync

computed property name

对象的键名可以使用变量定义,在创建对象时使用 bracket notation 方括号圈起来,如 {[phoneType]: 12345}

Spread syntax (…) 扩展

对象字面量扩展属性,相当于 Object.assign() 的简写。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

const obj1 = { foo: 'bar', x: 42 };
const obj2 = { foo: 'baz', y: 13 };

const mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }

剔除空值

对象字面量扩展简单应用:利用 Object.assign() 自动剔除源对象中值为 nullundefined 的属性这一特性,实现表单提交时过滤空值

数组字面量使用已存在的数组作为新创建数组的一部分或全部(即复制)。注意:多维数组扩展时,数组项是子数组的 reference(参 Object.assign),那么新数组项改变也将影响源数组项。

const parts = ['shoulders', 'knees'];
const lyrics = ['head', ...parts, 'and', 'toes'];
//  ["head", "shoulders", "knees", "and", "toes"]

迭代器 iterator

早期使用 for 循环方式遍历数据。迭代器为各种数据结构提供统一的访问接口。

生成器 generator

列表中所有元素都存在内存中,当数据量过大时,非常耗内存。如果列表元素可以按照某种算法推算出来,就可以在循环中不断推算出后续元素。从而避免创建完整的列表,节省内存。

Proxy

Proxy 和 Reflect 是ES6为操作对象引入的API。Proxy 可以对目标对象的读取、函数调用等操作进行拦截,并根据自己的逻辑进行处理。

Proxy 不直接操作对象,而是通过对象的代理对象进行操作。Reflect 挂载了很多静态方法(类似 Math.round() 直接使用,而无需 new 操作)

Proxy 对象由两部分组成:

  • target:目标对象。
  • handler:一个对象,其属性是一组函数,声明了对target的指定行为。

举例:

let person = { name: 'Jack', age: 20 };
let handler = {
  get: function(target, key) {
    console.log(`Getting ${key}`);
    return target[key];
  },
  set: function(target, key, value) {
    console.log(`Setting ${key} = ${value}`);
    target[key] = value;
  }
};

let proxy = new Proxy(person, handler);

proxy.name;
// Getting name
// "Jack"

proxy.age = 21; 
// Setting age = 21
// 21

handler 对象方法

除了上面提到的 getset 方法,还有 applyhas 等。

其中 apply(target, cxt, args) 方法用于拦截函数的调用,并返回函数执行结果。

function sub(a, b) {
  return a - b;
}
let handler = {
  apply: function(target, cxt, args) {
    console.log('handler.apply called');
    return Reflect.apply(...arguments); // 等同于 Function.prototype.apply.call(target, cxt, args)
  }
};
let proxy = new Proxy(sub, handler);
proxy(10, 3);
// handler.apply called
// 7

has(target, key) 方法用于拦截 in 操作符,判断target对象是否存在属性key。此方法不能判断属性是对象自身的,还是继承的。

let handler = {
  has: function(target, key) {
    console.log('handler.has called');
    return key in target;
  }
};
let exam = { name: 'John' };
let proxy = new Proxy(exam, handler);
'name' in proxy;
// handler.has called
// true