对象的新增方法

作者 zhufenfen 日期 2021-08-24
对象的新增方法

本篇博客记录了Object对象的新增方法。

Object.is()

ES5比较两个值是否相等,有两个运算符。==会自动转换数据类型,===的NaN不等于自身以及+0等于-0。Object.is与严格比较运算符的行为基本一致。不同之处只有两个:

  1. +0不等于-0
  2. NaN等于自身
1
2
3
4
5
6
7
8
9
10
11
12
// ES5部署Object.is
Object.defineProperty(Object, 'is', {
value: function(a, b) {
if (a === b) {
return a !== 0 || 1 / x === 1 / y // 判断是否为零以及为零时正负情况
}
return a !== a && b !== b
},
enumerable: false,
configurable: true,
writable: true
})

Object.assign()

Object.assign(target, source1, source2)将源对象的所有可枚举属性复制到目标对象(浅拷贝)。数值、布尔值、字符串会转成对应的包装对象,原始值会在包装对象的内部属性[[PrimitiveValue]]上面,只有字符串会产生可枚举的实义属性。null和undefined无法转成对象,不能用作首参数。

1
2
3
Object(true) // {[[PrimitiveValue]]: true}
Object(1) // {[[PrimitiveValue]]: 1}
Object('a') // {[[PrimitiveValue]]: 'a', 0: 'a', length: 1}
1
2
3
4
5
6
// 如果要复制的是一个取值函数,则将求值后再复制
var source = {
get foo() { return 1 }
}
var target = {}
Object.assign(target, source) // { foo: 1 }

用途

  • 为对象添加属性
    1
    2
    3
    4
    5
    class Point {
    constructor(x, y) {
    Object.assign(this, {x, y});
    }
    }
  • 为对象添加方法
    1
    2
    3
    4
    5
    6
    7
    Object.assign(SomeClass.prototype, {
    someMethod(arg1) {},
    anotherMethod() {}
    })
    // 等同于
    SomeClass.prototype.someMethod = function (arg1) {}
    SomeClass.prototype.anotherMethod = function () {}
  • 克隆对象
    1
    2
    3
    var newObj = Object.assign({}, obj)

    var newObj = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj)
  • 合并多个对象
    1
    const merge = (target, ...sources) => Object.assign(target, ...sources)
  • 为属性指定默认值
    1
    Object.assign({}, DEFAULTS, options)

Object.getOwnPropertyDescriptors()

返回指定对象所有自身属性的描述对象

1
2
3
4
5
6
7
function getOwnPropertyDescriptors(obj) {
var result = {}
for(var key of Reflect.ownKeys(obj)) {
result[key] = Object.getOwnPropertyDescriptor(obj, key)
}
return result;
}

引入目的是解决Object.assign()无法正确拷贝get和set属性的问题。

1
const shallowMerge = (target, source) => Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))

克隆对象

1
const shallowClone = (obj) => Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj))

Mixin混入模式

1
2
3
4
5
6
7
let mix = (obj) => ({
with: (...mixins) => mixins.reduce((sum, mixin) => Object.create(sum, Object.getOwnPropertyDescriptors(mixin)), obj)
})
let a = {a: 'a'}
let b = {b: 'b'}
let c = {c: 'c'}
let d = mix(a).with(b, c)

proto属性,Object.setPrototypeOf(),Object.getPrototypeOf()

只有浏览器才部署__proto__属性,所以最好不要使用

__proto__

用来读取或设置当前对象的原型对象

1
2
3
4
5
6
7
8
// ES5写法
var obj = {
method: function() {...}
}
obj.__proto__ = someOtherObj
// ES6写法
var obj = Object.create(someOtherObj)
obj.method = function() {...}

Object.setPrototypeOf() Object.getPrototypeOf()

null或undefined用作第一个参数会报错

Object.keys(),Object.values(),Object.entries()

对象自身可遍历属性的键名/键值

1
2
3
4
5
// 过滤属性名为Symbol值的属性
var obj = {a: 1, b: 2, [Symbol()]: 3}
for(var [key, value] of Object.entries(obj)) {
console.log([key, value]) // ['a', 1] ['b', 2]
}
1
2
// 转成真正的Map结构
new Map(Object.entries({a: 1})) // Map {"a" => 1}

Object.fromEntries()

1
2
3
4
5
6
7
// Object.entries的逆操作
Object.fromEntries([['a', 1], ['b', 2]]) // {a: 1, b: 2}
// map结构转成对象
var map = new Map([['a', 1], ['b', 2]]);
Object.fromEntries(map) // {a: 1, b: 2}
// 查询字符串转成对象
Object.fromEntries(new URLSearchParams('a=1&b=2')) // {a: 1, b: 2}