重学ES6 对象的扩展(2)

__proto__属性、 Object.setPrototypeOf()

__proto__属性

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

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

Object.setPrototypeOf()

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

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

例子

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的属性。

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

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

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

Object.getPrototypeOf()

读取一个对象的 prototype 对象。

例子

function Rectangle(){
    ...
}

var rec = new Rectangle();

Object.getPrototypeOf(rec) === Rectangle.prototype //true
复制代码

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

Object.keys()

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

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

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

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()

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

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

返回数组的成员顺序

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

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

Object.entries()

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

var obj = {
    foo:'bar',
    baz:10
}

Object.entries(obj); //[["foo","bar"],["baz",42]]
复制代码

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

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

var obj = {
    foo:'bar',
    baz:10
}

var map = new Map(Object.entries(obj));

map //Map {foo:"bar",baz:42}
复制代码

自己实现Object.entries()

// 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
}
复制代码

对象的扩展运算符

数组扩展运算符

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

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

解构赋值

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

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

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

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

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

解构赋值是浅复制。

let obj = {
    a: {
        b:1
    }
}

let {...x} = obj;

obj.a.b = 2;

x.a.b //2
复制代码

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

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

let o1 = {
    a:1
}

let o2 = {
    b:2
}

o2._proto_ = o1

let {...o3} = o2

o3 //{b:2}

o3.a // undefined
复制代码
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可以赋值成功!

扩展运算符

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

let z = {
    a:3,
    b:4
}

let n = {...z}

n // {a:3,b:4}

//等同于使用
let aclone = {...a}
//等同
let aclone = Object.assign({},a)
复制代码

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

// 方法1 兼容性差
const clone1 = {
    __proto__:Object.getPrototypeOf(obj),
    ...obj
}

//方法2  推荐
const clone2 = Object.assign(
    Object.create(Object.getPropertyOf(obj)),
    obj
)
复制代码

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

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

修改现有对象部分属性

let newVersion = {
    ...previousVersion,
    name: 'New Name'
}
复制代码

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

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);
复制代码

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

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

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

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
//    }
//}
复制代码

该方法的实现

function getOwnPropertyDescriptors(obj){
    const result = {}
    for(let key of Reflect.ownKeys(obj)){
        result[key] = Object.getOwnPropertyDescriptor(obj,key)
    }
    return result
}
复制代码

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

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

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

以前,通常是这么写:

const obj = {
    __proto__:prot,
    foo:123
}
复制代码

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

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

const obj = Object.create(prot);
obj.foo = 123;

// or

const obj = Object.assign(
    Object.create(prot),
    {
        foo:123
    }
)
复制代码

有了 Object.getOwnPropertyDescriptors 就可以这样写

const obj = Object.create(
    prot,
    Object.getOwnPropertyDescriptors({
        foo:123
    })
)
复制代码

Null 传导运算符

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

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

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

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

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

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

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值