JavaScript Object 方法 
ECMAScript 6 中的 Object 类提供了一系列方便的方法,用于对对象进行操作。本文将对这些方法进行分类介绍。
属性转数组类 
属性转数组类的方法主要有三种:keys(obj)、values(obj) 以及 entries(obj)。它们都接受一个对象作为参数,然后返回一个数组。返回的数组内容为:
| 方法 | 返回值 | 
|---|---|
Object.keys(obj) | [key1, key2, ...],其中为对象内的属性名 | 
Object.values(obj) | [value1, value2, ...],其中为对象内的属性值 | 
Object.entries(obj) | [[key1, value1], [key2, value2], ...],相当为将对象拉成数组 | 
可以自己实现一个 Object.entries
function myObjectEntries(obj) {
    let arr = [];
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {//确定属性不是从原型链上得到的
            arr.push([key, obj[key]]);
        }
    }
    return arr;
}2
3
4
5
6
7
8
9
冻结对象类 
冻结对象类主要有两种 Object.freeze(obj) 和 Object.seal(obj)。freeze 不允许对对象的属性进行添加或删除,同时也不能更改属性;seal 则是只不允许对对象属性进行增删,但是可以修改现有属性。如果希望只锁定某个属性,可以使用 Object.defineProperty。
如果对属性进行修改,执行时并不会报错,只是不起作用而已。但是如果增删属性,执行时会报错。
如果对象中某个属性实际上还是一个对象(引用类型属性),那么对这个对象内部的修改是允许的(会产生效果)。如果希望完全锁住对象,应当递归调用。(有点像默认为浅拷贝,需要自己手写深拷贝)
读写属性类 
对对象内属性进行读写的操作主要有三种:Object.hasOwnProperty()、Object.defineProperty() 以及 Object.defineProperties()。
a.hasOwnProperty(str) 用于检查对象 a 是否含有名称为 str 的属性,返回布尔值。这一检查是不考虑原型链且不关心为引用类型属性中的属性。
Object.defineProperty(obj, 'a', {value: 1, writable: false}) 将为对象 obj 增加一个名为 a 的属性,其值为 1。
- 可以设置 
writable: false来禁止对这一属性进行更改。(显然,这一禁止也是没办法对为引用类型属性中的属性进行限制的) - 可以设置 
enumerable: true来使这一属性可枚举。(例如,不设置的话,for(let key in obj)或者console.log(obj)时不会出现这个属性。) - 可以设置 
configurable: false来禁止删除这一属性。(但是可以对这一属性进行修改) - 可以设置 
get和set来定义属性的读写行为。Vue 2就是这样实现响应式的。例如 
let obj = {
    a: 1,
    b: 2
}
Object.defineProperty(obj, 'c', {
    get: function() {
        return this.a + this.b;
    },
    set: function(value) {
        this.a = value;
        this.b = value;
    }
})
console.log(obj.c); // 3
obj.c = 3;
console.log(obj.c); // 62
3
4
5
6
7
8
9
10
11
12
13
14
15
16
可枚举
可枚举是对象中属性的一种特性,如果属性是可枚举的,那么它会出现在 for...in 循环中,也会出现在 Object.keys() 之类的属性转数组方法的返回值中。默认情况下,通过 Object.defineProperty() 添加的属性是不可枚举的。
可以使用 Object.defineProperties 来一次性定义多个属性。(注意,这个方法比 Object.defineProperty 少了一个参数,因为多个属性直接又封成了一个对象)
Object.defineProperties(obj, {
  a: { value: 1, writable: false },
  b: { value: 2, writable: true }
})2
3
4
原型类 
涉及原型操作的主要有三种:Object.create() 、Object.getPrototypeOf() 和 Object.setPrototypeOf()。
Object.create(proto) 返回一个新对象,这一对象的原型对象为 proto。这一方法还可以接受第二个参数 propertiesObject,用于定义新对象的属性。(类似于 Object.defineProperties 中的第二个参数)。
小技巧
Object.create(null) 可以创建一个没有原型链的对象,这样的对象不会继承任何属性。很适合作为哈希表(字典)。
Object.getPrototypeOf(obj) 返回 obj 的原型对象,而 Object.setPrototypeOf(obj, proto) 可以将它的原型对象设置为 proto。
对象基本操作类 
基本的对象操作包括创建和比较: Object.fromEntries() 、Object.assign() 和 Object.is()。
Object.fromEntries(entries) 可以将 entries 数组转换为对象。这一数组的格式和 Object.entries(obj) 的返回值的格式是一样的。
// 思考:
Object.is(obj, Object.fromEntries(Object.entries(obj))) === true // 吗?
// 答案:不等于。因为 is 是比较引用,新生成的对象和原来的对象引用肯定不相同。
// 进一步思考:obj 和 Object.fromEntries(Object.entries(obj)) 的区别?
// 1. 如果属性不可枚举的话,生成的数组中将不含有。
// 2. 符号属性会在生成的数组中丢失。
// 2. 原型链的相关信息会丢失。2
3
4
5
6
7
8
Object.assign(target, source) 可以将 source 中的属性和它的值“原封不动”(会有一些变化)地挪到 target 中,并返回这个整合后的对象。
一些变化
注意,如果这一属性是由 defineProperty 添加设置了 writeable: false 时,整合后的对象不会含有这一约束,即只读属性会清除。
但是,如果设置了 enumerable: true,整合后的对象也会含有这一约束,即相应的属性还是可枚举的。
此外,Object.assign 执行的也是浅拷贝。
Object.is(target, source) 可以比较两个对象是否相同。它只检查两个对象是否是同一个引用,也不会比较原型链。
Object.is 和 === 的差异
Object.is() 和 === 在大多数情况下行为相同,但有以下区别:
Object.is(NaN, NaN)返回true,而NaN === NaN返回false。Object.is(+0, -0)返回false,而+0 === -0返回true。
