Skip to content

Object

[TOC]

索引

Object

属性

__proto__

object.__proto__Object已弃用,用于访问或修改对象原型[[Prototype]]) 的非标准属性。

语法特性

  1. 获取/设置原型

    js
    object.__proto__; // 返回对象的原型
    
    object.__proto__ = prototypeObject; // 修改对象的原型
  2. 替代标准方法

  3. 对比标准方法

    操作__proto__Object.get/setPrototypeOf()
    代码可读性较低(非显式方法调用)更高(明确语义)
    兼容性部分旧环境不支持ES6+ 广泛支持
    安全性可能被误覆盖无此风险

注意事项

  1. 性能问题:动态修改原型(obj.__proto__ = ...)会破坏 JavaScript 引擎优化(如 V8 隐藏类),导致性能下降。

  2. 原型链污染风险:直接修改原型可能引发不可预见的副作用(如覆盖内置方法):

    js
    Array.prototype.push = () => "Hacked!"; // 危险操作!
    console.log([].push()); // "Hacked!"

示例

  1. 获取对象原型

    js
    // 1. 数组实例的对象原型 === Array构造函数的原型
    const arr = [1, 2];
    console.log(arr.__proto__ === Array.prototype); // true
    
    // 2. 对象实例的对象原型 === Object构造函数的原型
    const obj = {};
    console.log(obj.__proto__ === Object.prototype); // true
  2. 设置对象原型

    js
    const parent = { greet: () => "Hello!" };
    const child = {};
    
    child.__proto__ = parent; // 设置child的对象原型为parent
    console.log(child.greet()); // "Hello!"
  3. 非法设置操作

    js
    const obj = {};
    // 尝试设置非对象/非 null 值
    obj.__proto__ = 42; // TypeError: Object prototype may only be an Object or null

constructor

object.constructor构造函数,指向创建该对象的构造函数。它通常用于获取对象类型或创建同类新对象,但在某些场景下需要谨慎使用(如原型继承时可能被覆盖)。

语法特性

  1. 获取对象的构造函数

    js
    const arr = [1, 2];
    console.log(arr.constructor === Array); // true
    
    const obj = {};
    console.log(obj.constructor === Object); // true
    
    function Person(name) { this.name = name; }
    const alice = new Person("Alice");
    console.log(alice.constructor === Person); // true
  2. 通过构造函数创建新对象

    js
    const arr = [1, 2];
    const arrCopy = new arr.constructor(3); // 等价于 new Array(3)
    console.log(arrCopy); // [empty × 3]
    
    const obj = { a: 1 };
    const objCopy = new obj.constructor(); // 等价于 new Object()
    objCopy.b = 2;
    console.log(objCopy); // { b: 2 }
  3. 原型继承中的 constructor 问题:若手动修改原型链,需修正 constructor 的指向:

    js
    function Animal() {}
    function Dog() {}
    
    // 继承 Animal 的原型
    Dog.prototype = Object.create(Animal.prototype);
    
    // 修正 constructor 指向
    Dog.prototype.constructor = Dog;
    
    const dog = new Dog();
    console.log(dog.constructor === Dog); // true(修正后正确)

注意事项

  1. constructor 的可信度

    • 若对象是通过字面量(如 {}[])或构造函数创建的,constructor 指向正确。
    • 若原型链被手动修改(如 Object.create()),可能指向错误,需显式修正:
    js
    const obj = Object.create(Array.prototype);
    console.log(obj.constructor === Array); // true(但 obj 并非真正的数组)
  2. 直接调用 constructor() 的 this指向风险:未使用 new 操作符时,构造函数内的 this 可能指向全局对象(非严格模式)或报错(严格模式):

    js
    function Person(name) { this.name = name; }
    const bob = Person("Bob"); // 非严格模式下,this 指向 window,污染全局变量
    console.log(window.name); // "Bob"
  3. null 和原始值的 constructor

    • null 和 undefined 无 constructor 属性。

    • 原始值(如 "text"、42)的 constructor 指向包装对象的构造函数:

    js
    console.log("text".constructor === String); // true
    console.log((42).constructor === Number);   // true

应用场景

  1. 动态创建同类对象

    js
    const newObj = new existingObj.constructor();
  2. 类型检测

    js
    if (obj.constructor === Array) { ... } // 不如 Array.isArray() 可靠
  3. 原型链修复

    js
    Child.prototype.constructor = Child;

静态方法

创建对象

new Object()

new Object()(value?)创建对象的一种方式,但现代开发中更推荐使用对象字面量{})以提高代码简洁性和性能。

  • value?any,用于初始化对象的任意类型的值。

  • 返回:

  • objobject,根据 value 的类型返回对应的对象。

语法特性

  1. 参数类型与行为:根据参数类型的不同返回的对象也不同。

    • 无参数/null/undefined:返回空对象({})。
    • 原始类型:返回对应的包装对象(如NumberStringBoolean)。
    • 对象/数组/函数:直接返回原始对象,不创建新对象(数组仍是数组,函数仍是函数)。
  2. 对比对象字面量{}

    特性new Object()对象字面量 {}
    语法简洁性冗长(需构造函数调用)简洁直接
    性能略低(需解析构造函数)更高(引擎直接优化)
    可读性较低(需理解构造函数行为)更高(直观表达对象结构)
    使用场景动态生成对象(如根据变量类型转换)静态定义对象结构(推荐日常使用)

注意事项

  1. 原始值的包装对象:使用 new Object() 传入原始值会创建包装对象,可能导致类型判断问题:

    js
    const numObj = new Object(5);
    console.log(typeof numObj); // "object"(而非 "number")
    console.log(numObj instanceof Number); // true
  2. 无意义的 null/undefined 参数:传入 null 或 undefined 与无参数效果相同,但可能引发误解:

    js
    console.log(new Object(null)); // {}(并非 null)
  3. 避免冗余使用:对象字面量 {} 更高效且简洁,应优先使用:

    js
    // 推荐
    const obj = { a: 1 };
    // 不推荐
    const obj = new Object({ a: 1 });

示例

  1. 基本使用

    js
    const emptyObj = new Object(); // {}
    const numObj = new Object(100); // Number {100}
    const strObj = new Object("text"); // String {"text"}
  2. 对象类型参数

    js
    const existingObj = { a: 1 };
    const newObj = new Object(existingObj);
    console.log(newObj === existingObj); // true(同一对象)
  3. 数组与函数

    js
    const arr = new Object([1, 2, 3]); // [1, 2, 3]
    const func = new Object(function() {}); // function() {}
assign()

Object.assign()(target, ...sources?),用于合并对象属性的方法,它将一个或多个源对象(source)的可枚举自身属性复制到目标对象(target),并返回修改后的目标对象。此方法执行的是浅拷贝

  • targetobject,目标对象,接收复制的属性。若参数非对象,会尝试转换为对象;若为 null/undefined 会报错。

  • ...sources?object,源对象(可多个)。若参数非对象(如原始值),会转换为包装对象;若为 null/undefined则忽略。

  • 返回:

  • targetobject,修改后的目标对象。

核心特性

  1. 属性复制规则

    • 同名覆盖:后传入的源对象属性会覆盖之前的同名属性。
    • 浅拷贝:若属性值为对象,复制的是引用而非新对象。
    • 仅复制可枚举的自身属性:忽略继承属性和不可枚举属性(如 enumerable: false 的属性)。
    • Symbol 属性:可复制 Symbol 类型的键名。
  2. 参数处理

    • 目标对象非对象:原始值会被转换为包装对象(如 5Number(5)),但操作后仍返回原始类型(不常见)。

      js
      const str = 'hello';
      const result = Object.assign(str, { a: 1 }); // String {'hello', a: 1}
      console.log(result.a); // 1
    • 源对象为 null/undefined:直接跳过,不报错。

      js
      Object.assign({}, null, undefined, { a: 1 }); // { a: 1 }

注意事项

  1. 浅拷贝风险:若属性值为对象或数组,目标对象和源对象会共享同一引用,修改一方会影响另一方。

    js
    const source = { arr: [1, 2] };
    const target = Object.assign({}, source);
    target.arr.push(3);
    console.log(source.arr); // [1, 2, 3]
  2. 无法复制存取器属性(getter/setter):Object.assign() 会将存取器属性的值(调用 getter 的结果)复制到目标对象,而非保留 getter/setter。

    js
    const source = {
      get value() { return 42; }
    };
    const target = Object.assign({}, source);
    console.log(target.value); // 42(数据属性,而非 getter)
  3. 异常会中断复制:若复制过程中某个属性不可写(如目标对象的属性为只读),会抛出 TypeError,且已复制的属性保留

    js
    const target = Object.defineProperty({}, 'x', { value: 1, writable: false });
    try {
      Object.assign(target, { x: 2, y: 3 });
    } catch (e) {
      console.log(e); // TypeError: Cannot assign to read-only property 'x'
    }
    console.log(target); // { x: 1, y: 3 }(y 复制成功)
  4. Symbol 属性支持

    js
    const sym = Symbol('key');
    const source = { [sym]: 'value' };
    const target = Object.assign({}, source);
    console.log(target[sym]); // 'value'

应用场景

  1. 对象合并:合并配置项、状态更新(如 Redux reducer)。

  2. 浅拷贝对象:快速克隆对象(需注意嵌套引用问题)。

  3. 添加默认值:为函数参数提供默认配置。

  4. Mixin:将多个对象的属性混合到一个对象中。

示例

  1. 合并多个对象

    js
    const target = { a: 1 };
    const source1 = { b: 2 };
    const source2 = { a: 3, c: 4 };
    
    const result = Object.assign(target, source1, source2);
    console.log(result); // { a: 3, b: 2, c: 4 }
    console.log(target === result); // true(直接修改目标对象)
  2. 克隆对象(浅拷贝)

    js
    const obj = { a: 1, nested: { b: 2 } };
    const clone = Object.assign({}, obj);
    
    clone.a = 10;
    clone.nested.b = 20;
    
    console.log(obj.a); // 1(原始值不受影响)
    console.log(obj.nested.b); // 20(引用对象被修改)
  3. 处理原始值源对象:字符串会被转为字符数组形式的对象。

    js
    const obj = Object.assign({}, 'abc', true, 10);
    console.log(obj); 
    // {0: 'a', 1: 'b', 2: 'c'}(字符串被转为字符数组形式的对象)
  4. 忽略继承属性

    js
    const parent = { parentProp: 'parent' };
    const child = Object.create(parent);
    child.childProp = 'child';
    
    const obj = Object.assign({}, child);
    console.log(obj); // { childProp: 'child' }(不复制继承属性)
create()

Object.create()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
fromEntries()【

Object.fromEntries()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

属性描述符

defineProperty()

Object.defineProperty()(obj, prop, descriptor),用于精确控制对象属性行为的核心方法。允许开发者直接在一个对象上定义新属性或修改现有属性,并通过属性描述符精确配置属性的读写性可枚举性可配置性等特性。

  • objobject,目标对象,用于定义或修改属性。

  • propstring|symbol,属性名称。

  • descriptorobject属性描述符对象,包含配置属性行为的键值对。

  • 返回:

  • objobject,传入函数的目标对象,其指定的属性已被添加或修改。

语法特性

  1. 属性描述符默认值

    • 使用defineProperty显式设置的属性,属性描述符项选项默认为false。
    • 使用字面量定义的属性,属性描述符项选项默认为true。
    js
    const obj = {};
    Object.defineProperty(obj, 'prop', { value: 10 }); // configurable/enumerable/writable默认false
    console.log(obj.prop); // 10
    obj.prop = 20;         // 静默失败(writable 默认为 false)
  2. 不可逆操作configurable: false 后,无法再修改描述符(除 writable 从 true 改为 false)。

    js
    Object.defineProperty(obj, 'x', { configurable: false });
    Object.defineProperty(obj, 'x', { enumerable: true }); // TypeError
  3. 严格模式报错:在严格模式下,违反属性配置的操作(如修改只读属性)会抛出错误。

    js
    'use strict';
    obj.readOnlyProp = 100; // TypeError: Cannot assign to read only property

应用场景

  1. 数据劫持(响应式系统):Vue 2.x 使用 Object.defineProperty() 实现数据双向绑定。

    js
    function observe(obj, key, callback) {
      let value = obj[key];
      Object.defineProperty(obj, key, {
        get() { return value; },
        set(newVal) {
          if (value !== newVal) {
            value = newVal;
            callback(newVal); // 调用钩子函数
          }
        }
      });
    }
  2. 创建不可变属性:防止关键属性被意外修改或删除。

    js
    const config = {};
    Object.defineProperty(config, 'apiUrl', {
      value: 'https://api.example.com',
      writable: false,
      configurable: false
    });
  3. 隐藏内部状态:封装对象内部状态,仅暴露受控接口。

    js
    class Counter {
      constructor() {
        let count = 0;
        Object.defineProperty(this, 'count', {
          get: () => count,
          set: (value) => { throw new Error('count is read-only'); }
        });
        this.increment = () => count++;
      }
    }

示例

  1. 定义只读属性

    js
    const obj = {};
    
    Object.defineProperty(obj, 'readOnlyProp', {
      value: 42,
      writable: false,    // 不可写
      enumerable: true,   // 可枚举
      configurable: false // 不可删除或修改描述符
    });
    
    obj.readOnlyProp = 100; // 静默失败(严格模式下报错)
    console.log(obj.readOnlyProp); // 42
  2. 使用存取描述符(Getter/Setter)

    js
    const user = {
      firstName: 'John',
      lastName: 'Doe'
    };
    
    Object.defineProperty(user, 'fullName', {
      get() {
        return `${this.firstName} ${this.lastName}`;
      },
      set(value) {
        [this.firstName, this.lastName] = value.split(' ');
      },
      enumerable: true
    });
    
    user.fullName = 'Alice Smith';
    console.log(user.firstName); // "Alice"
    console.log(user.lastName);  // "Smith"
  3. 控制属性的可枚举性

    js
    const obj = { a: 1 };
    
    Object.defineProperty(obj, 'hiddenProp', {
      value: 'secret',
      enumerable: false // 不可枚举
    });
    
    console.log(Object.keys(obj)); // ["a"]
    console.log(obj.hiddenProp);   // "secret"(仍可访问)
defineProperties()

Object.defineProperties()(obj, props),用于批量定义或修改对象属性的方法,允许通过一次调用配置多个属性的特性(如读写性、可枚举性等)。

  • objobject,目标对象,用于定义或修改属性。

  • props{key: Descriptor,...,属性描述符集合,键名为属性名(字符串或 Symbol),键值为属性描述符对象。

  • 返回:

  • objobject,传入函数的目标对象,其指定的属性已被添加或修改。

语法特性

  1. 属性描述符默认值:若未显式设置 enumerable、configurable 或 writable,它们的默认值为 false。

    js
    // prop 的描述符等同于 { value: 1, writable: false, enumerable: false, configurable: false }
    Object.defineProperties(obj, { prop: { value: 1 } });
  2. 不可逆操作:若某属性的 configurable 设为 false,后续无法修改其描述符(除 writable 从 true 改为 false)。

    js
    Object.defineProperties(obj, {
      key: { configurable: false }
    });
    Object.defineProperties(obj, {
      key: { enumerable: true } // TypeError: Cannot redefine property
    });
  3. 严格模式报错:在严格模式下,违反描述符规则的操作会抛出错误:

    js
    'use strict';
    const obj = {};
    Object.defineProperties(obj, { x: { value: 10 } });
    obj.x = 20; // TypeError: Cannot assign to read-only property 'x'
  4. 对象不可扩展性:若目标对象不可扩展(Object.preventExtensions()),添加新属性会报错:

    js
    const obj = Object.preventExtensions({});
    Object.defineProperties(obj, { newProp: { value: 1 } }); // TypeError: Cannot define property
  5. 对比 Object.defineProperty()

    特性Object.defineProperty()Object.defineProperties()
    操作属性数量一次只能定义或修改一个属性。可批量定义或修改多个属性。
    语法简洁性适用于单个属性操作。适用于批量属性配置,代码更集中。
    使用场景动态添加或修改单个属性。初始化对象、批量配置属性特性。

应用场景

  1. 批量初始化属性:统一配置多个属性的特性(如隐藏内部状态)。

    js
    class Logger {
      constructor() {
        Object.defineProperties(this, {
          _logs: { value: [], writable: true },
          logCount: {
            get() { return this._logs.length; },
            enumerable: true
          }
        });
      }
    }
  2. 数据响应式系统:Vue 2.x 使用 Object.defineProperties() 批量定义响应式属性。

    js
    function reactive(obj) {
      const observers = new Map();
      const reactiveObj = {};
    
      Object.defineProperties(reactiveObj, {
        _data: { value: obj, enumerable: false },
        // 为每个属性添加 getter/setter
        ...Object.keys(obj).reduce((descriptors, key) => {
          descriptors[key] = {
            get() { return this._data[key]; },
            set(value) {
              this._data[key] = value;
              observers.get(key)?.forEach(cb => cb(value));
            },
            enumerable: true
          };
          return descriptors;
        }, {})
      });
    
      return reactiveObj;
    }
  3. 不可变配置对象:创建不可修改的全局配置。

    js
    const config = {};
    Object.defineProperties(config, {
      apiUrl: { value: 'https://api.example.com', writable: false },
      timeout: { value: 5000, writable: false }
    });

示例

  1. 批量定义数据属性

    js
    const obj = {};
    
    Object.defineProperties(obj, {
      prop1: {
        value: 42,
        writable: true,
        enumerable: true,
        configurable: true
      },
      prop2: {
        value: 'Hello',
        writable: false,
        enumerable: false
      }
    });
    
    console.log(obj.prop1); // 42
    console.log(Object.keys(obj)); // ["prop1"](prop2 不可枚举)
  2. 混合数据属性和存取描述符

    js
    const user = {};
    
    Object.defineProperties(user, {
      _age: {
        value: 25,
        writable: true,
        enumerable: false
      },
      age: {
        get() { return this._age; },
        set(value) {
          if (value >= 0) this._age = value;
        },
        enumerable: true
      }
    });
    
    user.age = 30;
    console.log(user.age); // 30
    user.age = -5;         // 赋值无效(setter 校验)
    console.log(user.age); // 30
  3. 默认值行为:未显式设置的描述符键(如 enumerable)默认为 false:

    js
    const obj = {};
    
    Object.defineProperties(obj, {
      x: { value: 10 },          // enumerable: false, configurable: false, writable: false
      y: { value: 20, writable: true }
    });
    
    console.log(Object.keys(obj)); // [](x 和 y 均不可枚举)
    obj.y = 30;                    // 成功(writable: true)
    obj.x = 5;                     // 静默失败(writable: false)
getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor(obj, prop),用于获取对象自身属性的描述符的方法。

  • objobject,要查询属性描述符的目标对象。

  • propstring|Symbol,目标属性的键名。

  • 返回:

  • descriptorobject|undefined,返回结果如下:

    • object:返回属性描述符对象(包含 valuewritableenumerableconfigurablegetset)。

    • undefined:如果目标对象不存在该属性或 obj 参数无效返回undefined。

语法特性

  1. 仅获取自身属性:若属性是继承的(来自原型链),返回 undefined。

    js
    const arr = [1, 2];
    console.log(Object.getOwnPropertyDescriptor(arr, "length")); // 存在(自身属性)
    console.log(Object.getOwnPropertyDescriptor(arr, "toString")); // undefined(继承自原型)
  2. Symbol 属性支持

    js
    const sym = Symbol("key");
    const obj = { [sym]: "value" };
    const descriptor = Object.getOwnPropertyDescriptor(obj, sym);
    console.log(descriptor.value); // "value"
  3. 严格模式下的参数类型:非对象参数在严格模式下可能报错:

    js
    "use strict";
    Object.getOwnPropertyDescriptor(1, "x"); // TypeError: 1 is not an object

应用场景

  1. 属性检查:验证属性是否可配置、可枚举或可写。

  2. 动态代理: 结合 Object.defineProperty() 实现属性拦截(如 Vue 2.x 响应式系统)。

  3. 深拷贝工具:通过描述符克隆属性特性,而非简单复制值。

  4. 兼容性处理:检测浏览器对某些属性的支持情况(如 configurable 是否可修改)。

示例

  1. 获取数据描述符

    js
    const obj = {};
    Object.defineProperty(obj, "name", {
      value: "Alice",
      writable: false,
      enumerable: true,
      configurable: true
    });
    
    const descriptor = Object.getOwnPropertyDescriptor(obj, "name");
    console.log(descriptor);
    /* 输出:
    {
      value: "Alice",
      writable: false,
      enumerable: true,
      configurable: true
    }
    */
  2. 获取存取描述符

    js
    const obj = {
      _age: 25,
      get age() {
        return this._age;
      },
      set age(value) {
        this._age = value;
      }
    };
    
    const descriptor = Object.getOwnPropertyDescriptor(obj, "age");
    console.log(descriptor);
    /* 输出:
    {
      get: function get() { ... },
      set: function set(value) { ... },
      enumerable: true,
      configurable: true
    }
    */
  3. 不存在的属性或无效对象

    js
    console.log(Object.getOwnPropertyDescriptor({}, "x")); // undefined
    console.log(Object.getOwnPropertyDescriptor(42, "valueOf")); // undefined(原始类型的包装对象无该自身属性)
    console.log(Object.getOwnPropertyDescriptor(null, "x")); // TypeError: Cannot convert undefined or null to object
getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors()(obj),用于获取对象所有自身属性的描述符的方法。是 getOwnPropertyDescriptor 的批量版,适用于需要全面分析或复制对象属性的场景(如深度克隆、元编程)。

  • objobj,要查询属性描述符的目标对象。

  • 返回:

  • descriptors{key: Descriptor,...},包含目标对象所有自身属性的描述符集合。可以作为参数传递给其他静态方法(如defineProperties,create)

语法特性

  1. 包含所有自身属性

    • 可枚举与不可枚举属性:无论属性是否可枚举(enumerable: true/false),均会被包含。
    • Symbol 属性:支持 Symbol 类型的键名。
    • 不包含继承属性:仅处理目标对象自身的属性。
  2. 返回值结构:返回对象的每个键值对表示一个属性的描述符,结构与 Object.getOwnPropertyDescriptor() 一致:

    js
    {
      prop1: { value: ..., writable: ..., ... },
      prop2: { get: ..., set: ..., ... },
      [Symbol(key)]: { ... }
    }

应用场景

  1. 深度克隆对象(保留属性特性)

    • Object.assign():只能复制可枚举的自身属性值。
    • Object.getOwnPropertyDescriptors() + Object.defineProperties():可完整克隆属性描述符。
    js
    function clone(obj) {
      return Object.defineProperties(
        {},
        Object.getOwnPropertyDescriptors(obj)
      );
    }
    
    const original = Object.defineProperty({}, "x", { value: 1, writable: false });
    const copy = clone(original);
    console.log(Object.getOwnPropertyDescriptor(copy, "x").writable); // false
  2. 混入(Mixin)属性:保留源对象属性的特性(如 getter/setter):

    js
    const source = {
      get data() { return this._data; },
      set data(v) { this._data = v; }
    };
    const target = {};
    
    Object.defineProperties(
      target,
      Object.getOwnPropertyDescriptors(source)
    );
    
    console.log(Object.getOwnPropertyDescriptor(target, "data").set); // function set(v)
  3. 复制原型方法:创建一个与原对象相同特性的新对象,包括原型链:

    js
    const obj = Object.create(
      Object.getPrototypeOf(original),
      Object.getOwnPropertyDescriptors(original)
    );

示例

  1. 基础使用

    js
    const obj = {
      name: "Alice",
      age: 30,
      // 存取器属性
      get fullName() {
        return `${this.name} Smith`;
      }
    };
    
    // 定义不可枚举属性
    Object.defineProperty(obj, "id", {
      value: "123",
      enumerable: false
    });
    
    const descriptors = Object.getOwnPropertyDescriptors(obj);
    console.log(descriptors);
    /* 输出:
    {
      name: { value: "Alice", writable: true, enumerable: true, configurable: true },
      age: { value: 30, writable: true, enumerable: true, configurable: true },
      fullName: { get: function get() {...}, set: undefined, enumerable: true, configurable: true },
      id: { value: "123", writable: false, enumerable: false, configurable: false }
    }
    */
  2. 处理 Symbol 属性

    js
    const sym = Symbol("key");
    const obj = { [sym]: "value" };
    
    const descriptors = Object.getOwnPropertyDescriptors(obj);
    console.log(descriptors[sym]); 
    // { value: "value", writable: true, enumerable: true, configurable: true }
  3. 空对象或非对象参数

    js
    console.log(Object.getOwnPropertyDescriptors({})); // {}
    console.log(Object.getOwnPropertyDescriptors(42)); // 转换后返回 Number 包装对象的自身属性描述符
    console.log(Object.getOwnPropertyDescriptors(null)); // TypeError: Cannot convert undefined or null to object

扩展限制

preventExtensions()

Object.preventExtensions()(obj),用于阻止对象扩展的方法,使目标对象无法添加新的属性。它属于对象的不可变性操作之一,与 Object.seal()Object.freeze() 形成层级递进的限制。

  • objobject,要禁止扩展的目标对象。

  • 返回:

  • objobject,返回传入的目标对象(obj)。若参数为原始类型,返回原值(无实际效果)。

语法特性

  1. 禁止新增属性:调用后,无法为对象添加新属性(静默失败或报错,取决于严格模式)。

  2. 不影响现有属性:可修改或删除已有属性(若其 configurabletrue)。

  3. 对比 seal 和 freeze

    • Object.seal():等效于 Object.preventExtensions() + 设置所有属性的configurable: false
    • Object.freeze():等效于 Object.seal() + 设置所有属性的 writable: false
    方法新增属性删除属性修改属性值修改属性描述符
    Object.preventExtensions()❌ 禁止✅ 允许✅ 允许✅ 允许(若可配置)
    Object.seal()❌ 禁止❌ 禁止✅ 允许❌ 禁止(除writable设为false)
    Object.freeze()❌ 禁止❌ 禁止❌ 禁止❌ 禁止
  4. 相关操作Object.isExtensible(obj):检测对象是否可扩展。

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

注意事项

  1. 不可逆操作:一旦对象被设为不可扩展,无法撤销此状态。

  2. 原型链不受影响:仍可为对象的原型添加属性,但这些属性不会出现在不可扩展的对象上。

    js
    const obj = Object.preventExtensions({});
    const proto = Object.getPrototypeOf(obj);
    proto.newProp = "test";
    console.log(obj.newProp); // "test"(来自原型链)

应用场景

  1. 防止意外扩展:确保对象结构固定,避免外部代码注入未知属性。

  2. 安全沙箱:在需要隔离第三方代码的环境中,限制对象行为。

  3. 性能优化:引擎可优化不可扩展对象的内存结构(实际效果因引擎而异)。

示例

  1. 基础使用

    js
    // 非严格模式:静默操作
    console.log(obj.b); // undefined
    
    // 严格模式:抛出错误
    "use strict";
    obj.c = 3; // TypeError: Cannot add property c, object is not extensible
  2. 允许修改或删除现有属性

    js
    const obj = { a: 1 };
    Object.defineProperty(obj, 'a', { writable: true, configurable: true });
    Object.preventExtensions(obj);
    
    obj.a = 10;   // 修改成功
    delete obj.a;  // 删除成功
    console.log(obj); // {}
  3. 原始类型参数处理

    js
    // 非严格模式:返回原值(无意义)
    const num = 42;
    console.log(Object.preventExtensions(num)); // 42
    
    // 严格模式:报错
    "use strict";
    Object.preventExtensions(42); // TypeError: 42 is not an object
seal()

Object.seal()(obj),用于封闭对象的方法。核心作用是:禁止添加新属性,标记所有现有属性为不可配置,允许修改现有属性的值。它属于对象的不可变性操作之一,与 Object.preventExtensions()Object.freeze() 形成递进限制。

  • objobject,要封闭的目标对象。

  • 返回:

  • objobject,返回被封闭的原对象(obj)。若参数为原始类型,返回转换后的包装对象。

核心行为

  1. 禁止新增属性

    js
    const obj = { a: 1 };
    Object.seal(obj);
    obj.b = 2; // 静默失败(严格模式下报错)
    console.log(obj.b); // undefined
  2. 禁止删除属性

    js
    delete obj.a; // 静默失败(严格模式下报错)
    console.log(obj.a); // 1
  3. 禁止修改属性描述符

    js
    Object.defineProperty(obj, "a", { enumerable: false }); 
    // TypeError: Cannot redefine property: a
  4. 允许修改属性值

    js
    obj.a = 10; // 成功(假设属性 `writable: true`)
    console.log(obj.a); // 10
  5. 对比 preventExtensions 和 freeze

    • Object.seal():等效于 Object.preventExtensions() + 设置所有属性的configurable: false
    • Object.freeze():等效于 Object.seal() + 设置所有属性的 writable: false
    方法新增属性删除属性修改属性值修改属性描述符
    Object.preventExtensions()❌ 禁止✅ 允许✅ 允许✅ 允许(若可配置)
    Object.seal()❌ 禁止❌ 禁止✅ 允许❌ 禁止(除writable设为false)
    Object.freeze()❌ 禁止❌ 禁止❌ 禁止❌ 禁止
  6. 相关操作Object.isSealed(obj):检测封闭状态。

    js
    console.log(Object.isSealed(obj)); // true

注意事项

  1. 不可逆操作:一旦对象被封闭,无法解除封闭状态。

  2. 严格模式下的行为:在严格模式中,违反封闭规则的操作会抛出错误:

    js
    "use strict";
    const sealedObj = Object.seal({});
    sealedObj.newProp = 1; // TypeError: Cannot add property newProp
  3. 原始类型参数

    • 非严格模式:原始值被转换为包装对象,但无法修改:

      js
      const numObj = Object.seal(42); // 转换为 Number 对象
      numObj.newProp = 1; // 无效(原始值的包装对象不可扩展)
    • 严格模式:直接报错:

      js
      "use strict";
      Object.seal(42); // TypeError: 42 is not an object
  4. 浅层封闭:Object.seal() 仅封闭目标对象自身的属性,若属性值为对象,需递归封闭以实现深度不可变:

    js
    function deepSeal(obj) {
      Object.seal(obj);
      Object.values(obj).forEach(val => {
        if (typeof val === "object" && val !== null) deepSeal(val);
      });
    }

应用场景

  1. 固定对象结构:确保对象属性不被意外添加或删除(如配置对象、枚举常量)。

  2. 安全沙箱:限制第三方库对关键对象的修改。

  3. 性能优化:引擎可优化不可变对象的内存结构(实际效果因引擎而异)。

示例

  1. 基本使用

    js
    const obj = { a: 1, nested: { b: 2 } };
    
    // 封闭对象
    Object.seal(obj);
    
    // 修改现有属性(允许)
    obj.a = 100;
    
    // 新增属性(禁止)
    obj.c = 3; // 无效
    
    // 删除属性(禁止)
    delete obj.a; // 无效
    
    // 修改属性描述符(禁止)
    Object.defineProperty(obj, "a", { writable: false }); // TypeError
    
    // 嵌套对象不受影响(浅层封闭)
    obj.nested.b = 200; // 允许
freeze()

Object.freeze()(obj),用于冻结对象的方法,其核心作用是禁止新增属性禁止删除属性禁止修改属性值禁止修改属性描述符。它是对象不可变性操作的最高限制级别,与 Object.preventExtensions()Object.seal() 形成递进关系。

  • objobject,要冻结的目标对象。

  • 返回:

  • objobject,返回被冻结的原对象(obj)。若参数为原始类型,返回转换后的包装对象。

核心行为

  1. 禁止任何修改

    js
    const obj = { a: 1 };
    Object.freeze(obj);
    
    // 新增属性(禁止)
    obj.b = 2; // 静默失败(严格模式下报错)
    
    // 删除属性(禁止)
    delete obj.a; // 静默失败(严格模式下报错)
    
    // 修改属性值(禁止)
    obj.a = 10; // 静默失败(严格模式下报错)
    
    // 修改属性描述符(禁止)
    Object.defineProperty(obj, "a", { value: 100 }); // TypeError
  2. 浅层冻结:冻结仅作用于对象自身的直接属性,嵌套对象不受影响

    js
    const obj = { nested: { b: 2 } };
    Object.freeze(obj);
    obj.nested.b = 20; // 允许(需递归冻结实现深度不可变)
  3. 相关操作Object.isFrozen(obj):检测冻结状态

    js
    console.log(Object.isFrozen(obj)); // true
  4. 对比 preventExtensions 和 seal

    • Object.seal():等效于 Object.preventExtensions() + 设置所有属性的configurable: false
    • Object.freeze():等效于 Object.seal() + 设置所有属性的 writable: false
    方法新增属性删除属性修改属性值修改属性描述符
    Object.preventExtensions()❌ 禁止✅ 允许✅ 允许✅ 允许(若可配置)
    Object.seal()❌ 禁止❌ 禁止✅ 允许❌ 禁止(除writable设为false)
    Object.freeze()❌ 禁止❌ 禁止❌ 禁止❌ 禁止

注意事项

  1. 不可逆操作:冻结后的对象无法解冻,需通过克隆新对象恢复可变性。

  2. 严格模式下的错误处理:在严格模式中,任何违反冻结规则的操作都会抛出错误:

    js
    "use strict";
    const frozen = Object.freeze({ a: 1 });
    frozen.a = 2; // TypeError: Cannot assign to read-only property 'a'
  3. 性能优化:冻结对象可能帮助 JavaScript 引擎优化内存管理(如 V8 引擎的隐藏类优化)。

  4. 实现深度冻结:递归冻结所有嵌套对象:

    js
    function deepFreeze(obj) {
      Object.freeze(obj);
      Object.values(obj).forEach(val => {
        if (typeof val === "object" && val !== null) deepFreeze(val);
      });
      return obj;
    }
    
    const data = { a: { b: 2 } };
    deepFreeze(data);
    data.a.b = 20; // 严格模式报错

应用场景

  1. 定义常量:全局配置、枚举值等需完全不可变的场景。
  2. 保护数据:防止第三方库或用户代码意外修改核心数据。
  3. 函数式编程:配合纯函数使用,确保输入数据不可变。
  4. 性能敏感场景:不可变数据便于引擎优化(如 React 状态管理)。

示例

  1. 基本使用

    js
    const config = {
      apiUrl: "https://api.example.com",
      timeout: 5000
    };
    
    // 冻结对象
    Object.freeze(config);
    
    // 尝试修改(严格模式下报错)
    config.apiUrl = "http://new.api"; // 无效
    config.newProp = "test";          // 无效
    delete config.timeout;            // 无效
    
    console.log(config); // { apiUrl: "https://api.example.com", timeout: 5000 }
  2. 原始类型参数

    js
    // 非严格模式:返回包装对象(无实际冻结效果)
    const numObj = Object.freeze(42); // 转换为 Number 对象
    numObj.newProp = 1;               // 无效(原始值不可变)
    
    // 严格模式:直接报错
    "use strict";
    Object.freeze(42); // TypeError: 42 is not an object
isExtensible()【

Object.isExtensible()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
isFrozen()【

Object.isFrozen()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
isSealed()【

Object.isSealed()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

迭代操作

entries()【

Object.entries()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
values()【

Object.values()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
keys()【

Object.keys()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

原型操作

getPrototypeOf()

Object.getPrototypeOf()(obj),用于获取对象的原型([[Prototype]] 的方法。

  • objobject,要获取原型的目标对象。

  • 返回:

  • objobject|null,返回对象的原型。若没有返回null。

核心行为

  1. 获取普通对象的原型

    js
    const obj = { a: 1 };
    const proto = Object.getPrototypeOf(obj);
    console.log(proto === Object.prototype); // true(普通对象的原型是 Object.prototype)
  2. 获取构造函数实例的原型

    js
    function Person(name) {
      this.name = name;
    }
    const alice = new Person("Alice");
    console.log(Object.getPrototypeOf(alice) === Person.prototype); // true
  3. 处理原始类型参数

    js
    // 原始类型会转换为包装对象
    console.log(Object.getPrototypeOf(42) === Number.prototype); // true
    console.log(Object.getPrototypeOf("text") === String.prototype); // true
    console.log(Object.getPrototypeOf(true) === Boolean.prototype); // true
    
    // 严格模式下参数为 null/undefined 会报错
    "use strict";
    Object.getPrototypeOf(null); // TypeError: Cannot convert undefined or null to object
  4. 特殊对象的原型

    js
    // 原型为 null 的对象
    const objNull = Object.create(null);
    console.log(Object.getPrototypeOf(objNull)); // null
    
    // 数组的原型链
    const arr = [1, 2];
    console.log(Object.getPrototypeOf(arr) === Array.prototype); // true

特性

  1. __proto__ 的替代方案obj.__proto__ 是非标准属性,而 Object.getPrototypeOf() 是 ECMAScript 标准方法,推荐优先使用。

    js
    const obj = {};
    console.log(Object.getPrototypeOf(obj) === obj.__proto__); // true(效果相同)
  2. 原型链的动态性:若通过 Object.setPrototypeOf() 修改对象原型,Object.getPrototypeOf() 会返回最新值:

    js
    const obj = {};
    const newProto = { b: 2 };
    Object.setPrototypeOf(obj, newProto);
    console.log(Object.getPrototypeOf(obj) === newProto); // true
  3. 不可变对象的原型:使用 Object.freeze()Object.seal() 不影响原型获取:

    js
    const frozenObj = Object.freeze({});
    console.log(Object.getPrototypeOf(frozenObj) === Object.prototype); // true
  4. 对比 instanceof

    特性Object.getPrototypeOf()instanceof
    返回值直接返回原型对象。返回布尔值,判断构造函数是否在原型链中。
    动态性始终反映当前原型。依赖构造函数的 prototype 属性。
    适用场景精确获取原型对象。快速判断实例类型。

应用场景

  1. 检查继承关系:验证对象是否属于特定构造函数或类的实例。

  2. 原型链操作:动态修改或分析对象的继承结构。

  3. 深拷贝工具:递归复制对象及其原型链属性。

  4. 多态性检查:判断对象是否具备原型链上的方法或属性。

setPrototypeOf()

Object.setPrototypeOf()(obj, prototype),用于动态修改对象的原型([[Prototype]] 的方法。它允许在运行时改变对象的继承关系,但因其性能开销较大,通常仅在特殊场景(如动态继承、原型链修复)中使用。

  • objobject,要修改原型的目标对象。
  • prototypeobject|null,新的原型对象或 null(表示无原型)。若为非对象或不可扩展对象,抛出 TypeError。
  • 返回:
  • objobject,返回修改后的原对象(obj)。若操作失败(如参数无效),抛出错误。

核心行为

  1. 修改对象的原型链

    js
    const parent = { greet() { return "Hello!" } };
    const child = {};
    
    // 将 child 的原型设为 parent
    Object.setPrototypeOf(child, parent);
    console.log(child.greet()); // "Hello!"(继承父原型方法)
  2. 设置为 null 以移除原型

    js
    const obj = {};
    Object.setPrototypeOf(obj, null);
    console.log(obj.toString); // undefined(无原型链方法)
  3. 严格模式下的参数限制

    • 非对象参数会报错:

      js
      "use strict";
      Object.setPrototypeOf(42, {}); // TypeError: Object.setPrototypeOf called on non-object
    • 无效的原型参数(如非对象且非 null)会报错:

      js
      Object.setPrototypeOf({}, 123); // TypeError: Object prototype may only be an Object or null

特性

  1. __proto__的替代方案obj.__proto__ = parent 是非标准属性,Object.setPrototypeOf() 是 ECMAScript 标准方法,推荐优先使用后者。

  2. 性能问题:动态修改原型会破坏 JavaScript 引擎的优化(如 V8 的隐藏类机制),导致性能下降,应尽量避免高频使用。

  3. 不可扩展对象的限制:若 prototype 参数是不可扩展对象(Object.preventExtensions()Object.seal()Object.freeze()),会抛出错误:

    js
    const proto = Object.preventExtensions({});
    Object.setPrototypeOf({}, proto); // TypeError: #<Object> is not extensible
  4. 原型链循环检测:若设置的原型链形成循环(如 A 的原型是 B,而 B 的原型是 A),会抛出错误:

    js
    const A = {};
    const B = {};
    Object.setPrototypeOf(A, B);
    Object.setPrototypeOf(B, A); // TypeError: Cyclic __proto__ value
  5. 对比 Object.create()

    方法作用适用场景
    Object.setPrototypeOf()修改已存在对象的原型动态调整继承关系、原型链修复。
    Object.create()创建时指定原型的新对象初始化对象继承结构。

示例

  1. 动态继承

    js
    // 定义两个原型
    const animal = { eat() { return "Eating..."; } };
    const bird = { fly() { return "Flying..."; } };
    
    // 创建对象并动态切换原型
    const penguin = {};
    Object.setPrototypeOf(penguin, animal);
    console.log(penguin.eat()); // "Eating..."
    
    // 修改原型为 bird(失去 animal 的方法)
    Object.setPrototypeOf(penguin, bird);
    console.log(penguin.fly()); // "Flying..."
    console.log(penguin.eat);   // undefined
  2. 修复原型链

    js
    function User(name) { this.name = name; }
    User.prototype.sayHi = function() { return `Hi, ${this.name}`; };
    
    // 意外覆盖原型
    User.prototype = null;
    
    // 修复原型链
    const user = new User("Alice");
    Object.setPrototypeOf(user, User.prototype); // 重新关联原型
    console.log(user.sayHi()); // "Hi, Alice"

其他

getOwnPropertyNames()【

Object.getOwnPropertyNames()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
getOwnPropertySymbols()【

Object.getOwnPropertySymbols()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
groupBy()【

Object.groupBy()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
hasOwn()【

Object.hasOwn()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js
is()【

Object.is()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

语法特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

应用场景

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js