一、Object.is() —比较两个值是否严格相等
es5中比较两个值是否相等,使用的是== 和 ===运算符 es6中使用Object.is() ,它用来比较两个值是否严格相等,与===运算符的行为基本一致。不同之处只有两个:一是+0不等于-0,二是NaN等于自身。 检测的变量存在值类型和引用类型。
console. log ( Object. is ( 'abc' , 'abc' ) ) ;
console. log ( Object. is ( { } , { } ) ) ;
console. log ( Object. is ( + 0 , - 0 ) ) ;
console. log ( Object. is ( NaN , NaN ) ) ;
因为数组是引用类型,不会恒等。 自己实现is()方法的内部原理。
Object. defineProperty ( Object, 'is' , {
value : function ( x, y ) {
if ( x === y)
{
return true ;
}
else {
return false ;
}
}
} ) ;
console. log ( Object. is ( { } , { } ) ) ;
二、Object.assign()—对象合并
Object.assign()方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。 Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象。 有3个参数; 第一个参数是合并之后的目标 第二个参数是合并对象之一 第三个参数是合并对象之一
let h1 = { a: 1 , b: 2 } ;
let h2 = { a: 2 , c: 3 } ;
console. log ( Object. assign ( { } , h1, h2) ) ;
该方法返回值是合并之后的对象 合并规则:不同属性叠加,相同属性后面属性覆盖前面属性。 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
let h1 = { a: 1 , b: 2 } ;
let h2 = { a: 2 , c: 3 } ;
let target = { } ;
console. log ( Object. assign ( target, h1, h2) ) ;
console. log ( target) ;
等价于$.extend()。 如果只有一个参数,Object.assign()会直接返回该参数。
const obj = { a: 1 } ;
console. log ( Object. assign ( obj) ) ;
console. log ( Object. assign ( 2 ) ) ;
console. log ( typeof Object. assign ( 2 ) ) ;
由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。
console. log ( Object. assign ( undefined ) ) ;
console. log ( Object. assign ( null ) ) ;
如果非对象参数出现在源对象的位置(即非首参数),那么处理规则有所不同。首先,这些参数都会转成对象,如果无法转成对象,就会跳过。这意味着,如果undefined和null不在首参数,就不会报错。
let obj = { a: 1 } ;
console. log ( Object. assign ( obj, undefined ) ) ;
console. log ( Object. assign ( obj, null ) ) ;
其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
const a = 'abc' ;
const b = true ;
const c = 10 ;
const obj = Object. assign ( { } , a, b, c) ;
console. log ( obj) ;
只有字符串合入目标对象(以字符数组的形式),数值和布尔值都会被忽略。这是因为只有字符串的包装对象,会产生可枚举属性。 Object.assign()拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。 属性名为 Symbol 值的属性,也会被Object.assign()拷贝。
1. 浅拷贝
Object.assign()方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
const obj1 = { a: { b: 1 } } ;
const obj2 = Object. assign ( { } , obj1) ;
obj1. a. b = 2 ;
console. log ( obj2. a. b) ;
为什么obj1.a.b的值改变了,obj2.a.b的值也随之改变了? 这是因为Object.assign()方法实行的是浅拷贝,只拷贝了obj1外层的引用,而没有拷贝内层的引用。这个对象的任何变化,都会反映到目标对象上面。
const obj1 = { a: 1 } ;
const obj2 = Object. assign ( { } , obj1) ;
obj1. a = 2 ;
console. log ( obj2. a) ;
2. 同名属性的替换
对于这种嵌套的对象,一旦遇到同名属性,Object.assign()的处理方法是替换,而不是添加。
let o1 = { a: 1 , b: 2 , c: 3 } ;
let o2 = { a: 'abc' , b: 'def' } ;
console. log ( Object. assign ( o1, o2) ) ;
3. 数组的处理
let o3 = [ 1 , 2 , 3 ] ;
let o4 = [ 4 , 5 ] ;
console. log ( Object. assign ( o3, o4) ) ;
4. 取值函数的处理
Object.assign()只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。
const source = {
get foo ( ) { return 1 }
} ;
const target = { } ;
console. log ( Object. assign ( target, source) ) ;
5. Object.assign()方法的应用
(1)给对象添加属性
let work = { } ;
console. log ( Object. assign ( work, { a: 1 , b: 2 } ) ) ;
(2)给对象添加方法
使用Object.assign()给原型对象上添加方法。
Array . prototype. mySort = function ( ) {
mySort = function ( ) {
}
}
Object. assign ( Array . prototype, {
myPai : function ( ) {
}
} )
console. log ( Array . prototype) ;
(3)克隆对象
function clone ( origin ) {
return Object. assign ( { } , origin) ;
}
console. log ( clone ( { a: 1 , b: 2 , c: 3 } ) ) ;
采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。
function clone ( origin ) {
let originProto = Object. getPrototypeOf ( origin) ;
return Object. assign ( Object. create ( originProto) , origin) ;
}
console. log ( clone ( { a: 1 , b: 2 , c: 3 } ) ) ;
(4)合并多个对象
三、Object.getOwnPropertyDescriptors()—返回某个对象属性的描述对象
ES5 的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor)。ES2017 引入了Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的描述对象。 该方法的引入目的,主要是为了解决Object.assign()无法正确拷贝get属性和set属性的问题。
const obj= {
foo: 123 ,
get bar ( ) {
return 'abc'
}
} ;
console. log ( Object. getOwnPropertyDescriptors ( obj) ) ;
上面代码中,Object.getOwnPropertyDescriptors()方法返回一个对象,所有原对象的属性名都是该对象的属性名,对应的属性值就是该属性的描述对象。
自己实现getOwnPropertyDescriptors()方法
function getOwnPropertyDescriptors ( obj ) {
const result = { } ;
for ( let key of Reflect. ownKeys ( obj) ) {
result[ key] = Object. getOwnPropertyDescriptor ( obj, key) ;
}
return result;
}
console. log ( getOwnPropertyDescriptors ( {
foo: 123 , get bar ( ) {
return 'abc'
}
} ) ) ;
四、__proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
1. __proto__属性—读取或设置当前对象的原型对象
__proto__属性(前后各两个下划线),用来读取或设置当前对象的原型对象(prototype)。
const obj = {
method : function ( ) { }
} ;
obj. __proto__ = someOtherObj;
var obj = Object. create ( someOtherObj) ;
obj. method = function ( ) { } ;
__proto__调用的是Object.prototype. __proto __ 如果一个对象本身部署了__proto__属性,该属性的值就是对象的原型。
2. Object.setPrototypeOf()—设置一个对象的原型对象
Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的原型对象(prototype),返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。
let obj= { x: 10 } ;
Object. setPrototypeOf ( obj, proto) ;
proto. y= 20 ;
proto. z= 40 ;
console. log ( obj. x) ;
console. log ( obj. y) ;
console. log ( obj. z) ;
上面代码将proto对象设为obj对象的原型,所以从obj对象可以读取proto对象的属性。
let proto= { } ;
let a= 1 ;
Object. setPrototypeOf ( a, proto) ;
proto. y= 20 ;
proto. z= 40 ;
console. log ( a. x) ;
console. log ( a. y) ;
console. log ( a. z) ;
如果第一个参数不是对象,会自动转为对象。但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。
console. log ( Object. setPrototypeOf ( 1 , { } ) ) ;
console. log ( Object. setPrototypeOf ( 'abc' , { } ) ) ;
console. log ( Object. setPrototypeOf ( true , { } ) ) ;
由于undefined和null无法转为对象,所以如果第一个参数是undefined或null,就会报错。
console. log ( Object. setPrototypeOf ( undefined , { } ) ) ;
console. log ( Object. setPrototypeOf ( null , { } ) ) ;
3. Object.getPrototypeOf()—读取一个对象的原型对象
该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。
function Rect ( ) {
}
const rec= new Rect ( ) ;
console. log ( Object. getPrototypeOf ( rec) === Rect . prototype) ;
console. log ( Object. setPrototypeOf ( rec, Object . prototype) ) ;
console. log ( Object. getPrototypeOf ( rec) === Rect . prototype) ;
console. log ( Object. getPrototypeOf ( 1 ) ) ;
console. log ( typeof Object. getPrototypeOf ( 1 ) ) ;
console. log ( Object. getPrototypeOf ( 'foo' ) ) ;
console. log ( typeof Object. getPrototypeOf ( 'foo' ) ) ;
console. log ( Object. getPrototypeOf ( true ) ) ;
console. log ( typeof Object. getPrototypeOf ( true ) ) ;
console. log ( Object. getPrototypeOf ( 1 ) === Number . prototype) ;
console. log ( Object. getPrototypeOf ( 'foo' ) === String . prototype) ;
console. log ( Object. getPrototypeOf ( true ) === Boolean . prototype) ;
如果参数是undefined或null,它们无法转为对象,所以会报错。
五、Object.keys(),Object.values(),Object.entries()
Object.keys()------获取所有的key Object.values()—获取所有的值 Object.entries()—获取键值
1. Object.keys()----遍历键名
ES5 引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
console. log ( Object. keys ( { a: 1 , b: 2 , c: 3 } ) ) ;
2. Object.values()—遍历键值
Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。 Object.values会过滤属性名为 Symbol 值的属性。 如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。 如果参数不是对象,Object.values会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values会返回空数组。
console. log ( Object. values ( { a: 1 , b: 2 , c: 3 } ) ) ;
const obj= { 100 : 'a' , 2 : 'b' , 7 : 'c' } ;
console. log ( Object. values ( obj) ) ;
const obj1= Object. create ( { } , { p: { value: 42 } } ) ;
console. log ( Object. values ( obj1) ) ;
const obj2= Object. create ( { } , { p: { value: 42 , enumerable: true } } ) ;
console. log ( Object. values ( obj2) ) ;
console. log ( Object. values ( { [ Symbol ( ) ] : 123 , foo: 'abc' } ) ) ;
console. log ( Object. values ( 'foo' ) ) ;
console. log ( Object. values ( 42 ) ) ;
console. log ( Object. values ( true ) ) ;
3. Object.entries()—遍历键值对
Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。 除了返回值不一样,该方法的行为与Object.values基本一致。 Object.entries方法的另一个用处是,将对象转为真正的Map结构。
console. log ( Object. entries ( { a: 1 , b: 2 , c: 3 } ) ) ;
console. log ( Object. entries ( { [ Symbol ( ) ] : 123 , foo: 'abc' } ) ) ;
let obj= { one: 1 , two: 2 } ;
for ( let [ k, v] of Object. entries ( obj) ) {
console. log ( ` ${ JSON . stringify ( k) } : ${ JSON . stringify ( v) } ` ) ;
}
const obj1= { foo: 'bar' , baz: 42 } ;
const map= new Map ( Object. entries ( obj1) ) ;
console. log ( map) ;
自己实现Object.entries方法
function entries ( obj ) {
let arr= [ ] ;
for ( let key of Object. keys ( obj) ) {
arr. push ( [ key, obj[ key] ] ) ;
}
return arr;
}
4. for…of遍历
let obj= { a: 1 , b: 2 , c: 3 } ;
for ( let key of Object. keys ( obj) ) {
console. log ( key) ;
}
for ( let value of Object. values ( obj) ) {
console. log ( value) ;
}
for ( let [ key, value] of Object. entries ( obj) ) {
console. log ( [ key, value] ) ;
}
六、Object.fromEntries()—将一个键值对数组转为对象
Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。
console. log ( Object. fromEntries ( [
[ 'foo' , 'bar' ] ,
[ 'baz' , 42 ]
] ) ) ;
该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。
const entries= new Map ( [
[ 'foo' , 'bar' ] ,
[ 'baz' , 42 ]
] ) ;
console. log ( Object. fromEntries ( entries) ) ;
const map= new Map ( ) . set ( 'foo' , true ) . set ( 'bar' , false ) ;
console. log ( Object. fromEntries ( map) ) ;