文章目录
- 1,Object.is()
- 2,Object.asign()
- 3,Object.getOwnPropertyDescriptors()
- 4,Object.setPrototypeOf()和getPrototypeOf()
- 5,Object.keys()、values() 和 entries()
- 6,Object.fromEntries()
- 7,Object.hasOwn()
1,Object.is()
再ES5中 比较两个值是否相等,只有两个运算符:相等运算符(
==
)和严格相等运算符(===
)
但它们都有缺点,前者会自动转换
数据类型,后者的NaN
不等于自身,以及+0
等于-0
。
先说它们两个的比较过程:
双等号==
:
(1)如果两个值类型相同,再进行三个等号(===)的比较
(2)如果两个值类型不同,也有可能相等,需根据以下规则进行类型转换在比较:
1)如果一个是null,一个是undefined,那么相等
2)如果一个是字符串,一个是数值,把字符串转换成数值之后再进行比较
三等号===
:
(1)如果类型不同,就一定不相等
(2)如果两个都是数值,并且是同一个值,那么相等;如果其中至少一个是NaN
,那么不相等。
(3)如果两个都是字符串,每个位置的字符都一样,那么相等,否则不相等。
(4)如果两个值都是true
,或是false
,那么相等
(5)如果两个值都引用同一个对象或是函数,那么相等,否则不相等
(6)如果两个值都是null
,或是undefined
,那么相等
ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is
就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
Object.is('123', '123')
// true
Object.is({}, {})
// false
Object.is([], [])
// false
Object.is()
判断两个值是否相同。如果下列任何一项成立,则两个值相同:
- 两个值都是
undefined
- 两个值都是
null
- 两个值都是
true
或者都是false
- 两个值是由相同个数的字符按照相同的顺序组成的字符串
- 两个值指向同一个对象
- 两个值都是数字并且
- 都是正零
+0
- 都是负零
-0
- 都是
NaN
- 都是除零和
NaN
外的其它同一个数字
- 都是正零
如下的案例:
console.log(111 == '111');// true 先转数子再比较是否一样// 1,判断 undefined console.log(undefined === undefined); // trueconsole.log(Object.is(undefined, undefined)); // true// 2,判断 null console.log(null === null); // trueconsole.log(Object.is(null,null)); // true// 3,判断空数组[]console.log([] === []); // falseconsole.log(Object.is([],[])); // false// 4,需要特别注意下 +0和-0console.log(+0 === -0); // true 显然是判断失误了console.log(Object.is(+0, -0)); //false// 5,判断NaNconsole.log(NaN === NaN); // false 显然也是判断失误了console.log(Object.is(NaN,NaN)); // true
可以看出,使用Object.is()方法会有更高的准确度。
2,Object.asign()
- 基本用法
Object.assign()
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
// 目标对象 也可以是一个空对象const target = { name: 'Eula' };// 源对象 可以有多个const source1 = { age: 18 };const source2 = { friend: 'Amber' };Object.assign(target, source1, source2);console.log("target:",target); //{name: 'Eula', age: 18, friend: 'Amber'}
Object.assign()
方法的第一个参数是目标对象,后面的参数都是源对象。
注意 :如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性,如下:
// 目标对象 const target = { name: 'Eula' }; // 这个会被覆盖掉// 源对象 const source1 = { age: 18 };const source2 = { name: 'Amber' };Object.assign(target, source1, source2);console.log("target:",target); //{name: 'Amber', age: 18}
Object.assign()
拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false
)。
let copyA = Object.assign({ name: "Eula" },Object.defineProperty({}, "age", {enumerable: false, // 不可枚举value: 18 // 为此属性添加值 18 }));console.log("copyA:",copyA);//{ name: "Eula" }
上面代码中,Object.assign()
要拷贝的对象只有一个不可枚举属性age
,这个属性并没有被拷贝进去。如果把enumerable
改为true
,就可以成功拷贝;
- assign()方法 注意事项:
(1)浅拷贝
Object.assign()
方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
const obj1 = {my:{ name: "Eula"} };const obj2 = Object.assign({}, obj1);// 改变源对象的属性obj1.my.name = "Amber"console.log(obj2); //{my: {name: 'Amber'}}
Object.assign()
拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。
(2)同名属性的替换
对于这种嵌套的对象,一旦遇到同名属性,Object.assign()
的处理方法是替换,而不是添加。
const target = { my: { name: "Eula", age: 18 } };const source = { my: { name: "Amber" } };let res = Object.assign(target, source);console.log(res);// {my: {name: 'Amber'}}
一些函数库提供Object.assign()
的定制版本(比如 Lodash 的_.defaultsDeep()
方法),可以得到深拷贝的合并。
3,Object.getOwnPropertyDescriptors()
该方法返回指定对象所有自身属性(非继承属性
)的描述对象;如下:
const obj1 = {name: "Eula",fun: function () {return "优菈";}};const Descriptors = Object.getOwnPropertyDescriptors(obj1)console.log("Descriptors:",Descriptors);
打印结果如下:
4,Object.setPrototypeOf()和getPrototypeOf()
- setPrototypeOf()
Object.setPrototypeOf
方法用来设置一个对象的原型对象;下面案例是给obj原型上添加一个属性 age:
let obj1 = { name: "Eula" };let obj2 = { age: 18 };// 下面是给obj1添加一个属性 nameObject.setPrototypeOf(obj1, obj2);console.log(obj1.age); //18
- getPrototypeOf()
该方法与Object.setPrototypeOf
方法配套,用于读取一个对象的原型对象,下面是读取obj1 新增的原型属性:
let obj1 = { name: "Eula" };let obj2 = { age: 18 };// 下面是给obj1添加一个属性 nameObject.setPrototypeOf(obj1, obj2);// 获取里面原型对象console.log(Object.getPrototypeOf(obj1)); // { age: 18 }
5,Object.keys()、values() 和 entries()
(1) Object.keys()
返回自身的(不含继承的)所有可遍历(enumerable)属性的键名
的数组。
const ys = { KamisatoAyaka: '神里绫华', ShenliLingren: '神里绫人' };let ysKeys = Object.keys(ys)console.log(ysKeys); // ['KamisatoAyaka', 'ShenliLingren'] 注意:只返回了对象每一项的键名
(2)Object.values()
返回自身的(不含继承的)所有可遍历(enumerable)属性的键值
的数组。
const ys = { KamisatoAyaka: '神里绫华', ShenliLingren: '神里绫人' };let ysvalues = Object.values(ys)console.log(ysvalues); // ['神里绫华', '神里绫人'] 注意:只返回了对象每一项的键值
(3)Object.entries()
返回一个对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对
的数组。
注意:entries方法
同时返回了此对象的键值对
, 并用一个数组包装。
const ys = { KamisatoAyaka: "神里绫华", ShenliLingren: "神里绫人" };let ysentries = Object.entries(ys);console.log(ysentries);// 同时返回了键值对 并用一个数组包装// ['KamisatoAyaka', '神里绫华']// ['ShenliLingren', '神里绫人']
以下是配合for of 循环使用:
1,keys()是对键名的遍历
let obj = {Amber: "安柏",Eula: "优菈",KamisatoAyaka: "神里绫华"};// for of不支持遍历普通对象,可通过与Object.keys()搭配使用遍历for (let key of Object.keys(obj)) {console.log(key); // Amber,Eula,KamisatoAyaka 拿到的都是对象的键名}console.log(Object.keys(obj)); //(3) ['Amber', 'Eula', 'KamisatoAyaka']
2,values()是对键值的遍历
let obj = {Amber: "安柏",Eula: "优菈",KamisatoAyaka: "神里绫华"};for (let key of Object.values(obj)) {console.log(key); // 安柏,优菈,神里绫华 拿到的都是对象的值}console.log(Object.values(obj)); //(3) ['安柏', '优菈', '神里绫华']
3,entries()是对键值对的遍历
let obj = {Amber: "安柏",Eula: "优菈",KamisatoAyaka: "神里绫华"};for (let key of Object.entries(obj)) {console.log(key);// ['Amber', '安柏']// ['Eula', '优菈']// ['KamisatoAyaka', '神里绫华']}console.log(Object.entries(obj));// 会以一个数组重新包装起来// [// ["Amber", "安柏"],// ["Eula", "优菈"],// ["KamisatoAyaka", "神里绫华"]// ];
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" }
7,Object.hasOwn()
Object.hasOwn()
时用来判断是否为自身的属性。
JavaScript 对象的属性分成两种:自身的属性和继承的属性。对象实例有一个
hasOwnProperty()
方法,也可以判断某个属性是否为原生属性。
Object.hasOwn()
可以接受两个参数,第一个是所要判断的对象,第二个是属性名:
const foo = Object.create({ a: 123 });
foo.b = 456;Object.hasOwn(foo, 'a') // false
Object.hasOwn(foo, 'b') // true
上面示例中,对象foo的属性a是继承属性,属性b是原生属性。Object.hasOwn()
对属性a返回false
,对属性b返回true
。
Object.hasOwn()
的一个好处是,对于不继承Object.prototype的对象不会报错,而hasOwnProperty()是会报错的。
const obj = Object.create(null);obj.hasOwnProperty('foo') // 报错
Object.hasOwn(obj, 'foo') // false
上面示例中,Object.create(null)返回的对象obj是没有原型的,不继承任何属性,这导致调用obj.hasOwnProperty()会报错,但是Object.hasOwn()就能正常处理这种情况。