阮一峰ES6教程读书笔记(六)对象的新增方法

1. Object.is()

在ES6之前我们总是通过相等运算符==或者严格相等运算符===去判断两个值是否相等,但是这两者都有一定的缺陷。所以JavaScript缺乏一种运算,能够在所有环境中判断两个值是不是一样的,如果是一样的就应该相等。
ES6提出了同值相等算法,用来解决这个问题,该算法与===表现较为类似,不同之处在于比较+0-0和比较NaN与其自身:

+0 === -0 // true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

在没有部署Object.is()方法的环境可以通过以下代码来部署该方法:

Object.defineProperty(Object, 'is', {
  value: function(x, y) {
    if (x === y) {
      // 针对+0 不等于 -0的情况
      return x !== 0 || 1 / x === 1 / y;
    }
    // 针对NaN的情况
    return x !== x && y !== y;
  },
  configurable: true,
  enumerable: false,
  writable: true
})

2. Object.assign()

Object.assign()主要用于对象的合并,其行为是将源对象的所有可枚举属性和方法添加到目标对象中。

const [target, source] = [{}, {name: 'bing', age: 23}]
Object.assign(target, source)

target // {name: 'bing', age: 23}

其行为与扩展运算符类似,不过扩展运算符是把所有的源对象的属性和方法都放到了一个新的对象中,但是Object.assign()是把源对象的属性和方法放到了目标对象中。

2.1 如果有同名属性

如果有同名属性,那么后面的属性会覆盖前面的属性值

let a = {name: 'bing'}
let b = {name: 'yan', age: 24}
let c = {name: 'can', age: 27}

Object.assign(a,b,c) // {name: "can", age: 27}

2.2 如果参数不是对象

严谨的来说,如果源对象参数不是对象,或者是特殊对象(正则表达式,Date对象等),那么该方法会直接跳过参数而不会报错

let a = new Date()
let b = {}

Object.assign(b, a) // {}

如果目标对象不是对象或者是特殊对象,那么会返回一个包装对象,当然undefinednull除外

Object.assign(null) // Cannot convert undefined or null to object
Object.assign(undefined) // Cannot convert undefined or null to object

// 下面的都会返回一个包装对象
Object.assign(NaN)
Object.assign(2)
Object.assign('string')

2.3 参数是数组的情况

因为数组也是一种对象,当使用该方法时,数组会被当做对象处理:

Object.assign([1, 2, 3, 6], [3, 4, 5]) // [3, 4, 5, 6]

上述代码中因为目标数组中索引从0-3的位置都被原数组给覆盖了,所以返回的数组是[3, 4, 5, 6]

2.4 对取值函数的处理

Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。

const source = {
  get foo() { return 1 }
};
const target = {};

Object.assign(target, source)
// { foo: 1 }

上面代码中,source对象的foo属性是一个取值函数,Object.assign不会复制这个取值函数,只会拿到值以后,将这个值复制过去。

3. Object.getOwnPropertyDescriptors()

ES5 的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor)。ES2017 引入了Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的描述对象。

onst obj = {
  foo: 123,
  get bar() { return 'abc' }
};

Object.getOwnPropertyDescriptors(obj)
// { foo:
//    { value: 123,
//      writable: true,
//      enumerable: true,
//      configurable: true },
//   bar:
//    { get: [Function: get bar],
//      set: undefined,
//      enumerable: true,
//      configurable: true } }

上述代码中,使用该方法后反悔了一个对象,对象中包括了源对象的所有自身的属性的属性描述对象,该方法的出现主要是为了解决Object.assign无法拷贝getset,使用Object.getOwnPropertyDescriptors()方法配合Object.defineProperties()方法,就可以实现正确拷贝。

onst source = {
  set foo(value) {
    console.log(value);
  }
};

const target2 = {};
Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptor(target2, 'foo')
// { get: undefined,
//   set: [Function: set foo],
//   enumerable: true,
//   configurable: true }

4. Object.setPrototypeOf()

ES6 推荐使用该方法设置原型对象,在某些时候我们想新生成一个对象使之继承现有对象的原型,我们可以采用以下方法:

// 方法一
const a = {name: 'bing'}
const b = a.constructor() // b继承了a的原型

// 方法二
const a = {name: 'bing'}
const b = {}
Object.setPrototypeOf(b, Object.getPrototypeOf(a))

5. Object.values()

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历enumerable属性的键值。

const a = {name: 'bing'}
a.__proto__.age = 23  // 继承属性
Object.defineProperty(a, 'gender', {value: 'male', enumerable: false}) 
// 不可枚举属性

Object.values(a) // ["bing"] 只返回自身的可枚举属性

如果该方法的参数是一个字符串,那么将会得到令人惊喜的结果:

Object.values('string') // ["s", "t", "r", "i", "n", "g"]
[...'string'] // ["s", "t", "r", "i", "n", "g"]
Array.from('string') // ["s", "t", "r", "i", "n", "g"]

上述三种方法都能把一个字符串分解为包含字符的数组

6. Object.entries()

Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
Object.entries的基本用途是遍历对象的属性。

let obj = { one: 1, two: 2 };
for (let [k, v] of Object.entries(obj)) {
  console.log(
    `${JSON.stringify(k)}: ${JSON.stringify(v)}`
  );
}
// "one": 1
// "two": 2

Object.entries方法的另一个用处是,将对象转为真正的Map结构。

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

Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。

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

该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。

参考链接

作者:阮一峰
链接:http://es6.ruanyifeng.com/#docs/destructuring

你可能感兴趣的:(阮一峰ES6教程读书笔记(六)对象的新增方法)