全面介绍JavaScript的Object构造函数

3,348 阅读18分钟

随着JavaScript的发展,JavaScriptObject构造函数也增加了许多方法(自身方法和原型链方法。有必要全面了解一下。本文基本涵盖了下Object所有的属性和方法介绍。如果有遗漏,还请指出。

一些未列出的属性或方法是非标准的、不推荐使用的或者已经从Web标准中删除的,本文将不再进行介绍。

首先需要介绍一下JavaScript对象的属性描述符对象属性的可枚举性的概念。

JS属性描述符(属性描述对象)

创建对象的方式有三种:第一种,通过new操作符后面跟Object构造函数,第二种,对象字面量方式。第三种,使用Object.create()方法。如下:

const obj = {x: 5,y: 6}

const obj1 = new Object()
obj1.x = 5
obj2.x = 6

const obj2 = Object.create(Object.prototype, {
  x: {
    value: 5
  },
  y: {
    value: 6
  }
})

上面这三种方式创建出来的对象是一样的,有相同的属性。但是这些属性内部都有描述其行为的属性描述符,保存该属性的一些元信息。如下图:

如果要获得对象的属性描述符,可以通过Object.getOwnPropertyDescriptor()来获取对象中某个属性的属性描述符

const obj = { x: 5, y: 6 }
const desc = Object.getOwnPropertyDescriptor(obj, 'x')
/*  
  {   
    value: 5
    writable: true
    enumerable: true
    configurable: true
  }
*/
console.log(desc)

对象里目前存在的属性描述符有两种主要形式:数据属性描述符(data Property Descriptors )访问器(accessor Property Descriptors)属性描述符

属性描述符特性是为了实现 JavaScript 引擎用的,因此在 JavaScript 中不能直接访问它们。为了表示特性是内部值,该规范把它们放在了两对儿方括号中,例如[[Enumerable]]

数据属性描述符

数据属性描述符4个描述其行为的特性:

  1. [[Configurable]] : 表示能否通过delete删除属性,能否修改属性的特性,或者能否把属性修改为访问器属性描述符。一旦为false,就不能再设置它的(valuewritableconfigurable)。直接在对象上定义的属性默认值为true

  2. [[Enumerable]] : 表示能否能通过for-in,Object.keys(),JSON.stringify(),Object.assign()遍历属性。默认值为true

  3. [[Writable]] : 表示能否修改属性的值。如果为false,属性的值就不能被重写,只能为只读。默认值为true

  4. [[Value]] : 包含这个属性的值。读取属性值的时候,从这个位置读。写入属性值时,把新值保存在这个位置。默认值是 undefined

访问器属性描述符

访问器属性有4个描述其行为的特性:

  1. [[Configurable]] : 表示能否通过delete删除属性,能否修改属性的特性,或者能否把属性修改为数据属性描述符。一旦为false,就不能再设置它的(valuewritableconfigurable)。直接在对象上定义的属性默认值为true

  2. [[Enumerable]] : 表示能否能通过for-in,Object.keys(),JSON.stringify(),Object.assign()遍历属性。默认值为true

  3. [[Get]] : 在读取属性时调用的函数。默认值为undefined

  4. [[Set]] : 在写入属性时调用的函数。默认值为undefined

数据属性描述符和访问器属性描述符的区别

任何属性描述符都可以有名为[[Configurable]][[Enumerable]]的字段。数据属性描述符含有 [[Writable]][[Value]] 特性,访问器属性描述符含有[[Get]][[Set]]特性。

如下图所示,绿色代表该属性下可存在的特性,红色代表不可存在的特性。

[[Writable]][[Value]][[Get]][[Set]] 之间是互斥关系。因为一个属性,它不能既属于数据属性描述符,也属于访问器属性描述符。如果在 Object.defineProperty 中同时定义互斥特性会抛出异常。

JS属性的可枚举性

JavaScript对象的属性可分为可枚举不可枚举。它是由内部“可枚举”标志(enumerable)决定的,true 为可枚举,false为不可枚举。

对于通过直接的赋值和属性初始化的属性,该标识值默认为即为true,对于通过Object.definePropertyObject.create 等定义的属性,该标识值默认为false

const obj = { x: 5 }

Object.defineProperty(obj, 'y', {
  value: 6
})

const desc1 = Object.getOwnPropertyDescriptor(obj, 'x')

// {value: 5, writable: true, enumerable: true, configurable: true}
console.log(desc1)

const desc2 = Object.getOwnPropertyDescriptor(obj, 'y')

// {value: 6, writable: false, enumerable: false, configurable: false}
console.log(desc2)

可枚举的属性可以通过for...in循环进行遍历(除非该属性名是一个 Symbol)。

一、 Object 构造函数属性

Object.prototype

JavaScript规定,每个函数都有一个prototype属性,指向一个对象。所以Object构造函数也会有一个prototype属性。几乎所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOftoString方法的原因,因为这是从Object.prototype继承的。

Object.length

函数的 length 得到的是形参个数。所以Object.length的形参个数是1

function test1(a, b, c) { }
// 3
console.log(test1.length)

function test2(a, b, c, d) { }
// 4
console.log(test2.length)
// 1
console.log(Object.length)

Object.name

Object函数的name属性,返回该函数的函数名。

// Object
console.log(Object.name)

二、 Object 构造函数的方法

工具相关方法

Object.is()

Object.is()方法接收两个参数,判断两个值是否是相同的值。

传入一个参数或不传参的情况。

Object.is()             // true
Object.is(123)          // false
Object.is(undefined)    // true
Object.is(null)         // false

严格相等运算符(===)和Object.is()的区别。

+0 === -0               // true
NaN === NaN             // false

Object.is(+0, -0)       // false
Object.is(NaN, NaN)     // true

绝大多数情况下,Object.is()的结果与===运算符是相同的。除了+0,-0NaN这两种情况使用===Object.is()比较返回结果不同。

Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

Array.from()可以传入多个参数:

  • 第一个参数 target (必填):目标对象。
  • 第N个参数 source:源对象。

Object.assign(target, ...sources)

如果不传参数或者传入nullundefined都会抛出异常。

// Uncaught TypeError: Cannot convert undefined or null to object
Object.assign()
Object.assign(null)
Object.assign(undefined)

基本用法。

const target = { id: 1 }

const source1 = { name: 'zhangsan' }
const source2 = { age: 26 }

const newObj = Object.assign(target, source1, source2)

// {id: 1, name: "zhangsan", age: 26}defineProperty
console.log(newObj)

如果只传入一个参数,Object.assign会直接返回该参数。

const target = { id: 1, name: '刘德华' }

const newObj = Object.assign(target)
// true
console.log(newObj === target)

如果非对象参数出现在源对象的位置,这些参数都会转成对象,如果无法转成对象,就会跳过。如果undefinednull不在首参数,就不会报错。

const target = { id: 1, name: '刘德华' }
const newObj = Object.assign(target, 123,true)
// {id: 1, name: "刘德华"}
console.log(newObj)

const target1 = { id: 1, name: '刘德华' }
// 源对象是字符串的话会以数组形式拷贝到目标对象
const newObj1 = Object.assign(target1, '张学友')
// {0: "张", 1: "学", 2: "友", id: 1, name: "刘德华"}
console.log(newObj1)


// 其他值都不会产生效果
let target2 = { id: 1 };
Object.assign(target2, undefined) === target2   // true
Object.assign(target2, null) === target2        // true
Object.assign(target2, NaN) === target2         // true
Object.assign(target2, false) === target2       // true
Object.assign(target2, 10) === target2          // true

如果目标对象与源对象有同名属性,或多个源对象有同名属性,后面的属性就会覆盖前面的属性。

const target = { id: 1, name: '刘德华' }

const source1 = { name: '张学友', age: 50 }
const source2 = { age: 26 }

const newObj = Object.assign(target, source1, source2)

// {id: 1, name: "张学友", age: 26}
console.log(newObj)

Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性enumerable:false)。Object.assign方法是浅拷贝,而不是深拷贝。如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

获取和设置对象原型的相关方法

Object.create()

Object.create() 方法会使用指定的原型对象属性去创建一个新的对象。

Object.create()可以传入2个参数:

  1. 第一个参数 proto(必填):新创建对象的原型对象,不传会抛出异常。
  2. 第二个参数 propertiesObject(可选):要添加到新创建对象的属性描述符(新添加的属性是其自身的属性,而不是其原型链上的属性)。

如果不传参数,传入undefined或传入基本数据类型会抛出异常。

// Object prototype may only be an Object or null
Object.create(undefined)
Object.create(123)
Object.create('abc')

传入null的情况。

const obj = Object.create(null)
console.log(obj)

传入null的的时候,也就是将null设置成了新创建对象的原型,这个新对象就不会有原型链了。所以新对象是非常干净的对象。

使用对象自变量和直接使用 new Object() 创建对象。

const obj = {}
console.log(obj)

const obj1 = new Object()
console.log(obj1)

从上图可以看出,使用对象自变量和直接使用new Object()创建对象的时候,都会继承Object构造函数的原型对象。这也是它们和使用Object.create(null)创建出新对象的区别。

传入对象的情况。

// 自定义原型对象
const customPropertyObject = { id: 1, name: 'zhangsan' }
const obj = Object.create(customPropertyObject)
console.log(obj);

从上图可以看出 customPropertyObject被定义在了新创建对象的原型对象上,customPropertyObject又继承了Object构造函数的原型对象。

也可以直接使用来指定Object.create(Object.prototype)创建出和对象自变量一样的对象。

const obj = Object.create(Object.prototype)
console.log(obj)

这和通过 const obj = {} 直接创建对象是一样的效果。

传入2个参数。

const obj = Object.create({ id: 1 }, {
  name: {
    value: 'zhangsan',
    enumerable: true,
    configurable: true,
    writable: true,
  },
  age: {
    value: 20,
    enumerable: false,
    configurable: false,
    writable: false,
  }
})
console.log(obj)

从上图可以看到,第二个参数添加的属性是创建出的对象自身的属性。我们把age属性设置成了不可删除不可枚举不可修改的属性值。

obj.age = 1
delete obj.age

// id
// name
for (let prop in obj) {
  console.log(prop);
}

从上图可以看出,当修改,删除obj.age属性的时候是没有效果的,而且也没有办法通过for in循环出来。

第二个参数传入null会抛出异常。

// Uncaught TypeError:Cannot convert undefined or null to object
const obj = Object.create(null, null)

Object.getPrototypeOf()

Object.getPrototypeOf()方法返回指定对象的原型,如果没有继承属性,则返回 null

const obj = { id: 1, name: 'zhangsan' }
// 获取的是Object的原型对象,这里省略打印...
const propertyObj = Object.getPrototypeOf(obj)
// true
console.log(propertyObj === Object.prototype)
function Car() { }
const newCar = new Car()
// true
console.log(Object.getPrototypeOf(newCar) === Car.prototype)
// Object的原型对象上没有原型对象了,就返回了null
// null
console.log(Object.getPrototypeOf(Object.prototype));
// null
console.log(Object.getPrototypeOf({}.__proto__));

使用Object.create创建对象,并使用Object.getPrototypeOf()获取它的原型对象。

const obj = Object.create({ id: 1 })
const propertyObj = Object.getPrototypeOf(obj)
// {id: 1}
console.log(propertyObj)

Object.setPrototypeOf()

Object.setPrototypeOf()方法为指定对象设置原型,返回该指定对象。

Object.setPrototypeOf()可以传入2个参数:

  1. 第一个参数 obj(必填):要设置其原型的对象。
  2. 第二个参数 prototype(可选):该对象的新原型(一个对象 或 null)。
const son = { id: 1, name: 'zhangsan' }
// 要设置的原型对象
const father = { money: 100 }
const obj = Object.setPrototypeOf(son, father)
console.log(obj)

上图可以看出,Object.setPrototypeOf方法将对象son的原型,设置为对象father,因此son可以共享father的属性。

const obj = Object.setPrototypeOf({}, null)
// 会返回一个非常干净的空 {} 对象,没有继承任何原型对象。
console.log(obj)

如果传入错误参数类型,会抛出异常。

// Uncaught TypeError: Object prototype may only be an Object or null: undefined
const obj = Object.setPrototypeOf(1)
const obj = Object.setPrototypeOf(null)
const obj = Object.setPrototypeOf(undefined)


// 第二个参数:Uncaught TypeError: Object prototype may only be an Object or null
const obj = Object.setPrototypeOf({}, undefined)

Object操作属性描述符的相关方法

Object.defineProperty()

Object.defineProperty方法允许通过属性描述符(数据属性描述符访问器属性描述符),设置或修改一个属性,然后返回修改后的原对象。

Object.defineProperty()可以传入3个参数:

  1. 第一个参数 obj(必填):属性所在的对象。
  2. 第二个参数 prop(可选):属性名。
  3. 第三个参数 descriptor(必填):属性描述符。

Object.defineProperty设置属性的时候,如果属性不存在,则创建属性。如果属性已经存在,Object.defineProperty方法相当于更新该属性的属性描述对象

如果参数错误或不填,会抛出异常。

 // Uncaught TypeError: Object.defineProperty called on non-object
Object.defineProperty()
Object.defineProperty(1)

// Uncaught TypeError: Property description must be an object: undefined
Object.defineProperty({})

// Uncaught TypeError: Property description must be an object: 1
Object.defineProperty({}, 'abc', 1)
使用Object.defineProperty()定义数据属性描述符
const obj = { id: 1 }

const newObj = Object.defineProperty(obj, 'name', {
value: 'zhangsan',
writable: false,
enumerable: true,
configurable: true
})

// true
console.log(obj === newObj)

//{id: 1, name: "zhangsan"}
console.log(obj)

newObj.id = 10

// 不可修改,严格模式下会抛出异常
newObj.name = 'lisi'
//{id: 10, name: "zhangsan"}
console.log(obj)
使用Object.defineProperty()定义访问器属性描述符
const obj = { id: 1 }

Object.defineProperty(obj, 'name', {
  enumerable: true,
  configurable: true,
  set(newValue) {
    console.log('监听对象属性修改--->我的值是:' + newValue)

  },
  get() {
    console.log('获取对象属性');
    return '刘德华'  //先硬编码
  }
})

// 监听对象属性修改--->我的值是:zhangsan
obj.name = 'zhangsan'

// 获取对象属性
//刘德华
console.log(obj.name)

上面这个obj.name赋值或者取值的时候会分别触发 set 和 get 对应的函数。setget相当于监听函数。

模拟一个访问和设置的默认行为,达到我们正确的修改数据和访问数据是正确的。

const obj = { id: 1 }

// 内部 this 指向 obj
Object.defineProperty(obj, 'name', {
  enumerable: true,
  configurable: true,
  set(newValue) {
    this.name = newValue
  },
  get() {
    return this.name
  }
})

// Uncaught RangeError: Maximum call stack size exceeded
obj.name = 'zhangsan'

按照上面这么写的话会造成循环引用。obj.name = 'zhangsan' 会触发set函数,set函数内部 this.name = newValue又会触发set函数。然后无限调用....就抛出异常。需要定义一个新的属性解决问题。

const obj = { id: 1 }

// 内部 this 指向 obj
Object.defineProperty(obj, 'name', {
  enumerable: true,
  configurable: true,
  set(newValue) {
    this._name = newValue
  },
  get() {
    return this._name || undefined
  }
})

obj.name = 'zhangsan'

上面这样做法有一个缺点,就是obj对象里多了一个_name属性。

Object.defineProperties()

Object.defineProperties方法允许通过属性描述符数据属性描述符访问器属性描述符),定义或修改多个属性,然后返回修改后的原对象。

Object.defineProperties()可以传入2个参数:

  1. 第一个参数 obj(必填):属性所在的对象。
  2. 第二个参数 prop(可选):属性描述符对象。

如果参数错误或不填,会抛出异常。

 // Uncaught TypeError: Object.defineProperty called on non-object
Object.defineProperties()
Object.defineProperties(1,{})

// Cannot convert undefined or null to object
Object.defineProperties({})
Object.defineProperties({},null)
const obj = { id: 1 }

Object.defineProperties(obj, {
  name: { value: 'zhangsan', enumerable: true, writable: true },
  age: { value: 20, enumerable: true, writable: true },
})

// {id: 1, name: "zhangsan", age: 20}
console.log(obj)

注意:Object.defineProperty()Object.defineProperties()属性描述符对象,它的writableconfigurableenumerable这三个属性的默认值都为false

Object.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor()可以取得指定对象上一个自有属性(非继承属性)的描述符。如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回 undefined

Object.getOwnPropertyDescriptor()可以传入2个参数:

  1. 第一个参数 obj(必填):属性所在的对象。
  2. 第二个参数 prop(可选):属性名称。

如果不传参数,会抛出异常。

 // Uncaught TypeError: Cannot convert undefined or null to object
 Object.getOwnPropertyDescriptor()
 Object.getOwnPropertyDescriptor(null)
 Object.getOwnPropertyDescriptor(undefined)
const obj = { id: 1, name: 'zhangsan' }

Object.defineProperty(obj, 'name', {
  enumerable: true,
  configurable: true,
  get() {
    return 'get'
  },
  set() {
    return 'set'
  }
})

const descObj = Object.getOwnPropertyDescriptor(obj, 'id')

// {value: 1, writable: true, enumerable: true, configurable: true}
console.log(descObj)

// get和set是两个函数
// {enumerable: true, configurable: true, get: ƒ, set: ƒ}
const descObj1 = Object.getOwnPropertyDescriptor(obj, 'name')
console.log(descObj1);


// 因为toString是原型链上的对象,所以访问不到
// undefined
const descObj2 = Object.getOwnPropertyDescriptor(obj, 'toString')
console.log(descObj2);

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的属性描述符对象。如果没有任何自身属性,返回空对象。

Object.getOwnPropertyDescriptors()可以传入1个参数:

  1. 第一个参数 obj(必填):任意对象

如果不传参数或传入错误参数,会抛出异常。

 // Uncaught TypeError: Cannot convert undefined or null to object
 Object.getOwnPropertyDescriptors()
 Object.getOwnPropertyDescriptors(null)
 Object.getOwnPropertyDescriptors(undefined)
const obj = {
  id: 1,
  name: 'zhangsan'
};

const descObj = Object.getOwnPropertyDescriptors(obj)
/* {
  id:{
    value: 1,
    writable: true,
    enumerable: true,
    configurable: true
  },
  name: {
    value: 1,
    writable: true,
    enumerable: true,
    configurable: true
  }
}
*/
console.log(descObj)

Object.getOwnPropertyDescriptors()方法返回一个对象,所有原对象的属性名都是该对象的属性名,对应的属性值就是该属性的属性描述符对象

Object转换的相关方法

Object.keys()

Object.keys() 方法会返回由一个指定对象自身(非继承属性)可枚举属性组成的字符串数组。

const obj = {
  id: 1,
  name: 'zhangsan'
};

const props = Object.keys(obj)
// ["id", "name"]
console.log(props)

Object.keys()可以传入1个参数:

  1. 第一个参数 obj(必填):任意对象

如果不传参数,会抛出异常。

// Uncaught TypeError: Cannot convert undefined or null to object
Object.keys()
Object.keys(null)
Object.keys(undefined)
const obj = {
  id: 1,
  name: 'zhangsan'
};

const props = Object.keys(obj)
// ["id", "name"]
console.log(props)

const obj1 = { 100: 'a', 2: 'b', 7: 'c' };
// ['2', '7', '100']
console.log(Object.keys(obj1)); 

Object.values()

Object.values()方法返回由一个指定对象自身(非继承属性)可枚举属性值的数组。

Object.values()可以传入1个参数:

  1. 第一个参数 obj(必填):任意对象

如果不传参数,会抛出异常。

// Uncaught TypeError: Cannot convert undefined or null to object
Object.values()
Object.values(null)
Object.values(undefined)
const obj = {
  id: 1,
  name: 'zhangsan'
}
const newObj = Object.values(obj)
// [1, "zhangsan"]
console.log(newObj)

Object.entries()

Object.entries()方法返回由一个指定对象自身(非继承属性)可枚举属性的键值对数组。

Object.entries()可以传入1个参数:

  1. 第一个参数 obj(必填):任意对象

如果不传参数,会抛出异常。

// Uncaught TypeError: Cannot convert undefined or null to object
Object.entries()
Object.entries(null)
Object.entries(undefined)
const obj = {
  id: 1,
  name: 'zhangsan'
}
const newObj = Object.entries(obj)

// [['id',1],['name','zhangsan']]
console.log(newObj)

for (let [key, value] of Object.entries(obj)) {
  // id: 1
  // name: zhangsan
  console.log(`${key}: ${value}`);
}

Object.fromEntries()

Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。

Object.fromEntries()可以传入1个参数:

  1. 第一个参数 iterable(必填):可迭代对象,类似 ArrayMap 或者其它可迭代的对象。

如果不传参数或传入参数错误,会抛出异常。

// Uncaught TypeError: undefined is not iterable
Object.fromEntries()
Object.fromEntries(undefined)
Object.fromEntries(null)

// Uncaught TypeError: function is not iterable
Object.fromEntries(() => {})

// Uncaught TypeError:  Iterator value a is not an entry object
Object.fromEntries('abc')
const map = new Map([['id', 1], ['name', 'zhangsan']])
const obj = Object.fromEntries(map)
// {id: 1, name: "zhangsan"}
console.log(obj)

const obj1 = Object.fromEntries([['id', 1], ['name', 'zhangsan']])
// {id: 1, name: "zhangsan"}
console.log(obj1)

Object.getOwnPropertyNames()

Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性(非继承属性)的属性名(包括不可枚举属性不包括Symbol值作为名称的属性)组成的字符串数组。

Object.getOwnPropertyNames()可以传入1个参数:

  1. 第一个参数 obj(必填):任意对象。

如果不传参数或传入参数错误,会抛出异常。

// Uncaught TypeError: Cannot convert undefined or null to object
Object.getOwnPropertyNames()
Object.getOwnPropertyNames(undefined)
Object.getOwnPropertyNames(null)
const obj = { id: 1, name: 'zhangsan' }
const arr = Object.getOwnPropertyNames(obj)
// ["id", "name"]
console.log(arr)

Object.getOwnPropertySymbols()

Object.getOwnPropertySymbols()方法返回一个指定对象自身的所有Symbol属性的数组。所有的对象在初始化的时候不会包含任何的Symbol,除非你在对象上赋值了Symbol否则Object.getOwnPropertySymbols()只会返回一个空的数组。

Object.getOwnPropertySymbols()可以传入1个参数:

  1. 第一个参数 obj(必填):任意对象。

如果不传参数或传入参数错误,会抛出异常。

// Uncaught TypeError: Cannot convert undefined or null to object
Object.getOwnPropertySymbols()
Object.getOwnPropertySymbols(undefined)
Object.getOwnPropertySymbols(null)
const obj = { id: 1, name: 'zhangsan' }
obj[Symbol('age')] = 20
const arr = Object.getOwnPropertySymbols(obj)

// [Symbol(age)]
console.log(arr);

Object对象的防篡改相关方法

Object.preventExtensions()

Object.preventExtensions()方法让一个对象变的不可扩展,永远不能再添加新的属性。返回已经不可扩展的原对象。

Object.preventExtensions()可以传入1个参数:

  1. 第一个参数 obj :任意对象。
const obj = { id: 1, name: 'zhangsan' }
const newObj = Object.preventExtensions(obj)

// 在严格模式下,会抛出异常。
obj.age = 20

// {id: 1, name: "zhangsan"}
console.log(obj)
// true
console.log(obj === newObj)

Object.isExtensible()

Object.isExtensible()方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。返回true是可扩展的。

Object.isExtensible()可以传入1个参数:

  1. 第一个参数 obj :任意对象。
const obj = { id: 1, name: 'zhangsan' }

// true
console.log(Object.isExtensible(obj))

Object.preventExtensions(obj)

// false
console.log(Object.isExtensible(obj))

Object.seal()

Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置([[Configurable]]设置为false)。当前属性的值只要封闭之前是可写的就还是可写的。返回被密封的的原对象。

Object.seal()可以传入1个参数:

  1. 第一个参数 obj :任意对象。
const obj = { id: 1, name: 'zhangsan' }
Object.seal(obj)

// 不能新增, 严格模式下抛出异常
obj.age = 20

// 不能删除,严格模式下抛出异常
delete obj.id

Object.isSealed()

Object.isSealed() 方法判断一个对象是否被密封。返回true是被密封的。

Object.isSealed()可以传入1个参数:

  1. 第一个参数 obj :任意对象。

Object.freeze()

Object.freeze() 方法冻结一个对象。一个被冻结的对象再也不能被修改。冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改已有属性的值。也不能修改该对象已有属性的可枚举性、可配置性、可写性,以及。并且冻结一个对象后该对象的原型也不能被修改。freeze()返回原对象。

Object.freeze()可以传入1个参数:

  1. 第一个参数 obj :任意对象。
const obj = { id: 1, name: 'zhangsan',house: { 'beijing': 2 } }

Object.freeze(obj)

// 不能新增属性, 严格模式下抛出异常
obj.age = 20

// 不能删除属性,严格模式下抛出异常
delete obj.id

// 不能修改属性,严格模式下抛出异常
obj.id = 20

// 不能修改原型链,严格模式下抛出异常
obj.__proto__ = {}

// 不能修改属性描述符,严格模式下抛出异常
Object.defineProperty(obj, 'id', {
  enumerable: false
})

// 如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。
obj.house.beijing = 3
// 3 
console.log(obj.house.beijing)

被冻结对象自身的所有属性几乎都不可能以任何方式被修改。

Object.isFrozen()

Object.isFrozen()方法判断一个对象是否被冻结。返回true是被冻结的。

Object.isFrozen()可以传入1个参数:

  1. 第一个参数 obj:任意对象。
const obj = { id: 1, name: 'zhangsan' }
Object.freeze(obj)
// true
console.log(Object.isFrozen(obj))

三、 Object 实例对象(Object 原型)的属性和方法

Object.prototype.constructor

prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。因为Object是一个函数,所以它的原型对象上的constructor属性就是Function

// true
console.log(Object.__proto__.constructor === Function)

Object.prototype.hasOwnProperty()

对象实例的hasOwnProperty方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。

Object.prototype.hasOwnProperty()可以传入1个参数:

  1. 第一个参数 obj :要检测的属性的字符串名称,或者 Symbol
const obj = { id: 1, name: 'zhangsan' }

// true
console.log(obj.hasOwnProperty('id'))
// false
console.log(obj.hasOwnProperty('toString'))

Object.prototype.isPrototypeOf()

对象实例的isPrototypeOf()方法用来判断该对象是否为参数对象的原型。

Object.prototype.isPrototypeOf()可以传入1个参数:

  1. 第一个参数obj :在该对象的原型链上搜索
var father = { money: 100 };
var son = Object.create(father);
// true 儿子的原型是爸爸
console.log(father.isPrototypeOf(son))


//由于Object.prototype处于原型链的最顶端,所以对各种实例都返回true,只有直接继承自null的对象除外

Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false

Object.prototype.propertyIsEnumerable()

对象实例的propertyIsEnumerable()方法返回一个布尔值,表示指定的属性是否可枚举。

Object.prototype.对象实例的propertyIsEnumerable()可以传入1个参数:

  1. 第一个参数prop:属性名
const obj = { id: 1, name: 'zhangsan' }

Object.defineProperty(obj, 'age', {
enumerable: false
})
// true
console.log(obj.propertyIsEnumerable('id'))
// false
console.log(obj.propertyIsEnumerable('age'))
// false
console.log(obj.propertyIsEnumerable('toString'))

Object.prototype.toLocaleString()

对象实例的toLocaleString() 方法返回一个该对象的字符串表示。Object toLocaleString 返回的是调用 toString() 的结果。

const obj = { id: 1, name: 'zhangsan' }

// [object Object]
console.log(obj.toLocaleString())

Object.prototype.toString()

对象实例的toString() 方法返回一个表示该对象的字符串。

toString() 检测对象类型。

var toString = Object.prototype.toString;

console.log(toString.call(new Date()))  //  [object Date]
console.log(toString.call({}))          //  [object Object]
console.log(toString.call(''))          //  [object String]

Object.prototype.valueOf()

对象实例的 valueOf() 方法返回指定对象的原始值。

const emptyObject = {}
// true
console.log(emptyObject.valueOf() === emptyObject)

const arr = []
// true
console.log(arr.valueOf() === arr)

参考

developer.mozilla.org/zh-CN/docs/…

book.douban.com/subject/105…

es6.ruanyifeng.com/#docs/objec…

wangdoc.com/javascript/…

ddcode.net/2019/05/31/…

blog.gcl666.com/2019/04/22/…

javascript.ruanyifeng.com/stdlib/attr…

tc39.es/ecma262/#se…

tc39.es/ecma262/#se…