对象的扩展

作者 zhufenfen 日期 2021-07-27
对象的扩展

本篇博客记录了ES6在对象这个数据结构上做的升级。

属性的简洁表示法

在大括号里直接写入变量和函数,作为对象的属性和方法

1
{ name, hello(){} }

注意:简写的对象方法,不能当作构造函数

1
2
3
4
var obj = {
f(){}
}
new obj.f()

属性名表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
let lastWord = 'last word'
const keyA = {a: 1}
const keyB = {b: 1}
let obj = {
['a' + 'bc']: 123,
[lastWord]: 'world',
['first'+'Word'](){},
[keyA]: 'valueA',
[keyB]: 'valueB', // 对象会自动转为'[object Object]'
}
obj[lastWord] // 'world'
obj['last word'] // 'world'
obj['[object Object]'] // 'valueB'

方法的name属性

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
var obj = {
getItem(){}
}
obj.getItem.name // 'getItem'

var getItem = function(){}
getItem.bind().name // 'bound getItem'

(new Function()).name // 'anonymous'

var obj = {
set foo(x){},
get foo(){}
}
var descriptor = Object.getOwnPropertyDescriptor(obj, 'foo')
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"

// Symbol值的描述信息
var symbolA = Symbol("description");
var symbolB = Symbol()
var obj = {
[symbolA](),
[symbolB](){}
}
obj[symbolA].name // '[description]'
obj[symbolB].name

属性的可枚举性和遍历

1
2
3
4
var obj = {foo: '123'}
Object.getOwnPropertyDescriptor(obj, 'foo')
// 用来获取属性的描述对象
{value: "123", writable: true, enumerable: true, configurable: true}

可枚举性 enumerable

有四个操作会忽略enumerable为false的属性

  • for..in 遍历自身和继承的可枚举属性
  • Object.keys() 自身
  • JSON.stringify() 自身
  • Object.assign() 自身
    1
    2
    3
    Object.getOwnPropertyDescriptor([], 'length').enumberable // false
    Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumberable // false
    Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable // false

属性的遍历

方法

  • for…in 自身和继承的可枚举属性
  • Object.keys(obj) 自身的可枚举属性
  • Object.getOwnPropertyNames(obj) 自身所有属性(不包括Symbol)
  • Object.getOwnPropertySymbols(obj) 遍历自身所有Symbol属性
  • Reflect.ownKeys(obj) 自身所有属性

次序

  • 数值键,升序
  • 字符串键,加入时间升序
  • Symbol键,加入时间升序

super关键字

this关键字总是指向函数所在的当前对象,super指向当前对象的原型对象

super.foo等同于
Object.getPrototypeOf(this).foo
Object.getPrototypeOf(this).foo.call(this)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var proto = {
foo: 'world',
find() {
console.log(this.foo)
}
}
var obj = {
foo: 'world',
find() {
super.find()
}
}
Object.setPrototypeOf(obj, proto);
obj.find()

注意:super只能用在对象的方法中

对象的扩展运算符

解构赋值

  • 扩展运算符的解构赋值,不能复制继承自原型对象的属性
    1
    2
    3
    4
    5
    var obj = Object.create({a: 1, b: 2})
    obj.c = 3
    var {a, ...b} = obj
    a // 1
    b // {c: 3}
  • 只能用在最后一个参数
  • 扩展运算符后面必须是一个变量
    1
    2
    3
    4
    5
    var obj = {a: 1, b: 1, c: 1}
    var {a, ...{b, c}} = obj // 报错

    var {a, ...newObj} = obj // 正确
    var {b, c} = newObj

扩展运算符

{…obj}等同于Object.assign({}, obj)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 拷贝对象原型的属性
var clone1 = {
...obj,
__proto__: Object.getPrototypeOf(obj)
}
var clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)),
obj
)
var clone3 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)

扩展运算符的参数对象如果有取值函数,这个函数在扩展时是会执行的

1
2
3
4
5
6
var x = {
get a() {
console.log(1)
}
}
{...x}

链判断运算符(optional chaining)

  • obj?.prop
  • obj?.[]
  • func?.()

如果为undefined或null,则会返回undefined,不再往下运算

Null判断运算符

a??b
左侧为undefined或null,则会返回右侧

如果和多个逻辑运算符一起使用,必须用括号表明优先级。