1. Object.is()
- ES5 :
- 相等运算符(==) :会自动转换数据类型
- 严格相等运算符(===):NaN不等于自身,+0等于-0
- ES6 :
Object.is() : 比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
Object.is({}, {})// false +0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
2. Object.assign()
2.1 基本用法
Object.assign()
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。该方法的第一个参数是目标参数,其余都是源对象。
注意 如果目标对象和源对象有一个或者多个同名属性,则后边的属性会覆盖前面的属性
如果Object.is()方法只有一个对象参数,会直接返回该参数
如果Object.is()方法的参数不是对象,先转成对象再返回
由于undefined和null无法转为对象,如果参数是他们就会报错
其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
const v1 = 'abc'; const v2 = true; const v3 = 10; const obj = Object.assign({}, v1, v2, v3); console.log(obj); // { "0": "a", "1": "b", "2": "c" }
上面代码中,v1、v2、v3分别是字符串、布尔值和数值,结果只有字符串合入目标对象(以字符数组的形式),数值和布尔值都会被忽略。这是因为只有字符串的包装对象,会产生可枚举属性。
Object.assign()拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。
Object.assign({b: 'c'}, Object.defineProperty({}, 'invisible', { enumerable: false, value: 'hello' }) ) // { b: 'c' }
上述代码中,要拷贝的对象只有不可枚举的invisible,因为不可枚举,所以没有被拷贝进去。
属性名为Symbol值得属性,也会被拷贝
Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' }) // { a: 'b', Symbol(c): 'd' }
2.2 注意点
(1)浅拷贝
Object.assign()
方法实行的是浅拷贝,而不是深拷贝。(浅拷贝仅是对对象的引用,会随之改变而改变)
(2)同名属性的替换
对于嵌套的对象,遇到同名属性时,处理方法时替换而不是添加。
const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
而不会得到{ a: { b: 'hello', d: 'e' } }
的结果。
(3)数组的处理
Object.assign()
可以处理数组,但是会把数组视为对象
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
(4)取值函数的处理
Object.assign()
只能进行值的复制,如果复制的值是一个取值函数,那么将会去之后在进行复制。
const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
2.3 常见用途
(1)为对象添加属性
(2)为对象添加方法
(3)克隆对象
function clone(origin) {
return Object.assign({}, origin);
}
将原始对象拷贝到一个空对象,就得到了原始对象的克隆。
上述方法,只能克隆原始对象自身的值,不能克隆他继承的值。保持继承链,可以采用下述方法
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
(4)合并多个对象
- 将多个对象合并到某个对象
const merge = (target, ...sources) => Object.assign(target, ...sources);
- 希望合并后返回一个新对象
const merge = (...sources) => Object.assign({}, ...sources);
(5)为属性指定默认值
3. Object.getOwnPropertyDescriptors()
ES5中的Object.getOwnPropertyDescriptor()
方法会返回某个对象属性的描述对象。
ES2017 引入了Object.getOwnPropertyDescriptors()
方法,返回指定对象所有自身属性(非继承属性)的描述对象。
const 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()
无法正确拷贝get属性和set属性的问题。
4. __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
- __proto__属性用来读取或设置当前对象的原型对象。
- Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的原型对象(prototype),返回参数对象本身。
- 该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。
5. Object.keys(),Object.values(),Object.entries()
5.1 Object.keys(),
ES5 引入了Object.keys
方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作为遍历一个对象的补充手段,供for…of循环使用。
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
5.2 Object.values(),
Object.values
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是b、c、a。
Object.values
只返回对象自身的可遍历属性。
上面代码中,const obj = Object.create({}, {p: {value: 42}}); Object.values(obj) // []
Object.create
方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的,因为p的属性描述对象的enumerable
默认是false
,Object.values
不会返回这个属性。
只要把enumerable
改成true
,Object.values
就会返回属性p的值。
const obj = Object.create({}, {p:
{
value: 42,
enumerable: true
}
});
Object.values(obj) // [42]
2.
Object.values
会过滤属性名为 Symbol
值的属性。
Object.values({ [Symbol()]: 123, foo: 'abc' }); // ['abc']
- 如果
Object.values
方法的参数是一个字符串,会返回各个字符组成的一个数组。Object.values('foo') // ['f', 'o', 'o']
5.3 Object.entries()
Object.entries()
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
- 属性名是一个 Symbol 值,该属性会被忽略
Object.entries({ [Symbol()]: 123, foo: 'abc' }); // [ [ 'foo', 'abc' ] ]
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 }
6. Object.fromEntries()
Object.fromEntries()
方法是Object.entries()
的逆操作,用于将一个键值对数组转为对象。Object.fromEntries([ ['foo', 'bar'], ['baz', 42] ]) // { foo: "bar", baz: 42 }
- 将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。
// 例一 const entries = new Map([ ['foo', 'bar'], ['baz', 42] ]); Object.fromEntries(entries) // { foo: "bar", baz: 42 } // 例二 const map = new Map().set('foo', true).set('bar', false); Object.fromEntries(map) // { foo: true, bar: false }
- 该方法的一个用处是配合
URLSearchParams
对象,将查询字符串转为对象。Object.fromEntries(new URLSearchParams('foo=bar&baz=qux')) // { foo: "bar", baz: "qux" }