es6——对象的扩展

原创 minsong 随笔 es6 186阅读 2018-05-16 10:16:33 举报

1.对象的简介表示法

ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

2.属性名表达式

javascript中定义对象属性,最常见的方式如下:

ES6中允许用表达式作为对象的属性,将表达式放在一对中括号中,如下:

表达式还可以定义方法名:

方法的 name 属性

函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。

Object.is()

用于比较两个值是否严格相等,与严格比较运算符===基本一致

与严格比较运算符===的差异主要有两点:1. +0不等于-0, 2. NaN等于自身

ES5可以通过如下方法扩展Object.is方法:

Object.assign()

Object.assign方法用于对象合并,将待合并对象的所有可枚举属性,复制到目标对象中。

如果目标对象与待合并对象有同名属性,或多个待合并对象有同名属性,则后面的属性会覆盖前面的属性。
如果只有一个参数,Object.assign会直接返回该参数。

如果该参数不是对象,则会先转成对象,然后返回。但undefined和null无法转化为对象,所有以它们为参数时,会报错。

但如果undefined或null是作为带合并数据,则不会报错,因为无法转化为对象,所有跳过。

若数值、字符串和布尔值做为待合并数据,合并至目标目标对象时,只有字符串会以数组形式,拷贝到目标对象。而数值和布尔值则会被忽略。

字符串能被拷贝,是因为字符串的包装对象,会产生可枚举属性。

上面代码中,布尔值、数值、字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性[[PrimitiveValue]]上面,这个属性是不会被Object.assign拷贝的。只有字符串的包装对象,会产生可枚举的实义属性,那些属性则会被拷贝。
Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。

上面代码中,Object.assign要拷贝的对象只有一个不可枚举属性invisible,这个属性并没有被拷贝进去。

注意点

1.浅拷贝
Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

上面代码中,源对象obj1的a属性的值是一个对象,Object.assign拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。

2.同名属性的替换
对于这种嵌套的对象,一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。

上面代码中,target对象的a属性被source对象的a属性整个替换掉了,而不会得到{ a: { b: 'hello', d: 'e' } }的结果。这通常不是开发者想要的,需要特别小心。
一些函数库提供Object.assign的定制版本(比如 Lodash 的_.defaultsDeep方法),可以得到深拷贝的合并。

3.数组的处理
Object.assign可以用来处理数组,但是会把数组视为对象。

上面代码中,Object.assign把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性4覆盖了目标数组的 0 号属性1。

4.取值函数的处理
Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。

上面代码中,source对象的foo属性是一个取值函数,Object.assign不会复制这个取值函数,只会拿到值以后,将这个值复制过去。

常见用途

1.为对象添加属性

上面方法通过Object.assign方法,将x属性和y属性添加到Point类的对象实例。

2.为对象添加方法

上面代码使用了对象属性的简洁表示法,直接将两个函数放在大括号中,再使用assign方法添加到SomeClass.prototype之中。

3.克隆对象

上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆。
不过,采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。

4.合并多个对象
将多个对象合并到某个对象。

如果希望合并后返回一个新对象,可以改写上面函数,对一个空对象合并。

5.为属性指定默认值

上面代码中,DEFAULTS对象是默认值,options对象是用户提供的参数。Object.assign方法将DEFAULTS和options合并成一个新对象,如果两者有同名属性,则option的属性值会覆盖DEFAULTS的属性值。
注意,由于存在浅拷贝的问题,DEFAULTS对象和options对象的所有属性的值,最好都是简单类型,不要指向另一个对象。否则,DEFAULTS对象的该属性很可能不起作用。

上面代码的原意是将url.port改成 8000,url.host不变。实际结果却是options.url覆盖掉DEFAULTS.url,所以url.host就不存在了。

属性的可枚举型和遍历

可枚举性

对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。

描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性。
目前,有四个操作会忽略enumerable为false的属性。
for...in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

属性的遍历

(1)for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

Object.keys(),Object.values(),Object.entries()

1.Object.keys()
ES5 引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。

ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作为遍历一个对象的补充手段,供for...of循环使用。

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

返回数组的成员顺序,

上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是b、c、a。
Object.values只返回对象自身的可遍历属性。

上面代码中,Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的,因为p的属性描述对象的enumerable默认是false,Object.values不会返回这个属性。只要把enumerable改成true,Object.values就会返回属性p的值。

如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。

上面代码中,字符串会先转成一个类似数组的对象。字符串的每个字符,就是该对象的一个属性。因此,Object.values返回每个属性的键值,就是各个字符组成的一个数组。
如果参数不是对象,Object.values会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values会返回空数组。

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

除了返回值不一样,该方法的行为与Object.values基本一致。
Object.entries的基本用途是遍历对象的属性。

Object.entries方法的另一个用处是,将对象转为真正的Map结构。

自己实现Object.entries方法,非常简单。

扩展运算符

对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

这等同于使用Object.assign方法。

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

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复