文章目录
ES6 对象的扩展
1.0 属性的简洁表示法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
const foo = 'bar'; const baz = { foo}; baz // {foo: "bar"} // 等同于 const baz = { foo: foo};
2.0 属性名表达式
JavaScript 定义对象的属性,有两种方法。
const obj = { } // 方法一 obj.foo = true; // 方法二 obj['a' + 'bc'] = 123; console.log(obj); // { foo: true, abc: 123 }
上面代码是:
方法一是直接使用标识符作为属性名.
方法二是用表达式作为属性名, 这时要将表达式写在 方括号 里.
但是, 如果使用字面量方式定义对象(使用大括号), 在ES5中只能用方法一()标识符定义属性
var obj = { foo: true, abc: 123 };
ES6允许字面量方式定义对象时, 用方法二(表达式)作为对象的属性名, 即把表达式放在 方括号内
let propKey = 'foo'; let obj = { [propKey]: true, ['a' + 'bc']: 123 }; console.log(obj); // { foo: true, abc: 123 }
🏴 注意:
属性名表达式如果是一个对象, 默认情况下, 自动会将对象转化为
[Object,Object]
这一点要特别小心.const keyA = { a: 1}; const keyB = { b: 2}; const myObject = { [keyA]: 'valueA', [keyB]: 'valueB' }; console.log(myObject); // { '[object Object]': 'valueB' }
上面代码中,
[keyA]
和[keyB
得到 的都是[object Object]
, 所以[keyB]
会把[keyA]
覆盖掉, 而myObject
最后只有一个[Object,Object]
属性.
3.0 属性的可枚举性和遍历
-
可枚举性
对象的每个属性都有一个描述对象(descriptor), 用来控制该属性的行为.
Object.getOwnPropertyDescriptor
方法可以获取该属性的描述对象let myObj = { a:'123', b: '参数b' } console.log(Object.getOwnPropertyDescriptor(myObj, 'a')); // 最后打印出 /** * { value: '123', * writable: true, * enumerable: true, * configurable: true } */
描述对象的
enumerable
属性, 称为 "可枚举"属性, 如果该属性为false
, 就表示某些操作会忽略当前属性.getOwnPropertyDescriptors
和getOwnPropertyDescriptor
类似, 只不过前者返回所有属性的描述对象. -
属性的遍历
ES6 一共有5中方法可以遍历对象的属性
for…in
for...in 循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
- 首先遍历所有数值键,按照数值升序排列
- 其次遍历所有字符串键,按照加入时间升序排列
- 最后遍历所有 Symbol 键,按照加入时间升序排列
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 }) // ['2', '10', 'b', 'a', Symbol()]
4.0 super 关键字
我们知道,
this
关键字总是指向函数所在的当前对象, ES6又新增了另一个类似的关键字super
, 指向当前对象的原型对象.const proto = { foo: 'hello' }; const obj = { foo: 'world', find() { return super.foo; } }; Object.setPrototypeOf(obj, proto); console.log(obj.find()); // "hello
上面代码中, 对象
obj.find()
方法之中, 通过super.foo
引入了原型对象的foo
属性.注意:
super
关键字表示原型对象时, 只能用在对象的方法之中, 用在其他地方都会报错// 报错 const obj = { foo: super.foo } // 报错 const obj = { foo: () => super.foo } // 报错 const obj = { foo: function () { return super.foo } }
上面三种
super
的用法都会报错,因为对于 JavaScript 引擎来说,这里的super
都没有用在对象的方法之中。第一种写法是super
用在属性里面,第二种和第三种写法是super
用在一个函数里面,然后赋值给foo
属性。目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。
4.0 对象的解构赋值
对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; x // 1 y // 2 z // { a: 3, b: 4 }
上面代码中,变量
z
是解构赋值所在的对象。它获取等号右边的所有尚未读取的键(a
和b
),将它们连同值一起拷贝过来
解构赋值必须是最后一个参数,否则会报错。
let { ...x, y, z } = someObject; // 句法错误 let { x, ...y, ...z } = someObject; // 句法错误
注意,解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本
5.0 对象的扩展运算符
对象的扩展运算符(
...
) 用于取出参数对象的所有可遍历属性, 拷贝到当前的对象中const obj = { name: 'Gene', age: