Object的详细讲解

312 阅读27分钟

原型链的实例属性(2个)

1.Object.prototype.constructor

constructor属性表示创建某个对象实例的构造函数。每个 JavaScript 对象都会从其原型中继承这个属性。 

作用

  1. 确定某个对象是由哪个构造函数创建的。
  2. 在对象实例上创建新的实例。

代码示例

//确定某个对象是由哪个构造函数创建的。
const obj = {};
console.log(obj.constructor === Object); // true

const arr = [];
console.log(arr.constructor === Array); // true

const num = new Number(42);
console.log(num.constructor === Number); // true

//创建新的实例
function Person(name) {
  this.name = name;
}

const person1 = new Person("Alice");
console.log(person1.constructor === Person); // true

2.Object.prototype.__proto__(已弃用)

Object.prototype.proto 是一个 JavaScript 对象的访问器属性,用于访问和设置对象的内部 [[Prototype]] 属性,即该对象的原型。(原型对象是用于定义该对象属性和方法的模板)

目前推荐使用Object.getPrototypeOf() 和 Object.setPrototypeOf() 来获取和设置对象的原型,

作用

  • 获取原型:可以通过 __proto__ 访问对象的原型。
  • 设置原型:可以通过 __proto__ 设置对象的原型。

代码示例

//获取对象的原型
const obj = { a: 1 };
const prototype = obj.__proto__;
console.log(prototype === Object.prototype); // true

//设置对象的原型
const prototype = { b: 2 };
const obj = {};
obj.__proto__ = prototype;
console.log(obj.b); // 2

注意

  1. 设置对象的原型时。提供的值必须是一个对象或 null,任何其他值都不会产生作用。
  2. 对于原型为 null 的对象,proto 的值是 undefined。任何对 proto 的赋值操作都会在对象上创建一个名为 proto 的新属性,而不会改变对象的原型

原型链的实例方法(6个)

1.Object.prototype.hasOwnProperty()

用于检查该属性是否是对象的自身属性(非继承属性)

语法

obj.hasOwnProperty(prop)
  • 参数prop 是一个字符串,表示要检查的属性的名称。
  • 返回值:如果对象具有指定的自身属性,则返回 true,否则返回 false

代码示例

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

console.log(obj.hasOwnProperty('a')); // true
console.log(obj.hasOwnProperty('b')); // true
console.log(obj.hasOwnProperty('c')); // false

注意:

1。 该方法为原型链方法,使用该方法的对象必须继承自 Object.prototype ,否则不能使用。

2.Object.prototype.isPrototypeOf()

用于检查一个对象是否存在于另一个对象的原型链中

语法

Object.prototype.isPrototypeOf(object)

参数

  • object:要检查的对象,看它是否在调用 isPrototypeOf() 方法的对象的原型链上。

返回值

  • 当参数是 undefined 或者 null 时,返回false
  • 如果调用该方法的对象是指定对象的原型或位于其原型链上,则返回 true,否则返回 false

代码示例

function Person(name) {
  this.name = name;
}

const person1 = new Person('Alice');

console.log(Person.prototype.isPrototypeOf(person1)); // true

3.Object.prototype.propertyIsEnumerable()

用于检查指定属性是否能够通过 for...in 循环枚举,并且是否是对象的自身属性

语法

Object.prototype.propertyIsEnumerable(prop)

参数

  • prop:一个字符串,表示要检查的属性的名称。

返回值

  • 如果对象具有指定的可枚举属性(即该属性存在于对象本身而不是继承自原型链,并且可以通过 for...in 循环访问),则返回 true。否则返回 false

代码示例

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

console.log(obj.propertyIsEnumerable('a')); // true
console.log(obj.propertyIsEnumerable('b')); // true
console.log(obj.propertyIsEnumerable('toString')); // false,toString 方法不可枚举

4.Object.prototype.valueOf()

Object.prototype.valueOf()方法常用于将对象转换为原始值(基本数据类型)(例如数学运算、比较操作等)就常常会自动调用该方法。

返回值

一般情况下,它返回对象本身,但对于某些内置对象类型,如 Number、String 和 Date,它会返回相应的原始值。

示例

// 创建一个自定义对象
const obj = {
  value: 10,
  valueOf: function() {
    return this.value;
  }
};

// 当对象被用作数学运算的操作数时
const sum = obj + 5; // 调用 obj.valueOf() 获取原始值,然后进行加法运算
console.log(sum); // 输出: 15

// 在比较操作中使用
const isEqual = obj === 10; // 调用 obj.valueOf() 获取原始值,然后进行比较
console.log(isEqual); // 输出: true

// 显式调用 valueOf()
const primitiveValue = obj.valueOf();
console.log(primitiveValue); // 输出: 10

//返回当前时间戳
const date = new Date();
console.log(date.valueOf()); // 返回当前时间的时间戳

5.Object.prototype.toString()

用于获取对象的字符串表示的方法

语法

Object.prototype.toString()

返回值

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

代码示例


const obj = [];  
console.log(Object.prototype.toString.call(obj)); // 输出 "[object Array]"  
  
const func = function() {};  
console.log(Object.prototype.toString.call(func)); // 输出 "[object Function]"  
  
const date = new Date();  
console.log(Object.prototype.toString.call(date)); // 输出 "[object Date]"  
  
const nullValue = null;  
console.log(Object.prototype.toString.call(nullValue)); // 输出 "[object Null]"  
  
const objWithCustomPrototype = Object.create({});  
console.log(Object.prototype.toString.call(objWithCustomPrototype)); // 输出 "[object Object]"

注意 1.在调用 obj.toString()时我们需要带上(.call(obj)),这样才能把this指向我们的参数,返回参数的toString()而不是对象自身的 toString() 方法

6.Object.prototype.toLocaleString()

相比于toString() 来说,toLocaleString() 的返回值会根据提供的地区设置(locale)而变化,并可能包含地区特定的格式和符号。而toString() 的返回值通常是一个更通用的、不依赖于地区设置的字符串表示。

语法

Object.prototype.toLocaleString()

语法

  • toLocaleString() 方法返回一个表示对象本地化字符串的值。对于大多数内置对象,这个方法返回的值与 toString() 方法返回的值相同。

代码示例

const obj = {
  toString() {
    return 'Object';
  },
  toLocaleString() {
    return 'Localized Object';
  }
};

console.log(obj.toString());        // Object
console.log(obj.toLocaleString());  // 本地化Object

静态方法(22个)

1.Object.assign()

用于将一个或多个源对象的所有可枚举属性复制到目标对象中。它返回目标对象。

语法

Object.assign(target, ...sources)
  • target:目标对象。
  • sources:一个或多个源对象。

代码示例

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target); // { a: 1, b: 4, c: 5 }
console.log(returnedTarget); // { a: 1, b: 4, c: 5 }

注意事项

  1. 浅拷贝Object.assign() 执行的是浅拷贝。如果源对象中的属性是对象(引用类型),则只会复制其引用。
  2. 同名属性覆盖:如果多个源对象有相同的属性名,后面的属性会覆盖前面的属性。
  3. 属性描述符Object.assign() 只拷贝源对象的可枚举和自有属性。它不会拷贝继承的属性或不可枚举的属性。

示例:浅拷贝和深拷贝的区别

const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);

shallowCopy.b.c = 3;

console.log(obj.b.c); // 3, 浅拷贝影响了原对象

// 深拷贝可以使用 JSON 方法(但是注意这只适用于不包含函数的对象)
const deepCopy = JSON.parse(JSON.stringify(obj));

deepCopy.b.c = 4;

console.log(obj.b.c); // 3, 深拷贝不影响原对象

2.Object.create()

用于创建一个新对象,并且这个新对象的原型([[Prototype]])由你指定。你还可以通过可选的属性描述符来进一步定义这个新对象的属性。

语法

Object.create(proto, [propertiesObject])
  • proto:新创建对象的原型对象,可以为 null
  • propertiesObject(可选):一个对象,其属性将被添加到新创建的对象中,这些属性的描述符是使用 Object.defineProperties 的格式。

代码示例

const person = {
    isHuman: false,
    printIntroduction: function() {
        console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
    }
};

const me = Object.create(person);

me.name = 'Matthew'; // "name" 属性是直接添加到 "me" 对象上,而不是在原型上
me.isHuman = true; // 继承的属性可以被覆盖

me.printIntroduction(); // My name is Matthew. Am I human? true

//使用 `null` 作为原型
const obj = Object.create(null);
console.log(Object.getPrototypeOf(obj)); // null

//带属性描述符的用法
const obj = Object.create({}, {
    foo: {
        value: 42,
        writable: true,
        configurable: true,
        enumerable: true
    },
    bar: {
        value: 'hello',
        writable: false,
        configurable: false,
        enumerable: false
    }
});

console.log(obj.foo); // 42
console.log(obj.bar); // hello

使用场景

  1. 创建具有特定原型的新对象:在创建对象时,可以指定它的原型,从而实现继承。
  2. 模拟类和继承:在 JavaScript 中实现基于原型的继承。
  3. 创建空对象:创建没有继承链的对象(如 Object.create(null))。

注意事项

  1. 性能:直接使用 Object.create(null) 创建的对象没有原型,因此它的性能可能比常规对象更好,适合用作纯数据对象,如字典。
  2. 属性描述符:在创建对象时,可以通过属性描述符进一步定义对象的属性。

3.Object.defineProperty()

用于在对象上定义或修改一个属性,并返回该对象。

语法

Object.defineProperty(obj, prop, descriptor)
  • obj:要在其上定义属性的对象。
  • prop:要定义或修改的属性的名称。
  • descriptor:将被定义或修改的属性描述符。

属性描述符

属性描述符分为两类:数据描述符和访问器描述符。一个描述符只能是这两者之一,不可混合。

数据描述符

  • value:属性的值,默认为 undefined
  • writable:表示属性的值是否可以被修改,默认为 false
  • enumerable:表示属性是否可以通过 for...in 循环枚举,默认为 false
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除,默认为 false

访问器描述符

  • get:一个给属性提供 getter 的函数,如果没有 getter 则为 undefined
  • set:一个给属性提供 setter 的函数,如果没有 setter 则为 undefined
  • enumerable:表示属性是否可以通过 for...in 循环枚举,默认为 false
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除,默认为 false

代码示例

//基本用法
const obj = {};

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

console.log(obj.a); // 1

//定义一个只读属性
const obj = {};

Object.defineProperty(obj, 'a', {
    value: 1,
    writable: false
});

obj.a = 2; // 无效
console.log(obj.a); // 1

//定义一个访问器属性
const obj = {};
let value = 0;

Object.defineProperty(obj, 'b', {
    get() {
        return value;
    },
    set(newValue) {
        value = newValue;
    },
    enumerable: true,
    configurable: true
});

obj.b = 3;
console.log(obj.b); // 3

使用场景

  1. 精确控制属性行为:通过属性描述符,你可以精确控制属性的行为,如是否可枚举、可配置、可写。
  2. 实现只读属性:通过设置 writable: false,可以创建一个只读属性。
  3. 定义 getter 和 setter:可以使用 getset 方法定义访问器属性。

注意事项

  1. 默认值:如果没有显式指定,属性描述符中的所有字段默认为 falseundefined
  2. 不可配置属性:一旦属性被定义为不可配置(configurable: false),你就无法再修改它的可配置性和可枚举性。

4.Object.defineProperties()

用于一次性在一个对象上定义或修改多个属性。它会返回修改后的对象。这个方法与 Object.defineProperty() 类似,但是区别是 Object.defineProperties() 允许我们在一个调用中定义多个属性。

语法

Object.defineProperties(obj, props)
  • obj:要在其上定义属性的对象。
  • props:一个对象,其每个属性对应于要定义或修改的属性及其描述符。

属性描述符

属性描述符分为数据描述符和访问器描述符。一个描述符只能是这两者之一,不可混合。

数据描述符

  • value:属性的值,默认为 undefined
  • writable:表示属性的值是否可以被修改,默认为 false
  • enumerable:表示属性是否可以通过 for...in 循环枚举,默认为 false
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除,默认为 false

访问器描述符

  • get:一个给属性提供 getter 的函数,如果没有 getter 则为 undefined
  • set:一个给属性提供 setter 的函数,如果没有 setter 则为 undefined
  • enumerable:表示属性是否可以通过 for...in 循环枚举,默认为 false
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除,默认为 false

代码示例

const obj = {};

Object.defineProperties(obj, {
    'property1': {
        value: 42,
        writable: true,
        enumerable: true,
        configurable: true
    },
    'property2': {
        value: 'hello',
        writable: false,
        enumerable: false,
        configurable: false
    }
});

console.log(obj.property1); // 42
console.log(obj.property2); // hello

//定义数据属性和访问器属性
const obj = {};
let value = 0;

Object.defineProperties(obj, {
    'property1': {
        value: 42,
        writable: true,
        enumerable: true,
        configurable: true
    },
    'property2': {
        get() {
            return value;
        },
        set(newValue) {
            value = newValue;
        },
        enumerable: true,
        configurable: true
    }
});

console.log(obj.property1); // 42
obj.property2 = 33;
console.log(obj.property2); // 33

使用场景

  1. 定义多个属性:在一个调用中定义或修改多个属性,简化代码。
  2. 统一管理属性描述符:方便地对一个对象的多个属性进行精细控制。

注意事项

  1. 默认值:如果没有显式指定,属性描述符中的所有字段默认为 falseundefined
  2. 不可配置属性:一旦属性被定义为不可配置(configurable: false),你就无法再修改它的可配置性和可枚举性。

5.Object.getOwnPropertyDescriptor()

用于获取指定对象上某个自有属性(即对象自身具有的属性,而不是从原型链上继承的属性)的属性描述符。它会返回描述符以对象的形式,该对象包含了该属性的配置。

语法

Object.getOwnPropertyDescriptor(obj, prop)
  • obj:要查找的对象。
  • prop:要获取其描述符的属性的名称。

返回值

返回一个对象形式的属性描述符,如果对象上不存在指定属性,则返回 undefined

数据描述符

  • value:属性的值。
  • writable:表示属性的值是否可以被修改。
  • enumerable:表示属性是否可以通过 for...in 循环枚举,默认为 false
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除,默认为 false

访问器描述符

  • get:属性的 getter 函数。
  • set:属性的 setter 函数。
  • enumerable:表示属性是否可以通过 for...in 循环枚举,默认为 false
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除,默认为 false

代码示例

//获取数据属性的描述符
const obj = {
    a: 42
};

const descriptor = Object.getOwnPropertyDescriptor(obj, 'a');

console.log(descriptor);
// 输出:{ value: 42, writable: true, enumerable: true, configurable: true }

//获取访问器属性的描述符
const obj = {};
let value = 0;

Object.defineProperty(obj, 'b', {
    get() {
        return value;
    },
    set(newValue) {
        value = newValue;
    },
    enumerable: true,
    configurable: true
});

const descriptor = Object.getOwnPropertyDescriptor(obj, 'b');

console.log(descriptor);
// 输出:{ get: [Function: get], set: [Function: set], enumerable: true, configurable: true }

//属性不存在时返回 `undefined`
const obj = {
    a: 42
};

const descriptor = Object.getOwnPropertyDescriptor(obj, 'b');

console.log(descriptor); // undefined

使用场景

  1. 检查属性的配置:在对属性进行修改之前,检查属性的当前配置。
  2. 调试和测试:在调试和测试代码时,了解属性的详细配置。

6.Object.getOwnPropertyDescriptors()

用于获取对象自身所有属性的描述符。它会返回一个对象,其中每个属性对应一个属性描述符对象。

语法

Object.getOwnPropertyDescriptors(obj)
  • obj:要获取其属性描述符的对象。

返回值

返回一个对象,该对象包含指定对象自身所有属性的描述符。

属性描述符

属性描述符分为两类:数据描述符和访问器描述符。

数据描述符

  • value:属性的值。
  • writable:表示属性的值是否可以被修改。
  • enumerable:表示属性是否会出现在对象的枚举属性中。
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除。

访问器描述符

  • get:一个给属性提供 getter 的函数,如果没有 getter 则为 undefined
  • set:一个给属性提供 setter 的函数,如果没有 setter 则为 undefined
  • enumerable:表示属性是否会出现在对象的枚举属性中。
  • configurable:表示属性描述符是否可以被修改,属性是否可以被删除。

代码示例

//获取对象所有属性的描述符
const obj = {
    a: 42,
    get b() {
        return 10;
    }
};

const descriptors = Object.getOwnPropertyDescriptors(obj);

console.log(descriptors);
// 输出:
/*
{
  a: { value: 42, writable: true, enumerable: true, configurable: true },
  b: { get: [Function: get b], set: undefined, enumerable: true, configurable: true }
}
*/

使用场景

  1. 对象克隆:我们可以结合 Object.create() 实现对象的浅拷贝。
  2. 对象扩展:将一个对象的属性及其描述符复制到另一个对象中。
  3. 调试和检查:获取对象的所有属性描述符,便于调试和检查属性配置。

示例扩展:与 Object.defineProperties() 结合使用

可以将一个对象的所有属性及其描述符复制到另一个对象中。

const source = {
    a: 1,
    get b() {
        return this.a + 1;
    }
};

const target = {};
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));

console.log(target.a); // 1
console.log(target.b); // 2

7.Object.entries()

用于返回一个给定对象自身可枚举属性的键值对数组。数组中的每个元素都是一个包含两个元素的数组,第一个元素是属性键,第二个元素是属性值。

语法

Object.entries(obj)
  • obj:要返回其可枚举属性的对象。

返回值

返回一个数组,其中每个元素都是一个 [key, value] 对,表示对象自身可枚举属性的键值对。

代码示例

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

const entries = Object.entries(obj);
console.log(entries);
// 输出:[['a', 1], ['b', 2], ['c', 3]]

//处理数组,`Object.entries()` 可以处理数组,因为数组也是对象,数组的索引被视为键。

const arr = ['foo', 'bar', 'baz'];

const entries = Object.entries(arr);
console.log(entries);
// 输出:[['0', 'foo'], ['1', 'bar'], ['2', 'baz']]

使用场景

  1. 对象遍历:可以让我们方便地获取对象的键值对并进行遍历。
  2. 对象转换:可以将对象转换为其他数据结构,如 Map

注意事项

  1. 仅限自身属性Object.entries() 只会返回对象自身的可枚举属性,不包括继承的属性。
  2. 属性顺序:属性的顺序与通过 for...in 循环遍历对象属性时的顺序一致。

10.Object.getOwnPropertySymbols()

用于获取对象自身所有的符号属性(Symbol)的数组。与 Object.getOwnPropertyNames()Object.keys() 不同,Object.getOwnPropertySymbols() 专门用于获取符号属性,而不是字符串属性。

语法

Object.getOwnPropertySymbols(obj)
  • obj:要获取其符号属性的对象。

返回值 返回一个数组,包含对象自身的所有符号属性。如果没有符号属性,则返回一个空数组。

代码示例

const symbol1 = Symbol('symbol1');
const symbol2 = Symbol('symbol2');

const obj = {
    [symbol1]: 'value1',
    [symbol2]: 'value2',
    a: 1
};

const symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols);
// 输出:[Symbol(symbol1), Symbol(symbol2)]

console.log(obj[symbols[0]]); // 输出:value1
console.log(obj[symbols[1]]); // 输出:value2

Object.getOwnPropertyNames()Object.keys() 的比较

const symbol1 = Symbol('symbol1');
const obj = {
    [symbol1]: 'value1',
    a: 1,
    b: 2
};

const keys = Object.keys(obj);
console.log(keys);
// 输出:['a', 'b']

const propertyNames = Object.getOwnPropertyNames(obj);
console.log(propertyNames);
// 输出:['a', 'b']

const symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols);
// 输出:[Symbol(symbol1)]

使用场景

  1. 处理符号属性:在处理对象的符号属性时非常有用,因为符号属性不会被常规的属性枚举方法(如 Object.keysfor...in)获取到。
  2. 避免属性冲突:使用符号作为属性键可以避免属性名称冲突,尤其是在使用第三方库或扩展对象时。

11.Object.keys()

它会返回一个数组,该数组包含对象自身的可枚举属性的键(即属性名称)。这些键会以字符串的形式返回,并且只包括对象自身的属性,不包括从原型链上继承的属性。

语法

Object.keys(obj)
  • obj:要返回其可枚举属性键的对象。

返回值

返回一个包含对象自身的可枚举属性键的数组。这些键是按顺序排列的,与 for...in 循环遍历对象属性时的顺序一致。

代码示例

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

const keys = Object.keys(obj);
console.log(keys);
// 输出:['a', 'b', 'c']

处理数组 Object.keys() 可以用于数组,返回数组的索引作为键。

const arr = ['foo', 'bar', 'baz'];

const keys = Object.keys(arr);
console.log(keys);
// 输出:['0', '1', '2']

处理对象原型链 Object.keys() 只返回对象自身的可枚举属性,不包括继承的属性。

function Parent() {
    this.inherited = 'inherited';
}

Parent.prototype.protoProp = 'protoProp';

const obj = new Parent();
obj.ownProp = 'ownProp';

const keys = Object.keys(obj);
console.log(keys);
// 输出:['inherited', 'ownProp']

使用场景

  1. 遍历对象属性:获取对象自身的可枚举属性键,并进行遍历操作。
  2. 对象操作:结合数组方法(如 mapforEach 等),对对象属性进行各种操作。

示例扩展:遍历对象属性和值 可以结合 Array.prototype.forEach() 遍历对象的属性和值。

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

Object.keys(obj).forEach(key => {
    console.log(`${key}: ${obj[key]}`);
});
// 输出:
// a: 1
// b: 2
// c: 3

示例扩展:计算对象属性的个数 可以使用 Object.keys() 计算对象自身属性的个数。

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

const count = Object.keys(obj).length;
console.log(count); // 输出:3

12.Object.values()

它会返回一个给定对象自身的所有可枚举属性值的数组。这些值按属性键的顺序排列,与 Object.keys() 返回的键的顺序一致。

语法

Object.values(obj)
  • obj:要返回其可枚举属性值的对象。

返回值

返回一个包含对象自身的可枚举属性值的数组。

代码示例

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

const values = Object.values(obj);
console.log(values);
// 输出:[1, 2, 3]

结合 Object.keys()Object.values() 可以遍历对象的属性和值。

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

Object.keys(obj).forEach(key => {
    console.log(`${key}: ${obj[key]}`);
});
// 输出:
// a: 1
// b: 2
// c: 3

使用场景

  1. 遍历对象属性值:获取对象自身的可枚举属性值,并进行遍历操作。
  2. 对象操作:结合数组方法(如 mapforEach 等),对对象属性值进行各种操作。

13.Object.hasOwn()

用于检查对象自身(而不是从原型链上继承的)是否具有特定的属性。这个方法是 ES2022 (ECMAScript 2022) 引入的,它是 Object.prototype.hasOwnProperty() 的一个简洁替代。

语法

Object.hasOwn(obj, prop)
  • obj:要检查的对象。
  • prop:要检查的属性名称。

返回值

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

代码示例

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

console.log(Object.hasOwn(obj, 'a')); // true
console.log(Object.hasOwn(obj, 'b')); // true
console.log(Object.hasOwn(obj, 'c')); // false

使用场景

  1. 检查属性存在性:在处理对象属性时,检查对象是否具有某个自身属性,而不是继承的属性。
  2. 对象遍历:在遍历对象属性时,可以用来过滤掉继承的属性。
  3. 替代 hasOwnProperty():提供一个简洁的方法来代替 hasOwnProperty()

注意事项

  • Object.hasOwn() 是 ES2022 引入的,可能在较旧的 JavaScript 环境中不被支持。在这种情况下,可以使用 Object.prototype.hasOwnProperty.call(obj, prop) 作为替代。

14.Object.is()

用于比较两个值是否严格相等。它与严格相等运算符 === 的行为类似,但有几个特殊的区别,尤其是在处理特殊值(如 NaN-0)时。

语法

Object.is(value1, value2)
  • value1:要比较的第一个值。
  • value2:要比较的第二个值。

返回值

返回一个布尔值,表示两个值是否相等。

特殊情况

  • NaN 相等性Object.is(NaN, NaN) 返回 true,而 NaN === NaN 返回 false
  • -0 和 +0 相等性Object.is(-0, +0) 返回 false,而 -0 === +0 返回 true

代码示例

console.log(Object.is(1, 1)); // true
console.log(Object.is('foo', 'foo')); // true
console.log(Object.is({}, {})); // false (不同的引用)
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(-0, +0)); // false

使用场景

  • 特殊值比较:在需要严格区分 NaN-0+0 等特殊值时,使用 Object.is() 更为准确。
  • 对象比较:当需要比较对象引用是否相同时,可以使用 Object.is() 进行比较。

注意事项

  • Object.is() 是 ECMAScript 6 引入的新方法,与传统的比较运算符(如 =====)有所不同,需要根据具体情况选择使用。

Object.is()=== 的对比

console.log(Object.is(0, 0)); // true
console.log(0 === 0); // true

console.log(Object.is(-0, -0)); // true
console.log(-0 === -0); // true

console.log(Object.is(-0, 0)); // false
console.log(-0 === 0); // true

console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false

15.Object.getPrototypeOf()

用于返回指定对象的原型(即,内部 [[Prototype]] 属性的值)。原型是对象继承属性和方法的机制。

语法

Object.getPrototypeOf(obj)
  • obj:要返回其原型的对象。

返回值

返回指定对象的原型。如果对象没有继承属性(即其原型是 null),则返回 null

代码示例

const obj = {};
const proto = Object.getPrototypeOf(obj);

console.log(proto === Object.prototype); // true

//自定义原型链
function Parent() {
    this.parentProp = 'parent';
}

const child = new Parent();
console.log(Object.getPrototypeOf(child) === Parent.prototype); // true


//检查与内置对象的继承关系,检查对象是否继承自某个内置对象的原型。
const arr = [1, 2, 3];
console.log(Object.getPrototypeOf(arr) === Array.prototype); // true

const func = function() {};
console.log(Object.getPrototypeOf(func) === Function.prototype); // true

使用场景

  1. 对象原型检查:在开发和调试时,检查对象的原型链。
  2. 原型链操作:结合 Object.setPrototypeOf() 修改对象的原型链。
  3. 继承关系检查:验证对象的继承关系。

注意事项

  • 直接操作原型链(如使用 Object.setPrototypeOf())可能会影响性能,应该谨慎使用。
  • Object.getPrototypeOf() 返回 null 表示对象没有原型,即对象不继承任何属性或方法。

16.Object.setPrototypeOf()

用于设置指定对象的原型(即,内部 [[Prototype]] 属性的值)。它允许我们改变一个对象的原型链。

语法

Object.setPrototypeOf(obj, prototype)
  • obj:要设置原型的对象。
  • prototype:新原型对象,或者 null

返回值

返回修改后的对象。

代码示例

const proto = {
    greet() {
        return 'Hello';
    }
};

const obj = {
    name: 'Alice'
};

Object.setPrototypeOf(obj, proto);
console.log(obj.greet()); // 输出 'Hello'

//设置为 `null`,意味着该对象将不再从任何原型继承属性和方法。
const obj = {};
Object.setPrototypeOf(obj, null);

console.log(Object.getPrototypeOf(obj)); // 输出 null

使用场景

  1. 改变原型链:在动态系统中,可能需要更改对象的原型以改变其行为。
  2. 对象组合:通过设置对象的原型,可以实现对象的组合与继承。

注意事项

  1. 性能影响:直接操作原型链可能会对性能造成负面影响,特别是在热代码路径中。
  2. 浏览器兼容性Object.setPrototypeOf 是 ECMAScript 2015 (ES6) 引入的方法,较旧的浏览器可能不支持。
  3. 替代方法:可以使用 Object.create() 创建一个具有指定原型的新对象,避免直接修改原型链。

17.Object.freeze()

用于冻结一个对象。被冻结的对象不能再被修改,即不能向其添加新的属性,不能删除已有属性,不能修改已有属性的可枚举性、可配置性、可写性,不能修改已有属性的值(如果属性的值是对象,该对象的属性也无法修改,除非它们也被冻结)。

语法

Object.freeze(obj)
  • obj:要冻结的对象。

返回值

返回被冻结的对象。

代码示例

const obj = {
    prop: 42
};

Object.freeze(obj);

obj.prop = 33; // 不能修改属性值
delete obj.prop; // 不能删除属性

console.log(obj.prop); // 输出 42

冻结嵌套对象 冻结是浅层的,意味着只冻结对象的直接属性。如果属性的值是另一个对象,那个对象不会被冻结,除非手动冻结。

const obj = {
    internal: {
        a: 1
    }
};

Object.freeze(obj);
obj.internal.a = 42; // 可以修改内部对象的属性

console.log(obj.internal.a); // 输出 42

为了冻结嵌套对象,可以使用递归函数。

function deepFreeze(obj) {
    Object.freeze(obj);

    Object.keys(obj).forEach(key => {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            deepFreeze(obj[key]);
        }
    });

    return obj;
}

const obj = {
    internal: {
        a: 1
    }
};

deepFreeze(obj);
obj.internal.a = 42; // 不能修改内部对象的属性

console.log(obj.internal.a); // 输出 1

使用场景

  1. 常量对象:在开发中,将对象定义为常量,防止其被修改。
  2. 防止意外修改:确保对象的结构和内容在整个程序执行期间保持不变。
  3. 安全性:增强代码的安全性,防止对象被恶意篡改。

注意事项

  1. 不可逆:一旦对象被冻结,就无法解冻。
  2. 性能影响:冻结对象会有性能开销,尤其是在处理大量对象时。
  3. 浅冻结Object.freeze() 是浅冻结,嵌套对象需要手动深冻结。

18.Object.isFrozen()

用于检查对象是否被冻结。被冻结的对象意味着它不能再被修改:不能添加新属性,不能删除已有属性,不能修改已有属性的值、可枚举性、可配置性或可写性。

语法

Object.isFrozen(obj)
  • obj:要检查是否被冻结的对象。

返回值

返回一个布尔值,表示对象是否被冻结。

代码示例

const obj = {
    prop: 42
};

console.log(Object.isFrozen(obj)); // 输出 false

Object.freeze(obj);

console.log(Object.isFrozen(obj)); // 输出 true

检查非对象类型

对于非对象类型(如字符串、数字等),Object.isFrozen() 方法会返回 true,因为它们本质上是不可变的。

console.log(Object.isFrozen(42)); // 输出 true
console.log(Object.isFrozen('Hello')); // 输出 true

使用场景

  1. 确认对象是否冻结:在操作对象前,可以确认对象是否被冻结,以避免修改失败。
  2. 调试和验证:在调试和验证代码时,确保对象在需要冻结的情况下确实被冻结了。

注意事项

  1. 浅冻结Object.freeze() 只会浅冻结对象,对于嵌套对象,需要手动深冻结。
  2. 不可逆:一旦对象被冻结,就无法解冻。

20.Object.isExtensible()

用于检查对象是否是可扩展的。可扩展对象可以添加新的属性。默认情况下,所有对象都是可扩展的,除非使用了特定的方法来将其变为不可扩展。

语法

Object.isExtensible(obj)
  • obj:要检查的对象。

返回值

返回一个布尔值,表示对象是否是可扩展的。

代码示例

const obj = {
    prop: 42
};

console.log(Object.isExtensible(obj)); // 输出 true

Object.preventExtensions(obj);

console.log(Object.isExtensible(obj)); // 输出 false

使用Object.preventExtensions() 方法可以使对象变为不可扩展,即不能添加新的属性。

const obj = {
    prop: 42
};

Object.preventExtensions(obj);

obj.newProp = 27; // 无法添加新属性
console.log(obj.newProp); // 输出 undefined

使用Object.freeze() 方法会使对象变为不可扩展,同时将所有现有属性的可配置性和可写性设置为 false

const obj = {
    prop: 42
};

Object.freeze(obj);

console.log(Object.isExtensible(obj)); // 输出 false
obj.newProp = 27; // 无法添加新属性
console.log(obj.newProp); // 输出 undefined

// 尝试修改属性值也会失败
obj.prop = 27;
console.log(obj.prop); // 输出 42

使用场景

  1. 检查对象是否可扩展:在需要确定对象是否可以添加新属性时使用。
  2. 调试和验证:确保对象在某些情况下保持不可扩展状态,避免意外的属性添加。

注意事项

  • 不可逆:一旦对象变为不可扩展,就无法再变回可扩展。
  • 属性的其他特性Object.preventExtensions() 只会影响对象的可扩展性,而 Object.seal()Object.freeze() 会进一步限制对象属性的配置。

21.Object.seal()

用于将一个对象密封,使其变为不可扩展的,并且将所有现有属性的可配置性(configurable)设置为 false。密封对象的现有属性仍然可以修改,但不能添加新属性或删除现有属性。

语法

Object.seal(obj)
  • obj:要密封的对象。

返回值

返回密封后的对象。

代码示例

const obj = {
    prop: 42
};

Object.seal(obj);

obj.prop = 33; // 可以修改现有属性的值
console.log(obj.prop); // 输出 33

obj.newProp = 27; // 无法添加新属性
console.log(obj.newProp); // 输出 undefined

delete obj.prop; // 无法删除现有属性
console.log(obj.prop); // 输出 33

检查对象是否已密封 可以使用 Object.isSealed() 方法来检查对象是否已密封。

const obj = {
    prop: 42
};

console.log(Object.isSealed(obj)); // 输出 false

Object.seal(obj);

console.log(Object.isSealed(obj)); // 输出 true

Object.freeze() 的区别

  • Object.seal():将对象变为不可扩展,并将所有现有属性的可配置性设置为 false。现有属性的值仍然可以修改。
  • Object.freeze():在 Object.seal() 的基础上,还将所有现有属性的可写性(writable)设置为 false,使得现有属性的值也不能修改。

示例对比

const sealedObj = {
    prop: 42
};
Object.seal(sealedObj);
sealedObj.prop = 33; // 可以修改属性值
console.log(sealedObj.prop); // 输出 33

const frozenObj = {
    prop: 42
};
Object.freeze(frozenObj);
frozenObj.prop = 33; // 无法修改属性值
console.log(frozenObj.prop); // 输出 42

使用场景

  1. 保护对象结构:在需要确保对象的结构(属性的存在性和数量)保持不变的情况下使用。
  2. 防止属性删除:确保对象的属性不会被意外删除。
  3. 调试和验证:用于调试和验证代码中对象的状态,确保对象不会被意外修改。

注意事项

  1. 不可逆:一旦对象被密封,就无法取消密封。
  2. 仅影响可配置性Object.seal() 仅影响属性的可配置性,不影响属性的可写性。

22.Object.isSealed()

用于检查对象是否已经被密封。被密封的对象不可扩展,且其所有现有属性的可配置性(configurable)都被设置为 false,但属性值仍然可以修改。

语法

Object.isSealed(obj)
  • obj:要检查的对象。

返回值

返回一个布尔值,表示对象是否被密封。

代码示例

const obj = {
    prop: 42
};

console.log(Object.isSealed(obj)); // 输出 false

Object.seal(obj);

console.log(Object.isSealed(obj)); // 输出 true

尝试密封对象的影响

const obj = {
    prop: 42
};

Object.seal(obj);

obj.prop = 33; // 可以修改现有属性的值
console.log(obj.prop); // 输出 33

obj.newProp = 27; // 无法添加新属性
console.log(obj.newProp); // 输出 undefined

delete obj.prop; // 无法删除现有属性
console.log(obj.prop); // 输出 33

检查密封对象的属性 可以通过 Object.getOwnPropertyDescriptor() 检查对象属性的描述符,验证属性是否不可配置。

const obj = {
    prop: 42
};

Object.seal(obj);

const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop');
console.log(descriptor.configurable); // 输出 false
console.log(descriptor.writable); // 输出 true

使用场景

  1. 确认对象是否被密封:在操作对象前,确保对象已经被密封,避免结构被修改。
  2. 调试和验证:用于调试和验证代码中的对象状态,确保对象的结构保持不变。

Object.preventExtensions()Object.freeze() 的区别

  • Object.preventExtensions():使对象不可扩展,不能添加新属性,但可以删除或修改现有属性。
  • Object.seal():在 Object.preventExtensions() 的基础上,所有现有属性的可配置性被设置为 false,但现有属性的值仍然可以修改。
  • Object.freeze():在 Object.seal() 的基础上,所有现有属性的可写性被设置为 false,使得现有属性的值也不能修改。

示例对比

const obj1 = {
    prop: 42
};
Object.preventExtensions(obj1);
console.log(Object.isSealed(obj1)); // 输出 false

const obj2 = {
    prop: 42
};
Object.seal(obj2);
console.log(Object.isSealed(obj2)); // 输出 true

const obj3 = {
    prop: 42
};
Object.freeze(obj3);
console.log(Object.isSealed(obj3)); // 输出 true