第六章 标准库 6.1 Object 类型

6.1 Object 类型

Object 是一个内置的构造函数,它充当了所有对象的基类。JavaScript 中的所有对象,包括数组、函数、日期等等,都是由 Object 构造函数创建的。
Object 类可以用于创建一个空对象,也可以用于创建一个带有属性和方法的对象。在创建对象时,可以通过直接使用对象字面量的方式创建,也可以通过 new 关键字和 Object 构造函数来创建。例如:

// 使用对象字面量创建一个空对象
const emptyObject = {};








// 使用 Object 构造函数创建一个空对象
const anotherEmptyObject = new Object();








// 使用对象字面量创建一个带有属性和方法的对象
const myObject = {
  name: 'Alice',
  age: 30,
  greet: function () {
    console.log(
      `Hello, my name is ${this.name} and I am ${this.age} years old.`,
    );
  },

};


// 使用 Object 构造函数创建一个带有属性和方法的对象
const anotherObject = new Object({
  name: 'Bob',
  age: 40,
  greet: function () {
    console.log(
      `Hello, my name is ${this.name} and I am ${this.age} years old.`,
    );
  },
});

我们通常用对象字面量的方式创建对象。

下面介绍一些 Object 类常用的静态方法和实例方法。

Object.defineProperty

在之前章节的学习中,我们学习到给对象添加属性,可以在构造函数中,也可以给对象直接添加属性,而使用 Object.defineProperty 则是可以更定制化的控制对象的属性,它接受三个参数:

  • 1 obj:需要定义属性的对象。
  • 2 prop:需要定义的属性名。
  • 3 descriptor:一个对象,包含要定义的属性的配置。
    descriptor 参数是一个对象,其中可以包含以下属性:
  • 1 value:属性的值。默认为 undefined。
  • 2 writable:是否可写。默认为 false。
  • 3 enumerable:是否可枚举。默认为 false。
  • 4 configurable:是否可配置。默认为 false。
  • 5 get:获取属性值的函数。
  • 6 set:设置属性值的函数。
    下面是一个简单的示例:
const obj = {};



Object.defineProperty(obj, 'x', {
  value: 1,
  writable: false,
  enumerable: true,
  configurable: true,
});





console.log(obj.x); // 1
obj.x = 2; // 报错,因为 writable 为 false
console.log(obj.x); // 1
console.log(Object.keys(obj)); // ["x"]
delete obj.x; // 报错,因为 configurable 为 false

在这个示例中,我们先定义了一个空对象 obj,然后使用 Object.defineProperty() 方法定义了一个名为 x 的属性,其值为 1,不可写,可枚举,可配置。然后我们打印了 obj.x 的值,输出为 1。接着我们试图将 obj.x 的值改为 2,但因为 writable 为 false,所以会抛出一个错误,obj.x 的值仍为 1。然后我们使用 Object.keys() 方法获取了 obj 的属性键名数组,输出为 [“x”]。最后我们试图删除 obj.x 属性,但因为 configurable 为 false,所以会抛出一个错误。
需要注意的是,如果要修改已有属性的配置,需要将 configurable 设置为 true,否则会抛出一个错误。另外,一旦将属性的 configurable 设置为 false,就无法再将它设置为 true,即无法重新定义该属性的配置。因此,使用 Object.defineProperty() 方法时需要谨慎。
通过上面的例子我们应该学习到了 value, writable, enumerable, configurable 的作用。

下面再看看 get 和 set 的使用。
Object.defineProperty() 方法的 descriptor 参数中,可以通过 get 和 set 属性为属性定义 getter 和 setter 方法。下面是一个例子,展示如何使用 get 和 set 定义一个属性,使得每次读取该属性时都会自动计算并返回当前时间戳:

const obj = {};



Object.defineProperty(obj, 'timestamp', {
  get: function () {
    return Date.now();
  },
});



console.log(obj.timestamp); // 当前时间戳

在这个例子中,我们首先创建了一个空对象 obj,然后使用 Object.defineProperty() 方法为其定义了一个名为 timestamp 的属性,其中 get 属性被设置为一个函数,该函数返回 Date.now(),即当前时间戳。这样,每次读取 obj.timestamp 属性时,都会调用这个函数来计算当前时间戳,并将其作为属性的值返回。
除了 get,我们还可以使用 set 方法来定义属性的 setter 方法。下面是一个例子,展示如何使用 set 和 get 定义一个属性,使得每次设置该属性时都会自动打印一条消息:

const obj = {};



let value;
Object.defineProperty(obj, 'message', {
  get: function () {
    return value;
  },
  set: function (newValue) {
    console.log('Setting message to ' + newValue);
    value = newValue;
  },
});


obj.message = 'Hello, World!'; // 打印 "Setting message to Hello, World!"
console.log(obj.message); // "Hello, World!"

在这个例子中,我们首先创建了一个空对象 obj,然后定义了一个名为 message 的属性,并分别为其定义了 get 和 set 方法。当设置 message 属性时,set 方法会被调用,并打印一条消息。当读取 message 属性时,get 方法会被调用,并返回属性的值。在示例中,我们首先将 obj.message 设置为 “Hello, World!”,这会触发 set 方法并打印一条消息。然后我们再次读取 obj.message 的值,这次会触发 get 方法并返回 “Hello, World!”。
如果同时设置了 value 和 get 或 set,则会报错,错误如下:

Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>

Object.keys

Object.keys()方法可以返回一个对象自身所有可枚举属性的键名数组。
具体来说,它接收一个对象作为参数,然后返回该对象自身所有可枚举属性的键名数组,这些键名都是字符串类型的。
下面是一个简单的示例:

const obj = { a: 1, b: 2, c: 3 };


const keys = Object.keys(obj);








console.log(keys); // ["a", "b", "c"]

在这个示例中,我们先定义了一个包含三个属性的对象 obj,然后调用 Object.keys(obj) 方法,得到了一个由键名组成的数组 [“a”, “b”, “c”]。注意,这个数组中的元素的顺序并不一定和定义对象时属性的顺序相同。
需要注意的是,Object.keys() 方法只会返回对象自身的可枚举属性的键名,不包括继承的属性和不可枚举的属性。如果想要获取包括继承属性在内的所有属性,可以使用 for…in 循环。

function Parent() {


  this.a = 1;


}







Parent.prototype.b = 2;










const child = new Parent();







console.log(Object.keys(child)); // ["a"]
for (let key in child) {


  console.log(key); // "a", "b"
}


在这个示例中,我们定义了一个构造函数 Parent,它有两个属性 a 和 b,其中 a 是自身属性,b 是继承属性。然后我们通过 new 关键字创建了一个新的对象 child,它继承了 Parent 的属性。
我们使用 Object.keys() 方法和 for…in 循环分别输出了 child 对象的属性,可以看到 Object.keys() 只返回了自身属性 a 的键名数组,而 for…in 循环则可以遍历到所有的属性,包括继承属性 b。

Object.values

Object.values 可以返回一个对象自身所有可枚举属性的值的数组。
具体来说,它接收一个对象作为参数,然后返回该对象自身所有可枚举属性的值的数组,这些值的顺序与 Object.keys() 方法返回的键名数组相同。
下面是一个简单的示例:

const obj = { a: 1, b: 2, c: 3 };


const values = Object.values(obj);








console.log(values); // [1, 2, 3]

在这个示例中,我们先定义了一个包含三个属性的对象 obj,然后调用 Object.values(obj) 方法,得到了一个由值组成的数组 [1, 2, 3]。注意,这个数组中的元素的顺序与 Object.keys(obj) 返回的键名数组相同。
需要注意的是,Object.values() 方法只会返回对象自身的可枚举属性的值,不包括继承的属性和不可枚举的属性。如果想要获取包括继承属性在内的所有属性的值,可以使用 for…in 循环。

function Parent() {


  this.a = 1;


}







Parent.prototype.b = 2;










const child = new Parent();







console.log(Object.values(child)); // [1]
for (let key in child) {


  console.log(child[key]); // 1, 2
}


在这个示例中,我们定义了一个构造函数 Parent,它有两个属性 a 和 b,其中 a 是自身属性,b 是继承属性。然后我们通过 new 关键字创建了一个新的对象 child,它继承了 Parent 的属性。
我们使用 Object.values() 方法和 for…in 循环分别输出了 child 对象的属性值,可以看到 Object.values() 只返回了自身属性 a 的值的数组,而 for…in 循环则可以遍历到所有的属性,包括继承属性 b。
总之,Object.values() 是一个方便获取对象属性值的方法,它可以用来遍历对象属性、获取对象属性的数量等等。

Object.entries

Object.entries()可以返回一个对象自身所有可枚举属性的键值对的数组。
具体来说,它接收一个对象作为参数,然后返回该对象自身所有可枚举属性的键值对的数组,每个键值对都是一个由两个元素组成的数组,第一个元素是属性的键名,第二个元素是属性的值。
下面是一个简单的示例:

const obj = { a: 1, b: 2, c: 3 };


const entries = Object.entries(obj);








console.log(entries); // [["a", 1], ["b", 2], ["c", 3]]

在这个示例中,我们先定义了一个包含三个属性的对象 obj,然后调用 Object.entries(obj) 方法,得到了一个由键值对组成的数组 [[“a”, 1], [“b”, 2], [“c”, 3]]。注意,这个数组中的元素的顺序与 Object.keys(obj) 方法返回的键名数组相同。
需要注意的是,Object.entries() 方法只会返回对象自身的可枚举属性的键值对,不包括继承的属性和不可枚举的属性。如果想要获取包括继承属性在内的所有属性的键值对,可以使用 for…in 循环。

function Parent() {


  this.a = 1;


}







Parent.prototype.b = 2;










const child = new Parent();







console.log(Object.entries(child)); // [["a", 1]]
for (let key in child) {


  console.log([key, child[key]]); // ["a", 1], ["b", 2]
}


在这个示例中,我们定义了一个构造函数 Parent,它有两个属性 a 和 b,其中 a 是自身属性,b 是继承属性。然后我们通过 new 关键字创建了一个新的对象 child,它继承了 Parent 的属性。
我们使用 Object.entries() 方法和 for…in 循环分别输出了 child 对象的属性键值对,可以看到 Object.entries() 只返回了自身属性 a 的键值对的数组,而 for…in 循环则可以遍历到所有的属性,包括继承属性 b。
总之,Object.entries() 是一个方便获取对象属性键值对的方法,它可以用来遍历对象属性、获取对象属性的数量等等。

Object.assign

Object.assign() 方法用于将一个或多个源对象的所有可枚举属性复制到目标对象中,并返回目标对象。该方法的语法如下:
Object.assign(target, source1, source2, ...)
其中,target 是目标对象,source1、source2 等是源对象。如果源对象中存在与目标对象中同名的属性,则后面的源对象会覆盖前面的源对象。
下面是一个使用 Object.assign() 方法复制对象属性的例子:

const target = { x: 1 };
const source = { y: 2 };
const result = Object.assign(target, source);





console.log(target); // { x: 1, y: 2 }
console.log(source); // { y: 2 }
console.log(result); // { x: 1, y: 2 }
console.log(target === result); // true

在这个例子中,我们创建了一个名为 target 的目标对象,其中包含一个名为 x 的属性。然后,我们创建了一个名为 source 的源对象,其中包含一个名为 y 的属性。最后,我们使用 Object.assign() 方法将源对象的所有属性复制到目标对象中,并将结果保存在 result 变量中。目标对象 target 现在包含了源对象 source 中的所有属性,并且返回的结果也是目标对象 target。注意,Object.assign() 方法并不会复制源对象的原型属性。
需要注意的是,Object.assign() 方法会忽略源对象中值为 null 或 undefined 的属性。此外,如果源对象的某个属性是一个对象,那么该对象的引用会被复制到目标对象中,而不是该对象的副本。因此,如果源对象和目标对象中存在相同的引用类型属性,那么对其中一个对象中的该属性进行修改也会影响到另一个对象中的该属性。
下面是一个例子,演示了 Object.assign() 方法忽略源对象中值为 null 或 undefined 的属性:

const target = {};

const source = { a: 1, b: null, c: undefined };
Object.assign(target, source);

console.log(target); // { a: 1 }

在这个例子中,我们创建了一个空的目标对象 target,和一个包含三个属性的源对象 source,其中属性 b 的值为 null,属性 c 的值为 undefined。然后我们使用 Object.assign() 方法将源对象的属性复制到目标对象中,可以看到,目标对象 target 只包含了源对象 source 中值为非 null 和 undefined 的属性 a。
接下来是一个例子,演示了 Object.assign() 方法复制引用类型属性的行为:

const target = {};

const source = { a: { x: 1 } };
Object.assign(target, source);






console.log(target); // { a: { x: 1 } }
console.log(target.a === source.a); // true



target.a.x = 2;
console.log(source.a); // { x: 2 }

在这个例子中,我们创建了一个空的目标对象 target,和一个包含一个引用类型属性 a 的源对象 source,其中属性 a 的值是一个包含属性 x 的对象。然后我们使用 Object.assign() 方法将源对象的属性复制到目标对象中,
可以看到,目标对象 target 中的属性 a 的引用和源对象 source 中的属性 a 的引用是相同的。
接下来,我们将目标对象 target 中的属性 a 的 x 属性的值修改为 2,并输出源对象 source 中的属性 a,可以看到,修改目标对象 target 中的属性 a 的 x 属性的值,也会影响到源对象 source 中的属性 a。因为它们都指向了同一个引用类型对象。

Object.create

Object.create(proto, [propertiesObject]) 是一个创建一个新对象的方法,新对象的原型链指向 proto,并且可以根据 propertiesObject 参数定义新对象的属性和特性。
下面是 Object.create() 方法的参数说明:

  • 1 proto:要创建的新对象的原型链指向的对象。
  • 2 propertiesObject(可选):定义新对象的属性和特性的对象。它的属性可以是数据属性或访问器属性,类似于 Object.defineProperties() 方法的第二个参数。如果不需要定义属性和特性,则可以省略该参数。
    下面是一个例子,演示了如何使用 Object.create() 方法创建一个新对象,并定义新对象的属性和特性:
const proto = { a: 1 };


const obj = Object.create(proto, {
  b: {
    value: 2,
    writable: true,
    enumerable: true,
    configurable: true,
  },
  c: {
    get() {
      return this.a + this.b;
    },
    enumerable: true,
    configurable: true,
  },

});


console.log(obj.a); // 1
console.log(obj.b); // 2
console.log(obj.c); // 3

在这个例子中,我们创建了一个原型对象 proto,它有一个属性 a,值为 1。然后我们使用 Object.create() 方法创建了一个新对象 obj,并将其原型链指向 proto。同时,我们使用 propertiesObject 参数定义了 obj 的两个属性:b 和 c。其中,属性 b 的值为 2,属性 c 是一个访问器属性,返回 obj.a + obj.b 的值。这两个属性的特性也分别设置为可写、可枚举和可配置。
可以看到,新对象 obj 中的属性 a 继承自原型对象 proto,属性 b 是自身的属性,属性 c 是一个访问器属性,它的值是通过 obj.a 和 obj.b 计算得出的。

Object.getPrototypeOf

Object.getPrototypeOf() 方法是 Object 对象的静态方法,用于获取一个对象的原型对象(即 [[Prototype]])。
Object.getPrototypeOf() 方法的语法如下:
Object.getPrototypeOf(obj)
其中,obj 是要获取原型对象的对象。
如果 obj 存在原型对象,则返回该对象的原型对象,否则返回 null。
下面是一个例子,演示了如何使用 Object.getPrototypeOf() 方法获取一个对象的原型对象:

const proto = { a: 1 };


const obj = Object.create(proto);









console.log(Object.getPrototypeOf(obj) === proto); // true

在这个例子中,我们创建了一个原型对象 proto,它有一个属性 a。然后我们使用 Object.create() 方法创建了一个新对象 obj,并将其原型链指向 proto。最后,我们使用 Object.getPrototypeOf() 方法获取 obj 的原型对象,并将其与 proto 进行比较,可以发现它们是相等的,因此输出结果为 true。
需要注意的是,如果要获取的对象不是一个对象(例如 null 或 undefined),则会抛出一个类型错误。
在之前讲原型链和继承的章节还提到了ptoto属性, Object.getPrototypeOf() 方法和 proto 属性都可以用于获取一个对象的原型对象,但它们之间有一些区别。虽然 proto 属性比 Object.getPrototypeOf() 方法更加直观和便捷,但是在实际开发中,建议尽量避免使用 proto 属性,因为它不是标准的属性,在一些浏览器中可能会存在兼容性问题。而 Object.getPrototypeOf() 方法则是标准的方法,具有更好的可靠性和稳定性。
下面是一个例子,演示了如何使用 Object.getPrototypeOf() 方法和 proto 属性获取一个对象的原型对象:

const proto = { a: 1 };


const obj = Object.create(proto);









console.log(Object.getPrototypeOf(obj) === proto); // true

console.log(obj.__proto__ === proto); // true

在这个例子中,我们创建了一个原型对象 proto,它有一个属性 a。然后我们使用 Object.create() 方法创建了一个新对象 obj,并将其原型链指向 proto。最后,我们使用 Object.getPrototypeOf() 方法和 proto 属性分别获取 obj 的原型对象,并将其与 proto 进行比较,可以发现它们是相等的,因此输出结果为 true。这里再说一下 [[Prototype]] 和 proto 的区别:
[[Prototype]] 和 proto 都是 JavaScript 中用于实现对象之间继承关系的机制,它们之间的区别如下:
JavaScript 中的对象可以有一个指向另一个对象的引用,该对象就是该对象的原型。这个引用存储在对象的内部属性 [[Prototype]] 中,称为对象的原型链。
同时,JavaScript 还提供了一个 proto 属性,用于访问对象的原型。在代码中,我们可以通过 obj.proto 的方式来获取 obj 的原型。需要注意的是,proto 属性并不是标准的 JavaScript 属性,而是浏览器对 JavaScript 的实现,可以通过它来访问和修改对象的原型。
[[Prototype]] 和 proto 实际上是相互关联的。对象的 proto 属性指向该对象的原型,也就是该对象的 [[Prototype]] 属性所指向的对象。我们可以通过 Object.getPrototypeOf(obj) 方法来获取一个对象的原型,该方法和访问 obj.proto 属性是等价的。
在访问对象的属性时,如果该对象本身没有该属性,则会沿着对象的原型链向上查找,直到找到该属性或者到达原型链的顶端(即 Object.prototype)。如果没有找到该属性,则返回 undefined。
需要注意的是,[[Prototype]] 属性只能在对象创建时进行设置,而且不是所有的 JavaScript 引擎都支持直接访问 [[Prototype]] 属性。因此,我们通常使用 Object.create() 方法来创建对象并指定原型,或者使用 Object.setPrototypeOf() 方法来修改对象的原型。而 proto 属性可以在运行时进行访问和修改,但是不建议在生产环境中使用它。
最后,需要注意的是,在 ES6 标准中,推荐使用 Object.getPrototypeOf() 和 Object.setPrototypeOf() 方法来访问和修改对象的原型,而不是使用 proto 属性。 下面举一个例子:

// 定义一个父对象
const parent = {
  name: 'Parent',
};




// 定义一个子对象,并将其原型链指向父对象
const child = Object.create(parent);





// 输出 child 对象的 __proto__ 属性和 parent 对象的 [[Prototype]] 属性
console.log(child.__proto__ === parent); // true
console.log(Object.getPrototypeOf(child) === parent); // true


// 将 child 对象的 __proto__ 属性指向一个新对象
const other = { name: 'Other' };
child.__proto__ = other;

// 输出 child 对象的 __proto__ 属性和 parent 对象的 [[Prototype]] 属性
console.log(child.__proto__ === other); // true
console.log(Object.getPrototypeOf(child) === other); // true
console.log(Object.getPrototypeOf(child) === parent); // false

Object.setPrototypeOf

Object.setPrototypeOf() 方法可以用来设置一个对象的原型(即 [[Prototype]] 属性),它接受两个参数:第一个参数是要设置原型的对象,第二个参数是新的原型对象。语法如下:
Object.setPrototypeOf(obj, prototype)
其中,obj 是要设置原型的对象,prototype 是新的原型对象。这个方法会将 obj 的原型设置为 prototype,如果 prototype 参数不是对象或者是 null,则会抛出一个 TypeError 错误。
下面是一个使用 Object.setPrototypeOf() 方法设置原型的示例:

const obj = { foo: 1 };
const protoObj = { bar: 2 };
Object.setPrototypeOf(obj, protoObj);
console.log(obj.bar); // 输出 2

在这个例子中,我们先创建了一个对象 obj,它有一个属性 foo。然后,我们使用 Object.setPrototypeOf() 方法将 obj 的原型设置为 protoObj,也就是 obj 继承了 protoObj 的属性和方法。最后,我们访问 obj.bar 属性,它的值为 2。

Object.getOwnPropertyNames

Object.getOwnPropertyNames() 方法可以用来获取一个对象自身的所有属性名,无论这些属性是否可枚举,但是不包括继承的属性名。它的语法如下:
Object.getOwnPropertyNames(obj)
其中,obj 是要获取属性名的对象。这个方法会返回一个包含 obj 所有属性名的数组,顺序与使用 for…in 循环遍历对象属性时的顺序一致。注意,Object.getOwnPropertyNames() 方法只返回对象自身的属性名,不包括继承的属性名。
下面是一个使用 Object.getOwnPropertyNames() 方法获取对象属性名的示例:

const obj = {



  foo: 'hello',
  bar: 'world',
};

const propertyNames = Object.getOwnPropertyNames(obj);
console.log(propertyNames); // 输出 ["foo", "bar"]

在这个例子中,我们创建了一个对象 obj,它有两个属性 foo 和 bar。然后,我们使用 Object.getOwnPropertyNames() 方法获取 obj 的所有属性名,并将它们打印出来。最终,输出的是一个包含 foo 和 bar 的数组。

Object.freeze

Object.freeze() 方法可以冻结一个对象,使得该对象无法添加、删除或修改属性。当一个对象被冻结后,它的所有属性都变成只读的,并且不能再被修改。
该方法的语法如下:
Object.freeze(obj)
其中,obj 是要冻结的对象。该方法返回冻结后的对象。
需要注意的是,Object.freeze() 方法只冻结对象的一级属性,如果对象的属性值是一个对象,那么这个对象的属性仍然可以被修改。如果想要冻结整个对象及其子对象,需要递归地使用 Object.freeze() 方法。
下面是一个使用 Object.freeze() 方法冻结对象的示例:

const obj = {



  foo: {
    bar: 'hello',
  },
  baz: 'world',
};



Object.freeze(obj);


obj.baz = 'hi'; // 尝试修改属性
obj.foo.bar = 'hi'; // 尝试修改子对象的属性
console.log(obj.baz); // 输出 "world"
console.log(obj.foo.bar); // 输出 "hi"

在这个例子中,我们创建了一个对象 obj,它有两个属性 foo 和 baz。其中,foo 属性的值是一个包含一个属性 bar 的对象。然后,我们使用 Object.freeze() 方法冻结了 obj。接着,我们尝试修改 obj 的 baz 属性的值和 foo 属性的 bar 属性的值,但由于 obj 被冻结后,这些操作没有成功。最终,打印出的值分别是 world 和 hi。
需要注意的是,Object.freeze() 方法只冻结对象的一级属性,即只对 obj 对象本身的属性进行冻结。在这个例子中,虽然我们冻结了 obj 对象,但是它的 foo 属性并没有被冻结,因此 obj.foo.bar 的值仍然可以被修改。如果想要冻结整个对象及其子对象,需要递归地使用 Object.freeze() 方法。

Object.is

Object.is() 方法用于比较两个值是否相等。Object.is() 方法在比较时可以处理一些特殊情况,例如处理 NaN 值和 -0。
Object.is() 方法的语法如下:
Object.is(value1, value2)
其中,value1 和 value2 是要比较的两个值。
Object.is() 方法返回一个布尔值,如果 value1 和 value2 相等,则返回 true,否则返回 false。
它与===基本相同,但是有以下 2 种情况和===不一样:

  • 1 NaN 等于 NaN
  • 2 -0 不等于 +0
    下面是一些示例:
Object.is(1, 1); // true
Object.is(1, '1'); // false
Object.is('foo', 'foo'); // true
Object.is([], []); // false
Object.is(NaN, NaN); // true
Object.is(-0, +0); // false

Object.preventExtensions

Object.isExtensible

Object.isExtensible() 方法用于判断一个对象是否可扩展,即是否可以添加新属性。如果对象不可扩展,那么不能添加新的属性,但可以修改和删除现有属性。
语法:Object.isExtensible(obj)
参数:obj:要判断的对象。
返回值:返回一个布尔值,表示对象是否可扩展。如果对象可扩展,则返回 true,否则返回 false。
Object.preventExtensions() 方法用于将一个对象设置为不可扩展,即无法添加新的属性。已有属性可以修改或删除。
语法:Object.preventExtensions(obj)
参数:obj:要设置为不可扩展的对象。
返回值:返回被传入的对象。

const obj = { a: 1 };
console.log(Object.isExtensible(obj)); // true








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








obj.b = 2; // 无法添加新的属性,不会报错,但操作无效
console.log(obj); // {a: 1}


obj.a = 3; // 可以修改已有属性
console.log(obj); // {a: 3}

在上面的示例中,首先创建一个对象 obj,调用 Object.isExtensible(obj) 方法返回 true,表示 obj 是可扩展的。然后调用 Object.preventExtensions(obj) 方法将 obj 设置为不可扩展,此时再次调用 Object.isExtensible(obj) 方法返回 false,表示 obj 已经不可扩展了。在不可扩展的对象上添加新的属性是无效的,如 obj.b = 2,操作不会报错,但是添加失败,obj 仍然只有一个属性 a。而对于已有属性,仍然可以进行修改,如 obj.a = 3,可以将 obj 的属性 a 的值修改为 3。

preventExtensions 和 freeze 的区别

Object.preventExtensions() 和 Object.freeze() 方法都是用来保护对象的,但是它们的作用不同。
Object.preventExtensions() 方法用于将一个对象设置为不可扩展,即无法添加新的属性,但是已有属性可以修改或删除。相对于可扩展的对象,不可扩展的对象更加安全,但是仍然可以修改属性的值,因此不能完全保护对象的属性。
Object.freeze() 方法用于将一个对象设置为不可变的,即无法添加、修改或删除属性。冻结后的对象是无法修改的,是完全保护对象的一种方式。
两者的区别可以简单理解为:Object.preventExtensions() 方法保护对象的属性不会被添加新的属性,而 Object.freeze() 方法保护对象的属性不会被添加、修改或删除。
需要注意的是,使用 Object.freeze() 方法冻结一个对象,也会同时将该对象设置为不可扩展,因此冻结后的对象是既不可扩展也不可变的。但是使用 Object.preventExtensions() 方法只能将对象设置为不可扩展,而不能冻结对象。
Object 常用的实例属性
上面讲到的都是 Object 的静态方法,下面讲 Object 实例对象上常用的属性,这些属性都存在于实例对象的原型上,也就是 Object.prototype 对象上。

  • 1 Object.prototype.constructor:返回创建该对象实例的构造函数。例如:
function Person(name, age) {

  this.name = name;

  this.age = age;

}




const p = new Person('Tom', 18);

console.log(p.constructor === Person); // 输出 true
  • 2 Object.prototype.hasOwnProperty():判断对象是否拥有指定属性,返回一个布尔值。它接收一个属性名作为参数,如果对象自身包含该属性,则返回 true,否则返回 false。例如:
const obj = {



  name: 'Tom',
  age: 18,
  gender: 'male',
};









console.log(obj.hasOwnProperty('name')); // 输出 true
console.log(obj.hasOwnProperty('toString')); // 输出 false
  • 3 Object.prototype.isPrototypeOf():判断一个对象是否是另一个对象的原型。它接收一个对象作为参数,如果当前对象是该参数对象的原型,则返回 true,否则返回 false。例如:
function Person(name, age) {

  this.name = name;

  this.age = age;

}




const p = new Person('Tom', 18);

console.log(Person.prototype.isPrototypeOf(p)); // 输出 true
  • 4 Object.prototype.toString():返回对象的字符串表示。它可以用于判断一个对象的类型,例如:
const obj = {};



console.log(Object.prototype.toString.call(obj)); // 输出 "[object Object]"








const arr = [];
console.log(Object.prototype.toString.call(arr)); // 输出 "[object Array]"








const fn = function () {};
console.log(Object.prototype.toString.call(fn)); // 输出 "[object Function]"
  • 5 Object.prototype.valueOf()方法返回当前对象的原始值。但是,大多数对象都会覆盖该方法,以便返回更具体的原始值。
    例如,当使用 + 运算符将一个对象转换为数字时,JavaScript 引擎会先调用对象的 valueOf() 方法获取其原始值,然后再将其转换为数字。如果对象没有覆盖 valueOf() 方法,则默认返回对象本身,无法进行有效的转换。
    下面是一个简单的示例,演示了如何覆盖 valueOf() 方法来返回一个自定义的原始值:
const obj = {



  valueOf: function() {
    return 42;
  }
};









console.log(obj + 1); // 输出 43

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYAPAC9o' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片