【JavaScript】Object常用方法总结

前言

在 JavaScript 中,几乎所有的对象都是 Object 类型的实例,它们都会从 Object.prototype 继承属性和方法,虽然大部分属性都会被覆盖(shadowed)或者说被重写了(overridden)。 除此之外,Object 还可以被故意的创建,但是这个对象并不是一个“真正的对象”(例如:通过 Object.create(null)),或者通过一些手段改变对象,使其不再是一个“真正的对象”(比如说:Object.setPrototypeOf)。

静态方法

Object.create

创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。

let obj = Object.create(null)
let o1 = {
  name: 'abc',
  say() {
    console.log(this.name)
  }
}
let o2 = Object.create(o1)
o2.name = 'ABC'
o2.say() // ABC

Object.getPrototypeOf()

返回指定对象的原型(内部[[Prototype]]属性的值)。

function Foo() {}
let foo = new Foo()
Object.getPrototypeOf(foo) === Foo.prototype // true

Object.setPrototypeOf()

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

const obj = {}
Object.setPrototypeOf(obj, null)

Object.getOwnPropertyDescriptors()

获取一个对象的所有自身属性的描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

const obj = {
  age: 18,
  name: 'A'
}
console.log(Object.getOwnPropertyDescriptors(obj))
/**
{
  age: { value: 18, writable: true, enumerable: true, configurable: true },
  name: { value: 'A', writable: true, enumerable: true, configurable: true }
}
**/

Object.getOwnPropertyDescriptor

获取对象上一个自有属性对应的属性描述符。

const obj = {
  age: 18,
  name: 'A'
}
console.log(Object.getOwnPropertyDescriptor(obj, 'age'))
// { value: 18, writable: true, enumerable: true, configurable: true }

Object.getOwnPropertyNames()

获取指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。

const obj = {
  age: 18,
  name: 'A',
  [Symbol('address')]: 'GZ'
}
console.log(Object.getOwnPropertyNames(obj)) // [ 'age', 'name' ]

Object.getOwnPropertySymbols()

获取指定对象自身的所有 Symbol 属性的数组。

const obj = {
  age: 18,
  name: 'A',
  [Symbol('address')]: 'GZ'
}
console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(address) ]

Object.hasOwn()

如果指定的对象自身有指定的属性,返回 true。如果属性是继承的或者不存在,返回 false

Object.assign()

将所有可枚举自有属性从一个或多个源对象复制到目标对象,返回修改后的对象。
如果目标对象与源对象具有相同的 key,则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的属性。

Object.fromEntries()

将键值对列表转换为一个对象

const entries = new Map([
  ['name', 'abc'],
  ['age', 20]
])
const obj = Object.fromEntries(entries)
console.log(obj) // { name: 'abc', age: 20 }

Object.is()

Object.is() 方法判断两个值是否为同一个值,如果满足以下任意条件则两个值相等:

  • 都是undefined
  • 都是 null
  • 都是 true 或都是 false
  • 都是相同长度、相同字符、按相同顺序排列的字符串
  • 都是相同对象(意味着都是同一个对象的值引用)
  • 都是数字且
    • 都是 +0
    • 都是 -0
    • 都是 NaN
    • 都是同一个值,非零且都不是 NaN

Object.is()== 不同。== 运算符在判断相等前对两边的变量(如果它们不是同一类型)进行强制转换(这种行为将 "" == false 判断为 true),而 Object.is 不会强制转换两边的值。

Object.is()=== 也不相同。差别是它们对待有符号的零和 NaN 不同,例如,=== 运算符(也包括 == 运算符)将数字 -0+0 视为相等,而将 Number.NaNNaN 视为不相等。

Object.freeze()

冻结一个对象。
不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值,对象的原型也不能被修改。
这个方法返回原对象,而不是创建一个被冻结的副本。
如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。数组作为一种对象,被冻结,其元素不能被修改。没有数组元素可以被添加或移除。

const obj = {
  age: 18,
  name: 'A',
  address: ['GX', 'DS']
}
console.log(Object.freeze(obj) === obj)
// obj.age = 20 // 报错
// delete obj.age // 报错
obj.address.push('SS') // 可以添加
obj.address.splice(0, 1) // 可以删除
// obj.address = [] // 报错

// 冻结一个数组
const arr = [1, 2, 3]
Object.freeze(arr)
arr.push(4) // 不能添加,当然也不能做其他修改

Object.isFrozen()

判断一个对象是否被冻结

Object.seal()

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

const obj = {
  age: 18,
  name: 'A'
}
Object.seal(obj)
delete obj.age // 不能删除属性,会报错
// obj.age = 20 // 添加属性,会报错

Object.isSealed()

判断一个对象是否被密封。
注意冻结对象也是一个密封对象。

Object.preventExtensions()

让一个对象变的不可扩展,也就是永远不能再添加新的属性。

const obj = {
  age: 18,
  name: 'A'
}
Object.preventExtensions(obj)
delete obj.age // 可以删除属性
obj.age = 20 // 添加属性则会报错

Object.isExtensible()

判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。\n
注意冻结对象也是一个不可扩展的对象。一个不可扩展的空对象同时也是一个冻结对象。

const obj = {
  age: 18,
  name: 'A'
}
Object.seal(obj)
console.log(Object.isSealed(obj)) // true
console.log(Object.isExtensible(obj)) // false密封属性同时也是不可以拓展的

const obj1 = {}
Object.preventExtensions(obj1)
console.log(Object.isFrozen(obj1)) // true 一个不可扩展的空对象同时也是一个冻结对象

Object.defineProperty()

语法:

Object.defineProperty(obj, prop, descriptor)
  • obj:要定义属性的对象。
  • prop:要定义或修改的属性的名称或 [Symbol]
  • descriptor:要定义或修改的属性描述符:
    • value:该属性对应的值。可以是任何有效的JavaScript值(数值,对象,函数等)。默认undefined
    • writable:为 true 时,属性的值,也就是value,才能被赋值运算符改变。 默认false
    • configurable:为true时,该属性的描述符才能够被改变和删除。 默认false
    • enumerable:为 true 时,该属性才会出现在对象的枚举属性中。默认false
    • get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。
      执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认 undefined
    • set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为undefined
function defineReactive(obj, key, val) {
  // 获取当前key的属性描述符
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }
  const getter = property && property.get
  const setter = property && property.set
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }
  return Object.defineProperty(obj, key, {
    get() {
      const value = getter ? getter.call(obj) : val
      return value
    },
    set(newVal) {
      val = newVal
    }
  })
}
let obj = { a: 10 }
defineReactive(obj, 'a')
console.log(obj.a)

Object.defineProperties()

在一个对象上定义新的属性或修改现有属性,并返回该对象。

let obj = {}
Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    value: 'Hello',
    writable: false
  }
})

Object.entries()

返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。

const obj = {
  name: 'abc',
  age: 18,
  [{}]: 'aa',
  [Symbol['address']]: 'China'
}

for (const [key, value] of Object.entries(obj)) {
  console.log(`${key}: ${value}`)
}
/**
  name: abc
  age: 18
  [object Object]: aa
  undefined: China
 */

Object.keys()

返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序与使用for...in 循环的顺序相同。

const obj = {
  name: 'abc',
  age: 18,
  [{}]: 'aa',
  [Symbol['address']]: 'China'
}

for (const key of Object.keys(obj)) {
  console.log(key)
}
/**
  name
  age
  [object Object]
  undefined
 */

Object.values()

返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in 循环的顺序相同。

const obj = {
  name: 'abc',
  age: 18,
  [{}]: 'aa',
  [Symbol['address']]: 'China'
}

for (const value of Object.values(obj)) {
  console.log(value)
}
/**
  abc
  18
  aa
  China
 */

实例方法

Object.prototype.hasOwnProperty()

返回一个布尔值,表示对象自身属性中是否具有指定的属性。

const parent = {
  key: 'aaa'
}
const obj = Object.create(parent)
obj.age = 18
console.log(obj.age) // 18
console.log(obj.hasOwnProperty('age')) // true
console.log(obj.key) // aaa
console.log(obj.hasOwnProperty('key')) // false
// 也可以使用 Object 原型上的 hasOwnProperty 属性
console.log(Object.prototype.hasOwnProperty.call(obj, 'age')) // true

Object.prototype.isPrototypeOf

返回一个布尔值,表示一个对象是否存在于另一个对象的原型链上。

function Parent() {}
function Child() {}

Child.prototype = Object.create(Parent.prototype)
const child = new Child()
console.log(Parent.prototype.isPrototypeOf(child)) // true
console.log(Child.prototype.isPrototypeOf(child)) // true
console.log(Object.prototype.isPrototypeOf(child)) // true

Object.prototype.toString()

返回一个表示该对象的字符串。
Object.prototype.toString() 返回 [object Type],这里的 Type 是对象的类型。如果对象有 Symbol.toStringTag 属性,其值是一个字符串,则它的值将被用作 Type。许多内置的对象,包括 MapSymbol,都有 Symbol.toStringTag。一些早于 ES6 的对象没有 Symbol.toStringTag,但仍然有一个特殊的标签。它们包括(标签与下面给出的类型名相同):

  • Array
  • Function(它的 typeof 返回 "function")
  • Error
  • Boolean
  • Number
  • String
  • Date
  • RegExp
console.log(Object.prototype.toString.call(1)) // [object Number]
console.log(Object.prototype.toString.call('')) // [object String]
console.log(Object.prototype.toString.call(true)) // [object Boolean]
console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(null)) // [object Null]
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call([])) // [object Array]
console.log(Object.prototype.toString.call(function () {})) // [object Function]
console.log(Object.prototype.toString.call(new Date())) // [object Date]
console.log(Object.prototype.toString.call(new RegExp(/\d/g))) // [object RegExp]
console.log(Object.prototype.toString.call(new Error())) // [object Error]
console.log(Object.prototype.toString.call(Symbol())) // [object Symbol]
console.log(Object.prototype.toString.call(123n)) // [object BigInt]

// 自定义
let obj = {
  [Symbol.toStringTag]: 'MyObj'
}
console.log(Object.prototype.toString.call(obj)) // [object MyObj]

Object.prototype.valueOf()

this 值转换为一个对象。此方法旨在用于自定义类型转换的逻辑时,重写派生类对象。

function MyNumberType(n) {
  this.number = n
}

MyNumberType.prototype.valueOf = function () {
  return this.number
}

const object1 = new MyNumberType(4)

console.log(object1 + 3) // 7

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容