Object常用方法总结

Object


# 属性获取/遍历/设置

# in

所有属性:自身 + 原型链 + 可枚举 + 不可枚举 + 符号 + 非符号

let symbol = Symbol('c')
let obj = let obj = Object.create(
  {
    a: 1,
  },
  {
    b: {
      value: 2,
      enumerable: false,
    },
    [symbol]: {
      value: 3,
      enumerable: true
    },
    d: {
      value: 4
    }
  }
)

'a' in obj // true
'b' in obj // true
symbol in obj // true
'd' in obj // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# for...in

遍历 自身 + 原型链 + 可枚举 + 非符号 属性

let obj = Object.create(
  {
    a: 1,
  },
  {
    b: {
      value: 2,
      enumerable: false,
    },
    c: {
      value: 2,
      enumerable: true,
    },
    [Symbol('c')]: {
      value: 3,
      enumerable: true,
    },
  }
)

for (let key in obj) {
  // c
  // a
  console.log(key)
}
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

# Object.keys

返回自身 + 可枚举 + 非符号属性的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致

  • 在 ES5 里,如果此方法的参数不是对象(而是一个原始值),那么它会抛出 TypeError
  • ES6 后会自动装箱
// a 是原型上的属性
// getFoo 是不可枚举的
var myObj = Object.create(
  {
    a: 1,
  },
  {
    getFoo: {
      value: function () {
        return this.foo
      },
    },
  }
)
// foo 是可枚举且定义在自身的属性
myObj.foo = 1
// 符号属性
myObj[Symbol('bar')] = 2

console.log(Object.keys(myObj)) // ['foo']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Reflect.ownKeys

返回自身 + 可枚举 + 不可枚举 + 符号 + 非符号属性

Reflect.ownKeys = Object.getOwnPropertySymbols + Object.getOwnPropertyNames

let symbol = Symbol('c')
let obj = Object.create(
  {
    a: 1,
  },
  {
    b: {
      value: 2,
      enumerable: true,
    },
    [symbol]: {
      value: 3,
    },
    d: {
      value: 4,
    },
  }
)

Reflect.ownKeys(obj) // ['b', 'd', Symbol(c)]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Object.getOwnPropertyNames

返回一个由指定对象的所有自身 + 可枚举 + 不可枚举 + 非符号属性的属性名组成的数组

let my_obj = Object.create(
  {
    a: 1,
  },
  {
    getFoo: {
      value: function () {
        return this.foo
      },
    },
    [Symbol('c')]: {
      value: 2,
      enumerable: true,
    },
  }
)
my_obj.foo = 1

console.log(Object.getOwnPropertyNames(my_obj)) // ["getFoo", "foo"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Object.getOwnPropertySymbols

返回一个由指定对象的所有自身 + 可枚举 + 不可枚举 + 符号属性的属性名组成的数组

let my_obj = Object.create(
  {
    a: 1,
  },
  {
    getFoo: {
      value: function () {
        return this.foo
      },
      enumerable: false,
    },
    [Symbol('c')]: {
      value: 2,
      enumerable: true,
    },
  }
)
my_obj.foo = 1

console.log(Object.getOwnPropertyNames(my_obj).sort()) // ["foo", "getFoo"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Object.prototype.hasOwnProperty

返回一个布尔值,指示对象属性中是否具有指定的自身 + 可枚举 + 不可枚举 + 符号 + 非符号属性(也就是,是否有指定的键)

let s = Symbol('s')
let obj = Object.create(
  {
    a: 1,
  },
  {
    b: {
      value: 2,
    },
    c: {
      value: 3,
      enumberable: true,
    },
    [s]: {
      value: 4,
    },
  }
)

obj.hasOwnProperty('a') // false
obj.hasOwnProperty('b') // true
obj.hasOwnProperty('c') // true
obj.hasOwnProperty(s) // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# Object.getOwnPropertyDescriptor

获取对象上自有属性对应的属性描述符对象,属性不存在则返回 undefined

let s = Symbol('s')
let obj = Object.create(
  {
    a: 1,
  },
  {
    [s]: {
      value: 4,
    },
  }
)

// {"value":4, "writable":false, "enumerable":false, "configurable":false}
Object.getOwnPropertyDescriptor(obj, s)
// {
//   b: {value: 2, writable: false, enumerable: false, configurable: false},
//   c: {value: 3, writable: false, enumerable: false, configurable: false},
//   Symbol(s): {value: 4, writable: false, enumerable: false, configurable: false}
// }
Object.getOwnPropertyDescriptors(obj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Object.entries

返回一个给定对象自身 + 可枚举属性的键值对数组

const object1 = {
  a: 'somestring',
  b: 42,
}

for (const [key, value] of Object.entries(object1)) {
  console.log(`${key}: ${value}`)
}

// expected output:
// "a: somestring"
// "b: 42"
1
2
3
4
5
6
7
8
9
10
11
12

# Object.values

返回一个给定对象自身 + 可枚举属性的值的数组

var my_obj = Object.create(
  {},
  {
    getFoo: {
      value: function () {
        return this.foo
      },
    },
  }
)
my_obj.foo = 'bar'
console.log(Object.values(my_obj)) // ['bar']
1
2
3
4
5
6
7
8
9
10
11
12

# Object.defineProperty

直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

一次性设置多个属性使用Object.defineProperties

# 属性描述符对象

value/writable 不能和 存取描述符 同时存在

let val = 1
Object.defineProperty(obj, 'a', {
  value: val,
  set(v) {
    val = v
  },
})
// TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
1
2
3
4
5
6
7
8

# 数据描述符

  • value

    该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined

  • writable

    当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变, 默认为 false

  • enumberable

    当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。默认为 false

  • configable

    当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性才能被 delete 删除默认为 false

# 存取描述符

  • get

    属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined

  • set

    属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象默认为 undefined

# 原型相关

# Object.create

创建一个新对象,使用现有的对象来提供新创建的对象的__proto__

该方法的第二个参数的属性类型参照 Object.defineProperties 的第二个参数。

  • 用于继承
// Shape - 父类(superclass)
function Shape() {
  this.x = 0
  this.y = 0
}

// 父类的方法
Shape.prototype.move = function (x, y) {
  this.x += x
  this.y += y
  console.info('Shape moved.')
}

// Rectangle - 子类(subclass)
function Rectangle() {
  Shape.call(this) // call super constructor.
}

// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype, {
  constructor: {
    value: Rectangle,
  },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  • 结合 Object.assing 可以用来实现继承多个对象,通常称为混入
function MyClass() {
  SuperClass.call(this)
  OtherSuperClass.call(this)
}

// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype)
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype)
// 重新指定constructor
MyClass.prototype.constructor = MyClass
1
2
3
4
5
6
7
8
9
10
11

# Objet.getPrototypeOf

获取一个对象的原型(内部[[Prototype]]属性的值

let f = function () {}

Object.getPrototypeOf(f) === f.prototype // false
Object.getPrototypeOf(f) === f.__proto__ // true
1
2
3
4

# Object.setPrototypeOf

设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null

let f = function () {}

Object.setPrototypeOf(f, {
  name: 'f',
})
console.log(f.__proto__) // { name: 'f' }
1
2
3
4
5
6

# Object.prototype.isPrototypeOf

用于测试一个对象是否存在于另一个对象的原型链上

  • 与 instanceof 运算符不同, o instanceof Ctor 检测的是 构造器 Ctor 的 prototype 属性是否出现在 对象 o 的原型链 (即 __proto__) 中的任何位置
let A = function () {}

let a = new A()

a instanceof A // true

A.isPrototypeOf(a) // false

A.prototype.isPrototypeOf(a) // true
1
2
3
4
5
6
7
8
9

# 其他

# Object.assign

用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。

Object.assign(target, ...sources)
1
  • 只会拷贝源对象自身的并且可枚举的属性到目标对象,继承的和不可枚举的属性不会拷贝
  • Symbol 类型的属性都会被拷贝
  • 无法拷贝属性的特性们
let s1 = {
  // 自身可枚举属性
  a: 1,
  // symbol属性
  [Symbol('b')]: 2,
}
// 不可枚举属性
Object.defineProperty(s1, 'c', {
  value: 3,
  enumerable: false,
})
// 继承属性
Object.setPrototypeOf(s1, {
  d: 4,
})

let t = Object.assign({}, s1)
// {
//   a: 1,
//   Symbol(b): 2
// }
console.log(t)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  • source 对象值为 null 或 undefined 的时候不会抛出错误,但是会被忽略
  • target 对象的值为 null 或 undefined 则会报错
let t = Object.assign({}, undefined, null, {
  a: undefined,
  b: null,
})
// {
//   a: undefined,
//   b: null
// }
console.log(t)
1
2
3
4
5
6
7
8
9
  • 对于引用类型的属性,拷贝的是引用,而不是值,浅拷贝
let o1 = {
  a: {
    b: {
      c: 123,
      d: 123,
    },
  },
}
let o2 = {
  a: {
    b: {
      e: 123,
    },
  },
}
let t = Object.assign({}, o1, o2)

// {
//   a: {
//     b: {
//       e: 123,
//     }
//   }
// }
console.log(t)

t.a.b = 234
console.log(o2.a.b) // 234
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
28

# Object.is

判断两个值是否为同一个值,不会进行类型转换

  • === 运算符不同的是,Object.is 认为
    • +0-0不相等
    • NaNNaN相等
Object.is = function (x, y) {
  // SameValue algorithm
  if (x === y) {
    // +0 != -0
    return x !== 0 || 1 / x === 1 / y
  } else {
    // Step 6.a: NaN == NaN
    return x !== x && y !== y
  }
}
1
2
3
4
5
6
7
8
9
10

# Object.freeze

冻结一个对象。返回传递的对象,而不是创建一个被冻结的副本

判断一个对象是否被冻结使用 Object.isFrozen()

一个被冻结的对象再也不能被修改;

  • 不能向这个对象添加新的属性,
  • 不能删除已有属性,
  • 不能修改该对象已有属性的可枚举性、可配置性、可写性,
  • 不能修改已有属性的值
  • 该对象的原型也不能被修改
  • 浅冻结 而不是 深冻结
obj1 = {
  internal: {},
}

Object.freeze(obj1)
obj1.internal.a = 'aValue'

obj1.internal.a // 'aValue'
1
2
3
4
5
6
7
8

# Object.seal

封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置当前属性的值只要原来是可写的就可以改变

  • 密封一个对象会让这个对象变的不能添加新属性,且所有已有属性会变的不可配置
  • 属性不可配置的效果就是属性变的不可删除,以及不能修改其属性描述符对象,除了 value 属性
  • 属性的值仍然可以修改

判断一个对象是否被密封 Object.isSealed()

var obj = {
  prop: function () {},
  foo: 'bar',
}

// 可以添加新的属性
// 可以更改或删除现有的属性
obj.foo = 'baz'
obj.lumpy = 'woof'
delete obj.prop

var o = Object.seal(obj)

o === obj // true
Object.isSealed(obj) // === true

// 仍然可以修改密封对象的属性值
obj.foo = 'quux'

// 但是你不能将属性重新定义成为访问器属性
// 反之亦然
Object.defineProperty(obj, 'foo', {
  get: function () {
    return 'g'
  },
}) // throws a TypeError

Object.defineProperty(obj, 'foo', {
  value: 'the friendly duck',
})
obj.foo // 'the friendly duck'

// 删除属性将会失败
delete obj.foo
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
28
29
30
31
32
33
34
Last Updated: 10/21/2024, 4:15:17 PM