ES6--新特性02

89 阅读7分钟

一、 object.assign和扩展运算法

Object.assign()方法接收的第一个参数作为目标对象,后面的所有参数作为源对象。然后把所有的源对象合并到目标对象中。它会修改了一个对象,因此会触发 ES6 setter。

扩展操作符(…)使用它时,数组或对象中的每一个值都会被拷贝到一个新的数组或对象中。它不复制继承的属性或类的属性,但是它会复制ES6的 symbols 属性。

二、promise.race 方法

2.1 MDN解释: Promise.race()  函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。

简单解析: race含有竞速的意思,将多个Promise放在一个数组中,数组中有一个promise最先得到结果,不管是" 完成(resolved)"还是" 失败(resolved)" , 那么这个 .race 方法就会返回这个结果。

 Promise.race([promise1, promise2]).then(success, fail)
// promise1和promise2只要有一个成功就会调用success;
// promise1和promise2只要有一个失败就会调用fail;
// 总结: 谁第一个成功或失败,就认为是race的成功或失败。

2.2 应用场景

  • 中断Promise(网络请求设置超时时间,一旦超时就就中断)
const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);
p.then(response => console.log(response));
p.catch(error => console.log(error));

如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。

三、箭头函数和普通函数区别

  • 箭头函数不会创建自己的this
  • 箭头函数没有自己的arguments
  • 箭头函数没有原型prototype
  • 箭头函数不能用作Generator函数,不能使用yeild关键字
  • 箭头函数不能作为构造函数使用

三、 Decorator

3.1 一个普通的函数,用于扩展类属性和类方法

  • 代码可读性变强了,装饰器命名相当于一个注释
  • 在不改变原有代码情况下,对原来功能进行扩展
function strong(target){
    target.AK = true
}

@strong
class soldier{
}
console.log(soldier.AK)// true

3.2 用法

Docorator 修饰对象为下面两种:

  • 类的装饰
  • 类属性的装饰

3.21 类的装饰

当对类本身进行装饰的时候,能够接受一个参数,即类本身

@testable就是一个装饰器,target就是传入的类,即MyTestableClass,实现了为类添加静态属性:

@testable
class MyTestableClass {

}

function testable(target) {
  target.isTestable = true;
}

console.log(MyTestableClass.isTestable) // true

想要传递参数,可以在装饰器外层再封装一层函数:

function testable(isTestable) {
  return function(target) {
    target.isTestable = isTestable;
  }
}

@testable(true)
class MyTestableClass {}
console.log(MyTestableClass.isTestable) // true

@testable(false)
class MyClass {}
console.log(MyClass.isTestable) // false

3.22 类属性的装饰

当对类属性进行装饰的时候,能够接受三个参数:

  • 类的原型对象
  • 需要装饰的属性名
  • 装饰属性名的描述对象
function dec(id){
    console.log('evaluated', id);
    return (target, property, descriptor) =>console.log('executed', id);
}

class Example {
    @dec(1)
    @dec(2)
    method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1

3.33 注意

装饰器不能用于修饰函数,因为函数存在变量声明情况

4. 使用场景

  • 4.1、使用react-redux的时候

原始:

class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);

通过装饰器:

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
  • 4.2、mixins
function mixins(...list) {
  return function (target) {
    Object.assign(target.prototype, ...list);
  };
}

// 使用
const Foo = {
  foo() { console.log('foo') }
};

@mixins(Foo)
class MyClass {}

let obj = new MyClass();
obj.foo() // "foo"
  • 4.3、core-decorators.js几个常见的装饰器

  • 4.31 @antobind

autobind装饰器使得方法中的this对象,绑定原始对象

import { autobind } from 'core-decorators';

class Person {
  @autobind
  getPerson() {
    return this;
  }
}

let person = new Person();
let getPerson = person.getPerson;

console.log(getPerson() === person);// true
  • 4.32 @readonly

readonly装饰器使得属性或方法不可写

import { readonly } from 'core-decorators';

class Meal {
  @readonly
  entree = 'steak';
}

var dinner = new Meal();
dinner.entree = 'salmon';
// Cannot assign to read only property 'entree' of [object Object]

五、 对象新增的方法

关于对象新增的方法,分别有以下:

  • Object.is()
  • Object.assign()
  • Object.getOwnPropertyDescriptors()
  • Object.setPrototypeOf(),Object.getPrototypeOf()
  • Object.keys(),Object.values(),Object.entries()
  • Object.fromEntries()

5.1 Object.assign()

Object.assign()方法用于对象的合并,将源对象source的所有可枚举属性,复制到目标对象target

Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象

const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
console.log(target) // {a:1, b:2, c:3}

注意:Object.assign()方法是浅拷贝,遇到同名属性会进行替换

5.2 Object.keys()

返回自身的(不含继承的)所有可遍历(enumerable)属性的键名的数组

var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]

5.3 Object.values()

返回自身的(不含继承的)所有可遍历(enumerable)属性的键对应值的数组

const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]

5.4 Object.entries()

返回一个对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对的数组

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

5.5 Object.fromEntries()

用于将一个键值对数组转为对象

Object.fromEntries([  ['foo', 'bar'],
  ['baz', 42]
])
// { foo: "bar", baz: 42 }

6. ES6中数组新增扩展

6.1 构造函数新增的方法

关于构造函数,数组新增的方法有如下:

  • Array.from()
  • Array.of()

6.11 Array.from()

两类对象转为真正的数组:类似数组的对象和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map

let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

可以接受第二个参数,用来对每个元素进行处理,将处理后的值放入返回的数组

Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]

6.2 Array.of()

用于将一组值,转换为数组

Array.of(3, 11, 8) // [3,11,8]
  • 没有参数的时候,返回一个空数组
  • 当参数只有一个的时候,实际上是指定数组的长度
  • 参数个数不少于 2 个时,Array()才会返回由参数组成的新数组
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]

6.3 实例对象新增的方法

关于数组实例对象新增的方法有如下:

  • copyWithin()
  • find()、findIndex()
  • fill()
  • entries(),keys(),values()
  • includes()
  • flat(),flatMap()

6.31 fill()

使用给定值,填充一个数组

['a', 'b', 'c'].fill(7)
// [7, 7, 7]

new Array(3).fill(7)
// [7, 7, 7]

可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置

['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

注意:如果填充的类型为对象,则是浅拷贝

6.32 entries(),keys(),values()

keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"

6.33 includes()

用于判断数组是否包含给定的值

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

方法的第二个参数表示搜索的起始位置,默认为0

参数为负数则表示倒数的位置

[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true

6.34 flat()flatMap()

数组扁平化处理,返回一个新数组,对原数据没有影响

[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]

flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1

[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

flatMap()方法对原数组的每个成员执行一个函数相当于执行Array.prototype.map(),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组

// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]

flatMap()方法还可以有第二个参数,用来绑定遍历函数里面的this

6.4 数组的空位

数组的空位:数组的某一个位置没有任何值

ES6 则是明确将空位转为undefined,包括Array.from、扩展运算符、copyWithin()fill()entries()keys()values()find()findIndex()

建议在日常书写中,避免出现空位

6.5 排序稳定性

sort()默认设置为稳定的排序算法

const arr = [
  'peach',
  'straw',
  'apple',
  'spork'
];

const stableSorting = (s1, s2) => {
  if (s1[0] < s2[0]) return -1;
  return 1;
};

arr.sort(stableSorting)
// ["apple", "peach", "straw", "spork"]