Object

coderljw 2024-10-13 JS 基础
  • JS 基础
  • Object
大约 6 分钟

# 1. Object(any)

  • 创建一个对象包装器,俗称装箱。

    1. null 与 undefined 返回空对象。
    2. 基本数据类型返回包装后的对象。
    3. 引用数据类型返回本身。
Object(null) // => {}
Object(undefined) // => {}

Object(7) => // => {7}
Object(7).valueOf() === 7 // => true

const reg = /7/
Object(reg) === reg // => true
1
2
3
4
5
6
7
8

# 2. Object.create(proto, options)

  • 2006 年,Douglas Crockford 写了一篇文章:《JavaScript 中的原型式继承》 (opens new window)。ECMAScript 5 通过增加 Object.create() 方法将原型式继承的概念规范化了,第二个参数同 Object.defineProperties() 第二个参数。

    本质上,object() 是对传入的对象执行了一次浅复制。Object.create() 只使用一个参数时与 object() 等价。

function object(o) {
  function F() {}
  F.prototype = o
  return new F()
}

// 以下等价
const foo = {}
const foo = Object.create(Object.prototype)
const foo = object(Object.prototype)

// 创建完全为空的对象,无原型链
Object.create(null) // => {}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3. hasOwnProperty(prop)

  • 检测自身是否拥有该属性,不包含原型链中的属性。

  • in 运算符会查找原型链中的可枚举属性。

function Skt() {}
Skt.prototype.faker = 3
const edg = new Skt()
edg.clearlove7 = 0

edg.hasOwnProperty('faker') // => false
edg.hasOwnProperty('clearlove7') // => true

'faker' in edg // => true
1
2
3
4
5
6
7
8
9

# 4. isPrototypeOf(object)

  • 检测一个对象是否在其原型链上(Bar.isPrototypeOf(foo) 为检测 foo.__proto__ === Bar)。

  • instanceof 检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上(foo instanceof Bar 为检测 foo.__proto__ === Bar.prototype)。

  • Bar.prototype.isPrototypeOf(foo) 等价于 foo instanceof Bar。

function Foo() {}
const bar = new Foo()

Foo.prototype.isPrototypeOf(bar) // => true
Object.prototype.isPrototypeOf(bar) // => true
Function.prototype.isPrototypeOf(bar) // => false

bar instanceof Foo // => true
bar instanceof Object // => true
bar instanceof Function // => false
1
2
3
4
5
6
7
8
9
10

# 5. Object.assign(targetObject, object...)

  • 将多个对象中可枚举属性合并至目标对象,属性名相同时会覆盖。

  • {...} 展开运算符可完全替代 Object.assign(),较 Object.assign() 有简便和性能上的优势。

const foo = {
  name: '徐扶墙',
  age: 17,
}
const bar = {
  name: '姜姒',
}

Object.assign(foo, bar) // => {name: '姜姒', age: 17}
{...foo, ...bar} // => {name: '姜姒', age: 17}

// 传入可迭代对象
Object.assign({}, [1, 2, 3]) // => {0: 1, 1: 2, 2: 3}
Object.assign({}, 'neo') // => => {0: 'n', 1: 'e', 2: 'o'}
{...[1, 2, 3]} // => {0: 1, 1: 2, 2: 3}
{...'neo'} // => => {0: 'n', 1: 'e', 2: 'o'}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 6. Object.prototype.toString()

  • 通过 Object.prototype.toString.call() 获取对象的类型(最全面的检测方式)。
const detectionType = value =>
  typeof value === 'object'
    ? {}.toString.call(value).slice(8, -1).toLowerCase()
    : typeof value
1
2
3
4

# 7. Object.setPrototypeOf(object, proto)

  • 设置对象的原型(Object.setPrototypeOf(foo, bar) 等价于 foo.__proto__ = bar)。

  • 由于更改对象的原型指向性能并不好,更推荐使用 Object.create() 创建新对象并设置其对象的原型。

function Foo() {}
Foo.prototype.matrix = 'neo'

// 以下等价
Object.setPrototypeOf({}, Foo.prototype)
Object.create(Foo.prototype)
({}).__proto__ = Foo.prototype
1
2
3
4
5
6
7

# 8. Object.getPrototypeOf(object)

  • 获取对象的原型(Object.getPrototypeOf(bar) 获取 bar.__proto__)。
function Foo() {}
const bar = new Foo()

Object.getPrototypeOf(bar) === Foo.prototype // => true
1
2
3
4

# 9. Object.defineProperty(object, prop, options)

  • 定义对象属性(Vue 2.x 数据响应式中应用此方法)。

  • 当配置了 get() 或 set() 方法,value 和 writable 配置将会失效。

  • 配置默认值是使用 Object.defineProperty() 定义属性时的默认值,若在 foo 中先定义 name 属性,则默认值 writable、enumerable、configurable 为 true。

const foo = {}

Object.defineProperty(foo, 'name', {
  // 属性的值,默认undefined
  value: '徐扶墙',
  // 是否可写,默认false
  writable: true,
  // 是否可枚举,默认false
  enumerable: true,
  // 是否可配置,默认false
  configurable: true,
  // 获取属性时执行的方法
  get() {
    return '获取name值'
  },
  // 设置属性时执行的方法
  set(newValue) {
    return '设置name值'
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 10. Object.defineProperties(object, props)

  • 与 Object.defineProperty() 用法类似,可以一次定义多个属性。
const foo = {}

Object.defineProperties(foo, {
  name: {
    value: '徐扶墙',
    enumerable: true,
  },
  age: {
    get() {
      return '获取age值'
    },
    set(newValue) {
      return '设置age值'
    },
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 11. Object.getOwnPropertyDescriptor(object, prop)

  • 获取自身对应属性的描述符。
const foo = {}

Object.defineProperty(foo, 'name', {
  value: '徐扶墙',
  writable: true,
})

Object.getOwnPropertyDescriptor(foo, 'name') // => {value: '徐扶墙', writable: true, enumerable: false, configurable: false}
1
2
3
4
5
6
7
8

# 12. Object.getOwnPropertyDescriptors(object)

  • 获取自身所有属性的描述符。
const foo = {}

Object.defineProperties(foo, {
  name: {
    value: '徐扶墙',
    enumerable: true,
  },
  age: {
    get() {
      return '获取age值'
    },
    set(newValue) {
      return '设置age值'
    },
  },
})

Object.getOwnPropertyDescriptors(foo) // => {name: {value: '徐扶墙', writable: false, enumerable: true, configurable: false}, age: {enumerable: false, configurable: false, get: ƒ, set: ƒ}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 13. propertyIsEnumerable(prop)

  • 检测属性是否可枚举。
const foo = {}
Object.defineProperties(foo, {
  name: {
    value: '徐扶墙',
    enumerable: true,
  },
  age: {
    get() {
      return 17
    },
  },
})

foo.propertyIsEnumerable('name') // => true
foo.propertyIsEnumerable('age') // => false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 14. Object.keys(object) & Object.values(object) & Object.entries(object)

  • 返回由对象自身 key/value/[key, value] 组成的数组,不包含不可枚举属性。
const foo = {}
Object.defineProperties(foo, {
  name: {
    value: '徐扶墙',
    enumerable: true,
  },
  age: {
    enumerable: true,
    get() {
      return 17
    },
  },
  wife: {
    value: '裴南苇',
  },
})

Object.keys(foo) // => ['name', 'age']
Object.values(foo) // => ['徐扶墙', 17]
Object.entries(foo) // => [['name', '徐扶墙'], ['age', 17]]

Object.keys([1, 2, 3]) // => ['0', '1', '2']
Object.values('neo') // => ['n', 'e', 'o']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 15. Object.getOwnPropertyNames()

  • 返回自身属性组成的数组,包含不可枚举属性。
const foo = {}
Object.defineProperties(foo, {
  name: {
    value: '徐扶墙',
    enumerable: true,
  },
  age: {
    enumerable: true,
    get() {
      return 17
    },
  },
  wife: {
    value: '裴南苇',
    enumerable: false,
  },
})

Object.getOwnPropertyNames(foo) // => ['name', 'age', 'wife']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 16. Object.fromEntries(iterable)

  • 将键值对列表转换为一个对象。
Object.fromEntries(Object.entries({ name: '徐扶墙', age: 17 })) // => {name: '徐扶墙', age: 17}

Object.fromEntries(
  new Map([
    ['name', '徐扶墙'],
    ['age', 17],
  ])
) // => {name: '徐扶墙', age: 17}
1
2
3
4
5
6
7
8

# 17. Object.getOwnPropertySymbols(object)

  • 返回自身的所有的 Symbol 属性组成的数组。
const foo = {
  [Symbol('name')]: '徐扶墙',
  [Symbol('age')]: 17,
  wife: '裴南苇',
}

Object.getOwnPropertySymbols(foo) // => [Symbol(name), Symbol(age)]
1
2
3
4
5
6
7

# 18. Object.is(value, value)

  • 最准确的比较方式,效率不高,主要用来解决下面两种情况(NaN 可用 Number.isNaN() 方法判断)。
Object.is(+0, -0) // => false
Object.is(NaN, NaN) // => true

+0 === -0 // => true
NaN === NaN // => false
1
2
3
4
5

# 19. Object.preventExtensions(object)

  • 浅禁止对象扩展,可删除属性,可重新配置(Object.defineProperty() | Object.defineProperties())。
const foo = {
  name: '徐扶墙',
  harem: {
    bigWife: '姜姒',
  },
}

Object.preventExtensions(foo)
foo.age = 17
foo.harem.smallWife = '裴南苇'
delete foo.harem.bigWife // => true
console.log(foo) // => {name: '徐扶墙', harem: {smallWife: '裴南苇'}}
1
2
3
4
5
6
7
8
9
10
11
12

# 20. Object.isExtensible(object)

  • 判断对象是否可扩展。
const foo = {
  name: '徐扶墙',
  age: 17,
  harem: {
    bigWife: '姜姒',
    smallWife: '裴南苇',
  },
}

Object.preventExtensions(foo)
Object.isExtensible(foo) // => false
Object.isExtensible(foo.harem) // => true
1
2
3
4
5
6
7
8
9
10
11
12

# 21. Object.seal(object)

  • 浅密封对象,不可扩展,不可删除属性,不可重新配置(Object.defineProperty() | Object.defineProperties())。
const foo = {
  name: '徐扶墙',
  harem: {
    bigWife: '姜姒',
    smallWife: '裴南苇',
  },
}

Object.seal(foo)
foo.age = 17
delete foo.name // => false
delete foo.harem.smallWife // => true
console.log(foo) // => {name: '徐扶墙', harem: {bigWife: '姜姒'}}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 22. Object.isSealed(object)

  • 判断对象是否密封。
const foo = {
  name: '徐扶墙',
  age: 17,
  harem: {
    bigWife: '姜姒',
    smallWife: '裴南苇',
  },
}

Object.seal(foo)
Object.isSealed(foo) // => true
Object.isSealed(foo.harem) // => false
1
2
3
4
5
6
7
8
9
10
11
12

# 23. Object.freeze(object)

  • 浅冻结对象,不可增删改对象属性,不可从新配置(Object.defineProperty() | Object.defineProperties())。
const foo = {
  name: '徐扶墙',
  age: 17,
  harem: {
    bigWife: '姜姒',
    smallWife: '裴南苇',
  },
}

Object.freeze(foo)
foo.rank = '天下第二' // => 无效
foo.age = 18 // => 无效
delete foo.name // => false
foo.harem.smallWife = '白狐儿脸' // => 有效
console.log(foo) // => { name: '徐扶墙', age: 17, harem: { bigWife: '姜姒', smallWife: '白狐儿脸' } }

// 深度冻结
function deepFreeze(obj) {
  const values = Object.values(obj)
  if (values.length)
    values.forEach(val => {
      if (typeof val === 'object' && val !== null) deepFreeze(val)
    })
  return Object.freeze(obj)
}
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

# 24. Object.isFrozen(object)

  • 判断是否为冻结对象。
const foo = {
  name: '徐扶墙',
  age: 17,
  harem: {
    bigWife: '姜姒',
    smallWife: '裴南苇',
  },
}

Object.freeze(foo)

Object.isFrozen(foo) // => true
Object.isFrozen(foo.name) // => true
Object.isFrozen(foo.harem) // => false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
以父之名
周杰伦.mp3