我是靠谱客的博主 爱笑母鸡,这篇文章主要介绍重学ES6 对象的扩展(2),现在分享给大家,希望可以做个参考。

__proto__属性、 Object.setPrototypeOf()

__proto__属性

proto 用来设置或者读取当前对象的prototype对象。

该属性没有写入ES6正文,代码最好认为这个属性是不存在的。无论从语义还是兼容性,都不要使用这个属性。而是使用Object.setPrototypeOf()(写操作),Object.getPrototypeOf()(读操作)或者Object.create()(生成操作)代替。

Object.setPrototypeOf()

Object.setPrototypeOf() 用来设置一个对象的 prototype 对象,返回参数对象本身。

复制代码
1
2
3
// 格式 Object.setPrototypeOf(object,prototype) 复制代码

例子

复制代码
1
2
3
4
5
6
7
8
9
let proto = {}; let obj = {x:10} Object.setPrototypeOf(obj,proto); proto.y = 20; proto.z = 40; obj.x //10 obj.y //20 obj.z //40 复制代码

上述代码将 proto 设置为 obj 的原型,所以,obj可以读取 proto的属性。

如果第一个参数不是对象,那么会自动转为对象。但是由于返回的还是第一个参数,所以这个操作不会产生任何作用。

复制代码
1
2
3
4
Object.setPrototypeOf(1,{}) === 1 //true Object.setPrototypeOf('foo',{}) === 'foo' //true Object.setPrototypeOf(true,{}) === true //true 复制代码

由于 undefined 和 null 无法转化为对象,所以第一个参数是 undefined 或者 null 就会报错。

Object.getPrototypeOf()

读取一个对象的 prototype 对象。

例子

复制代码
1
2
3
4
5
6
function Rectangle(){ ... } var rec = new Rectangle(); Object.getPrototypeOf(rec) === Rectangle.prototype //true 复制代码

Object.keys()、Object.values()、Object.entries()

Object.keys()

返回一个数组,成员时参数对象自身的(不含继承的)所有可遍历属性的键名。

复制代码
1
2
3
4
5
6
var obj = { foo:'bar', baz:10 } Object.keys(obj); //["foo","baz"] 复制代码

ES2017引入了与Object.keys配套的Object.values,Object.entries

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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(key); // 1,2,3 } for(let [key,value] of entries(obj)){ console.log([key,value]); // ['a':1],['b':2],['c':3] } 复制代码

Object.values()

方法返回一个数组,成员是参数自身的(不含继承的)所有可遍历属性的键值。

复制代码
1
2
3
4
5
6
var obj = { foo:'bar', baz:10 } Object.values(obj);// ["bar",10] 复制代码

返回数组的成员顺序

复制代码
1
2
3
4
5
6
7
var obj = { 100:'a', 2:'b', 7:'c' } Object.values(obj); // ["b","c","a"] 复制代码

上述代码,属性名为数值的属性,按照数字从小到大遍历。

Object.entries()

方法返回一个数组,成员是参数自身的(不含继承的)所有可遍历属性的键值对数组。

复制代码
1
2
3
4
5
6
var obj = { foo:'bar', baz:10 } Object.entries(obj); //[["foo","bar"],["baz",42]] 复制代码

如果源对象属性名是一个Symbol值,该属性被忽略。

Object.entries另外一个用处是将对象转化成真正的Map结构。

复制代码
1
2
3
4
5
6
7
var obj = { foo:'bar', baz:10 } var map = new Map(Object.entries(obj)); map //Map {foo:"bar",baz:42} 复制代码

自己实现Object.entries()

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Generator function* entries(obj){ for(let key of Object.keys(obj)){ yield [key,obj[key]]; } } //普通 function entries(obj){ let arr = []; for(let key of Object.keys(obj)){ arr.push([key,obj[key]]) } return arr } 复制代码

对象的扩展运算符

数组扩展运算符

复制代码
1
2
3
4
const [a,...b] = [1,2,3]; a // 1 b // [2,3] 复制代码

ES2017将这个运算符引入了对象。

解构赋值

对象解构赋值相当于 从一个对象取值,相当于将 所有可遍历的,但尚未被读取的属性分配到指定对象上面。所有的键和值都会被复制到新的对象上面。

复制代码
1
2
3
4
5
let {x,y,...z} = {x:1,y:2,a:3,b:4}; x //1 y //2 z // {a:3,b:4} 复制代码

上述代码,变量z是解构赋值所在的对象。它获取等号右边所有尚未读取的键,将他们的值一起复制过来。

由于解构赋值要求等号右边是一个对象,所以右边是undefined或者null就会报错。因为它们无法转为对象。

解构赋值必须是最后一个参数,否则会报错。

解构赋值是浅复制。

复制代码
1
2
3
4
5
6
7
8
9
let obj = { a: { b:1 } } let {...x} = obj; obj.a.b = 2; x.a.b //2 复制代码

上述代码,x是解构赋值所在对象,复制了 obj 的 a 属性,a属性引用了一个对象,修改这个对象会影响解构赋值对它的引用。

另外,解构赋值不会复制继承自原型对象的属性。

复制代码
1
2
3
4
5
6
7
8
9
10
11
let o1 = { a:1 } let o2 = { b:2 } o2._proto_ = o1 let {...o3} = o2 o3 //{b:2} o3.a // undefined 复制代码
复制代码
1
2
3
4
5
6
7
var o = Object.create({x:1,y:2}) o.z = 3 let {x,...{y,z}} = o x // 1 y // undefined z // 3 复制代码

x是单纯的解构赋值,所以可以读取对象o继承的属性;变量y是双重解构赋值,只能读取对象o 自身属性,只有变量z可以赋值成功!

扩展运算符

(...)用于取出参数对象的所有可遍历属性,将其复制到当前对象之中。

复制代码
1
2
3
4
5
6
7
8
9
10
11
let z = { a:3, b:4 } let n = {...z} n // {a:3,b:4} //等同于使用 let aclone = {...a} //等同 let aclone = Object.assign({},a) 复制代码

上述方法只是复制了对象实例属性,如果想完整克隆一个对象,还要复制对象原型的属性。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
// 方法1 兼容性差 const clone1 = { __proto__:Object.getPrototypeOf(obj), ...obj } //方法2 推荐 const clone2 = Object.assign( Object.create(Object.getPropertyOf(obj)), obj ) 复制代码

扩展运算符可用于合并两个对象

复制代码
1
2
3
4
let ab = {...a,...b} //等同 let ab = Object.assign({},a,b) 复制代码

修改现有对象部分属性

复制代码
1
2
3
4
5
let newVersion = { ...previousVersion, name: 'New Name' } 复制代码

如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认属性值。

复制代码
1
2
3
4
5
6
let aWidthDefaults = {x:1,y:2,...a} // equals let aWtithDefaults = Object.assign({},{x:1,y:2},a); // equals let aWtithDefaults = Object.assign({x:1,y:2},a); 复制代码

对象扩展运算符可以带有表达式

复制代码
1
2
3
4
5
const obj = { ...(x > 1 ? {a:1} : {}), b:2 } 复制代码

Object.getOwnPropertyDescriptors()

用于返回对象属性的描述对象。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var obj = {p:'a'}; Object.getOwnPropertyDescriptors(obj,'p'); //Object { // value:"a", // writable:true, // enumerable:true, // configurable:true //} Object.getOwnPropertyDescriptors(obj); //Object { // p:{ // value:"a", // writable:true, // enumerable:true, // configurable:true // } //} 复制代码

该方法的实现

复制代码
1
2
3
4
5
6
7
8
function getOwnPropertyDescriptors(obj){ const result = {} for(let key of Reflect.ownKeys(obj)){ result[key] = Object.getOwnPropertyDescriptor(obj,key) } return result } 复制代码

Object.getOwnPropertyDescriptors 另一个用处是,配合 Object.create 方法将对象属性克隆到一个新的对象,属于浅复制

复制代码
1
2
3
4
5
// Object.create 第一个参数 是 继承原型 ,第二个参数 是 对象属性描述 const clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)) 复制代码

Object.getOwnPropertyDescriptors还可以实现一个对象继承另一个对象。

以前,通常是这么写:

复制代码
1
2
3
4
5
const obj = { __proto__:prot, foo:123 } 复制代码

__prot__只需要部署浏览器,无需部署其他环境。

如果去掉__proto__,代码就这样写

复制代码
1
2
3
4
5
6
7
8
9
10
const obj = Object.create(prot); obj.foo = 123; // or const obj = Object.assign( Object.create(prot), { foo:123 } ) 复制代码

有了 Object.getOwnPropertyDescriptors 就可以这样写

复制代码
1
2
3
4
5
6
7
const obj = Object.create( prot, Object.getOwnPropertyDescriptors({ foo:123 }) ) 复制代码

Null 传导运算符

我们在读取对象内部某个属性,往往需要判断该对象是否存在。 比如要读取 message.body.user.firstname

复制代码
1
2
3
const firstname = (message && message.body && message.body.user && message.body.user.firstname) || 'default' 复制代码

这样判断实在是太麻烦了 简化写法:

复制代码
1
2
const firstname = message?.body?.user?.firstname || 'default' 复制代码

3个 ?.运算符,只要其中一个返回null或undefined,就不再继续运算,而是返回 undefined。

转载于:https://juejin.im/post/5cdac0c3e51d4547587bf6d1

最后

以上就是爱笑母鸡最近收集整理的关于重学ES6 对象的扩展(2)的全部内容,更多相关重学ES6内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(96)

评论列表共有 0 条评论

立即
投稿
返回
顶部