9.1 属性(包括方法)的简洁表示法
9.2.1 基本语法
1 | var birth = '2000/01/01'; |
9.2.2 应用
- 函数中返回对象
1 | function getPoint() { |
- CommonJS模块输出变量
1 | var ms = {}; |
- 属性的赋值器(setter)和取值器(getter)
1 | var cart = { |
- Generator函数(前面需要加上
*
)
1 | var obj = { |
9.2 属性名表达式
说明:定义对象字面量时,属性名(包括方法名)也可以使用[表达式]
这种形式,即属性名表达式
注意:属性名表达式
和简洁表示法
,不能同时使用,会报错
9.2.1 案例
属性名(非方法)
1 | var lastWord = 'last word'; |
方法名
1 | let obj = { |
9.2.2 属性名表达式与简洁表示法
1 | // 报错 |
9.3 方法的name属性
分类 | name属性值 |
---|---|
普通函数 | 函数名 |
普通对象方法 | 方法名 |
get 方法 | get 方法名 |
set 方法 | set 方法名 |
bind 返回的方法 | bound 函数名 |
Function 构造函数创建的函数 | anonymous |
Symbol 值 | Synbol 值的描述 |
1 | /* 1. 普通对象方法和 get 方法 */ |
9.4 Object.is()
背景:JavaScript缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等
==
:会自动转换数据类型===
:NaN不等于自身,以及+0等于-0用途:用来比较两个值是否严格相等
1 | Object.is('foo', 'foo') |
9.4.1 Object.is()
vs. ===
不同点 | Object.is() | === |
---|---|---|
NaN 和NaN 比较 |
相等 | 不相等 |
+0 和-0 比较 |
不相等 | 相等 |
1 | +0 === -0 //true |
9.4.2 polyfill
1 | Object.defineProperty(Object, 'is', { |
9.5 Object.assign()
用途:对象的合并
说明:将源对象(source)的所有可枚举属性
,复制到目标对象(target)
参数(+):第一个参数是目标对象
,后面的参数都是源对象
限制:Object.assign
拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false
)
注意:属性名为Symbol
值的属性,也会被Object.assign
拷贝
9.5.1 第一个参数(目标对象)
情形 | Object.assign() 行为 |
---|---|
只有第一个参数 | 直接返回该参数 |
不是对象且能转成对象 | 会先转成对象 |
undefined 和null |
无法转成对象,会报错 |
9.5.2 其他参数(源对象)
情形 | Object.assign() 行为 |
---|---|
非对象且可以转成对象 | 转成对象 |
非对象且无法转成对象 | 会跳过(不参与合并) |
1 | var v1 = 'abc'; |
非对象如何转为对象?
基本类型 | 转换后 | 是否有可枚举的实例属性 |
---|---|---|
布尔 | Boolean |
否 |
数字 | Number |
否 |
字符串 | Array |
是 |
1 | // 包装对象的内部属性[[PrimitiveValue]]上面,这个属性是不会被Object.assign拷贝的 |
限制
1 | Object.assign({b: 'c'}, |
Symbol 值
1 | Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' }) |
9.5.3 注意点
浅拷贝
object.assign()
实行的是浅拷贝
。如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用
1 | var obj1 = {a: {b: 1}}; |
替换同名属性
合并时一旦遇到同名属性,Object.assign
的处理方法是替换,而不是添加
1 | var target = { a: { b: 'c', d: 'e' } } |
合并数组
Object.assign
可以用来处理数组,但是会把数组视为对象
1 | // 把数组视为属性名为0、1、2的对象 |
9.5.4 常见用途
(1)为对象添加属性
1 |
|
(2)为对象添加方法
1 | Object.assign(SomeClass.prototype, { |
(3) 克隆对象
说明:将原始对象拷贝到一个空对象{}
,就得到了原始对象的克隆
注意:采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它通过prototype
继承的值
1 | // 只克隆自身,不克隆原型链 |
(4) 合并多个对象
1 | /** |
(5) 为属性指定默认值
说明:Object.assign
方法将DEFAULTS
和options
合并成一个新对象,如果两者有同名属性,则option
的属性值会覆盖DEFAULTS
的属性值
1 | // 默认值 |
9.6 属性的可枚举性
9.6.1 Object.getOwnPropertyDescriptor()
描述对象:对象的每个属性都有一个描述对象,用来控制该属性的行为
说明:获取该属性的描述对象
1 | let obj = { foo: 123 }; |
9.6.2 可枚举性
enumerable
:如果该属性为false
,就表示某些操作会忽略当前属性
注意:ES6规定,所有Class
的原型的方法都是不可枚举的
技巧:操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,尽量不要用for...in
循环,而用Object.keys()
代替
会被enumerable 影响的操作 |
说明 |
---|---|
for...in |
只遍历对象自身的和继承的可枚举的属性 |
Object.keys() |
返回对象自身的所有可枚举的属性的键名 |
JSON.stringify() |
只串行化对象自身的可枚举的属性 |
Object.assign() |
会忽略enumerable 为false 的属性,只拷贝对象自身的可枚举的属性 |
Object.create(proto[, propertiesObject])
用途: 以 第一个参数为 prototype 创建一个新的对象,其中第二个参数中可以为新对象添加些初始化的属性。
注意:第二个参数默认是不可遍历的,除非在描述对象中显示声明属性可枚举。
9.7 属性的遍历
说明:一共 5 种方式
遍历顺序:这5种方法遍历对象的属性,都遵守同样的属性遍历的次序规则
- 首先遍历所有属性名为数值的属性,按照数字排序
- 其次遍历所有属性名为字符串的属性,按照生成时间排序
- 最后遍历所有属性名为Symbol值的属性,按照生成时间排序
方式 | 说明 | 备注 |
---|---|---|
for...in |
循环遍历对象自身的和继承的可枚举属性 | 不含Symbol 属性 |
Object.keys(obj) |
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol 属性) |
|
Object.getOwnPropertyNames(obj) |
返回一个数组,包含对象自身的所有属性 | 不含Symbol 属性,但是包括不可枚举属性 |
Object.getOwnPropertySymbols(obj) |
返回一个数组,包含对象自身的所有Symbol 属性 |
|
Reflect.ownKeys(obj) |
返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol 或字符串,也不管是否可枚举 |
1 | Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 }) |
9.8 proto属性,Object.setPrototypeOf(),Object.getProptotypeOf()
9.8.1 __proto__属性
__proto__属性
:用来读取或设置当前对象的prototype
对象
注意:该属性没有写入ES6
的正文,而是写入了附录。标准明确规定,只有浏览器
必须部署这个属性,其他运行环境不一定需要部署,而且新的代码最好认为这个属性是不存在的。
1 | // es6的写法 |
polyfill
1 | Object.defineProperty(Object.prototype, '__proto__', { |
9.8.2 Object.setPrototypeOf()
用途:设置一个对象的prototype
对象
注意:ES6正式推荐的设置原型对象的方法
Object.setPrototypeOf(object, prototype)
1 | // 例一:创建一个新对象,并将其 prototype 设置为 null |
polyfill
1 | function (obj, proto) { |
9.8.3 Object.getPrototypeOf()
用途:读取一个对象的prototype
对象
1 | // 构造器 |
9.9 Object.values(),Object.entries()
比较 | 返回值 | 兼容性 |
---|---|---|
Object.keys() |
一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键名 | es5 |
Object.values() |
一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值 | es7提案 |
Object.entries() |
一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组 | es7提案 |
9.9.1 Object.keys()
1 | var obj = { foo: "bar", baz: 42 }; |
9.9.2 Object.values()
注意:
- 返回数组的成员顺序,见9.7
- 会过滤属性名为
Symbol
值的属性 - 如果参数是一个字符串,会返回各个字符组成的一个数组
- 如果参数不是对象,会先将其转为对象
- 由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以会返回空数组
1 | /* 只返回对象自身的可遍历属性 */ |
9.9.3 Object.entries()
说明:除了返回值不一样,该方法的行为与Object.values
基本一致。
用途:
- 基本用途是遍历对象的属性
- 将对象转为真正的
Map
结构
- 将对象转为真正的
1 | /* 基本用途是遍历对象的属性 */ |
polyfill
Generator
函数的版本
1 | function* entries(obj) { |
非Generator
函数的版本
1 | function entries(obj) { |
9.10 对象的扩展运算符
说明:将Rest解构赋值
/扩展运算符(...)
引入对象
兼容性:ES7
的一个提案,Babel
转码器已经支持这项功能
9.10.1 Rest解构赋值
说明:对象的Rest解构赋值
用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面
Rest解构赋值
要求等号右边是一个对象,所以如果等号右边是undefined
或null
,就会报错(因为它们无法转为对象)Rest解构赋值
必须是最后一个参数,否则会报错Rest解构赋值
的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么Rest解构赋值
拷贝的是这个值的引用,而不是这个值的副本Rest解构赋值
不会拷贝继承自原型对象的属性用途:扩展某个函数的参数,引入其他操作
1 | /* 基础 */ |
9.10.2 扩展运算符
说明:可以取代Object.assign()
的功能
用途:用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
- 可以用于合并两个对象
- 自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉
- 扩展运算符的参数对象之中,如果有取值函数get,这个函数是会执行的
- 如果扩展运算符的参数是 null 或 undefined,这个两个值会被忽略,不会报错
1 | /* 可以用于合并两个对象 */ |
9.11 Object.getOwnPropertyDescriptors()
兼容性:ES7
的一个提案
用途:返回指定对象所有自身属性(非继承属性)的描述对象
- 解决
Object.assign()
无法正确拷贝get
属性和set
属性的问题(Object.assign()
方法总是拷贝一个属性的值,而不会拷贝它背后的get
或set
) - 配合
Object.create()
方法,将对象属性克隆到一个新对象。这属于浅拷贝 - 可以实现,一个对象继承另一个对象
- 可以用来实现
Mixin
(混入)模式
返回值描述:所有原对象的属性名都是该对象的属性名,对应的属性值就是该属性的描述对象
注意:出于完整性的考虑,Object.getOwnPropertyDescriptors
进入标准以后,还会有Reflect.getOwnPropertyDescriptors
方法
俩方法比较 | 兼容性 | 说明 |
---|---|---|
Object.getOwnPropertyDescriptor |
es5 | 返回某个对象属性的描述对象(包括继承来的) |
Object.getOwnPropertyDescriptors |
es7 | 返回指定对象所有自身属性(非继承属性)的描述对象 |
1 | const obj = { |
9.11.1 polyfill
1 | /** |
9.11.2 常见用途
9.11.2.1 拷贝 get 和 set
背景:Object.assign()
方法总是拷贝一个属性的值,而不会拷贝它背后的get
或set
说明:解决Object.assign()
无法正确拷贝get
属性和set
属性的问题
原理:Object.getOwnPropertyDescriptors()
配合Object.defineProperties
使用Object.assign()
1 | const source = { |
正确拷贝(浅拷贝) get 和 set
1 | const source = { |
9.11.2.2 配合 Object.create() 实现浅拷贝
1 | /** |
9.11.2.3 实现继承
1 | const obj = Object.create( |
9.11.2.4 实现Mixin(混入)模式
说明:利用Array.prototype.reduce
将某些对象的属性混合到目标对象
1 | let mix = (object) => ({ |