Object
[TOC]
索引
Object
属性
__proto__
object.__proto__:Object
,已弃用,用于访问或修改对象原型([[Prototype]]
) 的非标准属性。
语法特性:
获取/设置原型:
jsobject.__proto__; // 返回对象的原型 object.__proto__ = prototypeObject; // 修改对象的原型
替代标准方法:
对比标准方法:
操作 __proto__
Object.get/setPrototypeOf()
代码可读性 较低(非显式方法调用) 更高(明确语义) 兼容性 部分旧环境不支持 ES6+ 广泛支持 安全性 可能被误覆盖 无此风险
注意事项:
性能问题:动态修改原型(
obj.__proto__ = ...
)会破坏 JavaScript 引擎优化(如 V8 隐藏类),导致性能下降。原型链污染风险:直接修改原型可能引发不可预见的副作用(如覆盖内置方法):
jsArray.prototype.push = () => "Hacked!"; // 危险操作! console.log([].push()); // "Hacked!"
示例:
获取对象原型:
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
设置对象原型:
jsconst parent = { greet: () => "Hello!" }; const child = {}; child.__proto__ = parent; // 设置child的对象原型为parent console.log(child.greet()); // "Hello!"
非法设置操作:
jsconst obj = {}; // 尝试设置非对象/非 null 值 obj.__proto__ = 42; // TypeError: Object prototype may only be an Object or null
constructor
object.constructor:构造函数
,指向创建该对象的构造函数。它通常用于获取对象类型或创建同类新对象,但在某些场景下需要谨慎使用(如原型继承时可能被覆盖)。
语法特性:
获取对象的构造函数:
jsconst 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
通过构造函数创建新对象:
jsconst 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 }
原型继承中的 constructor 问题:若手动修改原型链,需修正 constructor 的指向:
jsfunction 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(修正后正确)
注意事项:
constructor 的可信度:
- 若对象是通过字面量(如
{}
、[]
)或构造函数创建的,constructor
指向正确。 - 若原型链被手动修改(如
Object.create()
),可能指向错误,需显式修正:
jsconst obj = Object.create(Array.prototype); console.log(obj.constructor === Array); // true(但 obj 并非真正的数组)
- 若对象是通过字面量(如
直接调用 constructor() 的 this指向风险:未使用 new 操作符时,构造函数内的 this 可能指向全局对象(非严格模式)或报错(严格模式):
jsfunction Person(name) { this.name = name; } const bob = Person("Bob"); // 非严格模式下,this 指向 window,污染全局变量 console.log(window.name); // "Bob"
null 和原始值的 constructor:
null 和 undefined 无 constructor 属性。
原始值(如 "text"、42)的 constructor 指向包装对象的构造函数:
jsconsole.log("text".constructor === String); // true console.log((42).constructor === Number); // true
应用场景:
动态创建同类对象:
jsconst newObj = new existingObj.constructor();
类型检测:
jsif (obj.constructor === Array) { ... } // 不如 Array.isArray() 可靠
原型链修复:
jsChild.prototype.constructor = Child;
静态方法
创建对象
new Object()
new Object():(value?)
,创建对象的一种方式,但现代开发中更推荐使用对象字面量({}
)以提高代码简洁性和性能。
value?:
any
,用于初始化对象的任意类型的值。返回:
obj:
object
,根据 value 的类型返回对应的对象。
语法特性:
参数类型与行为:根据参数类型的不同返回的对象也不同。
- 无参数/
null
/undefined
:返回空对象({}
)。 - 原始类型:返回对应的包装对象(如
Number
,String
,Boolean
)。 - 对象/数组/函数:直接返回原始对象,不创建新对象(数组仍是数组,函数仍是函数)。
- 无参数/
对比对象字面量
{}
:特性 new Object()
对象字面量 {}
语法简洁性 冗长(需构造函数调用) 简洁直接 性能 略低(需解析构造函数) 更高(引擎直接优化) 可读性 较低(需理解构造函数行为) 更高(直观表达对象结构) 使用场景 动态生成对象(如根据变量类型转换) 静态定义对象结构(推荐日常使用)
注意事项:
原始值的包装对象:使用 new Object() 传入原始值会创建包装对象,可能导致类型判断问题:
jsconst numObj = new Object(5); console.log(typeof numObj); // "object"(而非 "number") console.log(numObj instanceof Number); // true
无意义的 null/undefined 参数:传入 null 或 undefined 与无参数效果相同,但可能引发误解:
jsconsole.log(new Object(null)); // {}(并非 null)
避免冗余使用:对象字面量 {} 更高效且简洁,应优先使用:
js// 推荐 const obj = { a: 1 }; // 不推荐 const obj = new Object({ a: 1 });
示例:
基本使用:
jsconst emptyObj = new Object(); // {} const numObj = new Object(100); // Number {100} const strObj = new Object("text"); // String {"text"}
对象类型参数:
jsconst existingObj = { a: 1 }; const newObj = new Object(existingObj); console.log(newObj === existingObj); // true(同一对象)
数组与函数:
jsconst arr = new Object([1, 2, 3]); // [1, 2, 3] const func = new Object(function() {}); // function() {}
assign()
Object.assign():(target, ...sources?)
,用于合并对象属性的方法,它将一个或多个源对象(source)的可枚举自身属性复制到目标对象(target),并返回修改后的目标对象。此方法执行的是浅拷贝。
target:
object
,目标对象,接收复制的属性。若参数非对象,会尝试转换为对象;若为 null/undefined 会报错。...sources?:
object
,源对象(可多个)。若参数非对象(如原始值),会转换为包装对象;若为 null/undefined则忽略。返回:
target:
object
,修改后的目标对象。
核心特性:
属性复制规则:
- 同名覆盖:后传入的源对象属性会覆盖之前的同名属性。
- 浅拷贝:若属性值为对象,复制的是引用而非新对象。
- 仅复制可枚举的自身属性:忽略继承属性和不可枚举属性(如
enumerable: false
的属性)。 - Symbol 属性:可复制 Symbol 类型的键名。
参数处理:
目标对象非对象:原始值会被转换为包装对象(如
5
→Number(5)
),但操作后仍返回原始类型(不常见)。jsconst str = 'hello'; const result = Object.assign(str, { a: 1 }); // String {'hello', a: 1} console.log(result.a); // 1
源对象为
null
/undefined
:直接跳过,不报错。jsObject.assign({}, null, undefined, { a: 1 }); // { a: 1 }
注意事项:
浅拷贝风险:若属性值为对象或数组,目标对象和源对象会共享同一引用,修改一方会影响另一方。
jsconst source = { arr: [1, 2] }; const target = Object.assign({}, source); target.arr.push(3); console.log(source.arr); // [1, 2, 3]
无法复制存取器属性(getter/setter):Object.assign() 会将存取器属性的值(调用 getter 的结果)复制到目标对象,而非保留 getter/setter。
jsconst source = { get value() { return 42; } }; const target = Object.assign({}, source); console.log(target.value); // 42(数据属性,而非 getter)
异常会中断复制:若复制过程中某个属性不可写(如目标对象的属性为只读),会抛出 TypeError,且已复制的属性保留。
jsconst 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 复制成功)
Symbol 属性支持:
jsconst sym = Symbol('key'); const source = { [sym]: 'value' }; const target = Object.assign({}, source); console.log(target[sym]); // 'value'
应用场景:
对象合并:合并配置项、状态更新(如 Redux reducer)。
浅拷贝对象:快速克隆对象(需注意嵌套引用问题)。
添加默认值:为函数参数提供默认配置。
Mixin:将多个对象的属性混合到一个对象中。
示例:
合并多个对象:
jsconst 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(直接修改目标对象)
克隆对象(浅拷贝):
jsconst 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(引用对象被修改)
处理原始值源对象:字符串会被转为字符数组形式的对象。
jsconst obj = Object.assign({}, 'abc', true, 10); console.log(obj); // {0: 'a', 1: 'b', 2: 'c'}(字符串被转为字符数组形式的对象)
忽略继承属性:
jsconst parent = { parentProp: 'parent' }; const child = Object.create(parent); child.childProp = 'child'; const obj = Object.assign({}, child); console.log(obj); // { childProp: 'child' }(不复制继承属性)
create()
Object.create():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
fromEntries()【
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
属性描述符
defineProperty()
Object.defineProperty():(obj, prop, descriptor)
,用于精确控制对象属性行为的核心方法。允许开发者直接在一个对象上定义新属性或修改现有属性,并通过属性描述符精确配置属性的读写性、可枚举性、可配置性等特性。
obj:
object
,目标对象,用于定义或修改属性。prop:
string|symbol
,属性名称。descriptor:
object
,属性描述符对象,包含配置属性行为的键值对。返回:
obj:
object
,传入函数的目标对象,其指定的属性已被添加或修改。
语法特性:
属性描述符默认值:
- 使用defineProperty显式设置的属性,属性描述符项选项默认为false。
- 使用字面量定义的属性,属性描述符项选项默认为true。
jsconst obj = {}; Object.defineProperty(obj, 'prop', { value: 10 }); // configurable/enumerable/writable默认false console.log(obj.prop); // 10 obj.prop = 20; // 静默失败(writable 默认为 false)
不可逆操作:
configurable: false
后,无法再修改描述符(除 writable 从 true 改为 false)。jsObject.defineProperty(obj, 'x', { configurable: false }); Object.defineProperty(obj, 'x', { enumerable: true }); // TypeError
严格模式报错:在严格模式下,违反属性配置的操作(如修改只读属性)会抛出错误。
js'use strict'; obj.readOnlyProp = 100; // TypeError: Cannot assign to read only property
应用场景:
数据劫持(响应式系统):Vue 2.x 使用 Object.defineProperty() 实现数据双向绑定。
jsfunction observe(obj, key, callback) { let value = obj[key]; Object.defineProperty(obj, key, { get() { return value; }, set(newVal) { if (value !== newVal) { value = newVal; callback(newVal); // 调用钩子函数 } } }); }
创建不可变属性:防止关键属性被意外修改或删除。
jsconst config = {}; Object.defineProperty(config, 'apiUrl', { value: 'https://api.example.com', writable: false, configurable: false });
隐藏内部状态:封装对象内部状态,仅暴露受控接口。
jsclass Counter { constructor() { let count = 0; Object.defineProperty(this, 'count', { get: () => count, set: (value) => { throw new Error('count is read-only'); } }); this.increment = () => count++; } }
示例:
定义只读属性:
jsconst obj = {}; Object.defineProperty(obj, 'readOnlyProp', { value: 42, writable: false, // 不可写 enumerable: true, // 可枚举 configurable: false // 不可删除或修改描述符 }); obj.readOnlyProp = 100; // 静默失败(严格模式下报错) console.log(obj.readOnlyProp); // 42
使用存取描述符(Getter/Setter):
jsconst 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"
控制属性的可枚举性:
jsconst 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)
,用于批量定义或修改对象属性的方法,允许通过一次调用配置多个属性的特性(如读写性、可枚举性等)。
obj:
object
,目标对象,用于定义或修改属性。props:
{key: Descriptor,...
,属性描述符集合,键名为属性名(字符串或 Symbol),键值为属性描述符对象。返回:
obj:
object
,传入函数的目标对象,其指定的属性已被添加或修改。
语法特性:
属性描述符默认值:若未显式设置 enumerable、configurable 或 writable,它们的默认值为 false。
js// prop 的描述符等同于 { value: 1, writable: false, enumerable: false, configurable: false } Object.defineProperties(obj, { prop: { value: 1 } });
不可逆操作:若某属性的 configurable 设为 false,后续无法修改其描述符(除 writable 从 true 改为 false)。
jsObject.defineProperties(obj, { key: { configurable: false } }); Object.defineProperties(obj, { key: { enumerable: true } // TypeError: Cannot redefine property });
严格模式报错:在严格模式下,违反描述符规则的操作会抛出错误:
js'use strict'; const obj = {}; Object.defineProperties(obj, { x: { value: 10 } }); obj.x = 20; // TypeError: Cannot assign to read-only property 'x'
对象不可扩展性:若目标对象不可扩展(
Object.preventExtensions()
),添加新属性会报错:jsconst obj = Object.preventExtensions({}); Object.defineProperties(obj, { newProp: { value: 1 } }); // TypeError: Cannot define property
对比 Object.defineProperty():
特性 Object.defineProperty()
Object.defineProperties()
操作属性数量 一次只能定义或修改一个属性。 可批量定义或修改多个属性。 语法简洁性 适用于单个属性操作。 适用于批量属性配置,代码更集中。 使用场景 动态添加或修改单个属性。 初始化对象、批量配置属性特性。
应用场景:
批量初始化属性:统一配置多个属性的特性(如隐藏内部状态)。
jsclass Logger { constructor() { Object.defineProperties(this, { _logs: { value: [], writable: true }, logCount: { get() { return this._logs.length; }, enumerable: true } }); } }
数据响应式系统:Vue 2.x 使用 Object.defineProperties() 批量定义响应式属性。
jsfunction 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; }
不可变配置对象:创建不可修改的全局配置。
jsconst config = {}; Object.defineProperties(config, { apiUrl: { value: 'https://api.example.com', writable: false }, timeout: { value: 5000, writable: false } });
示例:
批量定义数据属性:
jsconst 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 不可枚举)
混合数据属性和存取描述符:
jsconst 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
默认值行为:未显式设置的描述符键(如 enumerable)默认为 false:
jsconst 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)
,用于获取对象自身属性的描述符的方法。
obj:
object
,要查询属性描述符的目标对象。prop:
string|Symbol
,目标属性的键名。返回:
descriptor:
object|undefined
,返回结果如下:object
:返回属性描述符对象(包含value
、writable
、enumerable
、configurable
或get
、set
)。undefined
:如果目标对象不存在该属性或obj
参数无效返回undefined。
语法特性:
仅获取自身属性:若属性是继承的(来自原型链),返回 undefined。
jsconst arr = [1, 2]; console.log(Object.getOwnPropertyDescriptor(arr, "length")); // 存在(自身属性) console.log(Object.getOwnPropertyDescriptor(arr, "toString")); // undefined(继承自原型)
Symbol 属性支持:
jsconst sym = Symbol("key"); const obj = { [sym]: "value" }; const descriptor = Object.getOwnPropertyDescriptor(obj, sym); console.log(descriptor.value); // "value"
严格模式下的参数类型:非对象参数在严格模式下可能报错:
js"use strict"; Object.getOwnPropertyDescriptor(1, "x"); // TypeError: 1 is not an object
应用场景:
属性检查:验证属性是否可配置、可枚举或可写。
动态代理: 结合 Object.defineProperty() 实现属性拦截(如 Vue 2.x 响应式系统)。
深拷贝工具:通过描述符克隆属性特性,而非简单复制值。
兼容性处理:检测浏览器对某些属性的支持情况(如 configurable 是否可修改)。
示例:
获取数据描述符:
jsconst 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 } */
获取存取描述符:
jsconst 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 } */
不存在的属性或无效对象:
jsconsole.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 的批量版,适用于需要全面分析或复制对象属性的场景(如深度克隆、元编程)。
obj:
obj
,要查询属性描述符的目标对象。返回:
descriptors:
{key: Descriptor,...}
,包含目标对象所有自身属性的描述符集合。可以作为参数传递给其他静态方法(如defineProperties,create)。
语法特性:
包含所有自身属性:
- 可枚举与不可枚举属性:无论属性是否可枚举(
enumerable: true/false
),均会被包含。 - Symbol 属性:支持 Symbol 类型的键名。
- 不包含继承属性:仅处理目标对象自身的属性。
- 可枚举与不可枚举属性:无论属性是否可枚举(
返回值结构:返回对象的每个键值对表示一个属性的描述符,结构与 Object.getOwnPropertyDescriptor() 一致:
js{ prop1: { value: ..., writable: ..., ... }, prop2: { get: ..., set: ..., ... }, [Symbol(key)]: { ... } }
应用场景:
深度克隆对象(保留属性特性):
Object.assign()
:只能复制可枚举的自身属性值。Object.getOwnPropertyDescriptors()
+Object.defineProperties()
:可完整克隆属性描述符。
jsfunction 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
混入(Mixin)属性:保留源对象属性的特性(如 getter/setter):
jsconst 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)
复制原型方法:创建一个与原对象相同特性的新对象,包括原型链:
jsconst obj = Object.create( Object.getPrototypeOf(original), Object.getOwnPropertyDescriptors(original) );
示例:
基础使用:
jsconst 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 } } */
处理 Symbol 属性:
jsconst sym = Symbol("key"); const obj = { [sym]: "value" }; const descriptors = Object.getOwnPropertyDescriptors(obj); console.log(descriptors[sym]); // { value: "value", writable: true, enumerable: true, configurable: true }
空对象或非对象参数:
jsconsole.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()
形成层级递进的限制。
obj:
object
,要禁止扩展的目标对象。返回:
obj:
object
,返回传入的目标对象(obj)。若参数为原始类型,返回原值(无实际效果)。
语法特性:
禁止新增属性:调用后,无法为对象添加新属性(静默失败或报错,取决于严格模式)。
不影响现有属性:可修改或删除已有属性(若其
configurable
为true
)。对比 seal 和 freeze:
Object.seal()
:等效于Object.preventExtensions()
+ 设置所有属性的configurable: false
。Object.freeze()
:等效于Object.seal()
+ 设置所有属性的writable: false
。
方法 新增属性 删除属性 修改属性值 修改属性描述符 Object.preventExtensions()
❌ 禁止 ✅ 允许 ✅ 允许 ✅ 允许(若可配置) Object.seal()
❌ 禁止 ❌ 禁止 ✅ 允许 ❌ 禁止(除writable设为false) Object.freeze()
❌ 禁止 ❌ 禁止 ❌ 禁止 ❌ 禁止 相关操作:Object.isExtensible(obj):检测对象是否可扩展。
jsconst obj = { a: 1 }; console.log(Object.isExtensible(obj)); // true Object.preventExtensions(obj); console.log(Object.isExtensible(obj)); // false
注意事项:
不可逆操作:一旦对象被设为不可扩展,无法撤销此状态。
原型链不受影响:仍可为对象的原型添加属性,但这些属性不会出现在不可扩展的对象上。
jsconst obj = Object.preventExtensions({}); const proto = Object.getPrototypeOf(obj); proto.newProp = "test"; console.log(obj.newProp); // "test"(来自原型链)
应用场景:
防止意外扩展:确保对象结构固定,避免外部代码注入未知属性。
安全沙箱:在需要隔离第三方代码的环境中,限制对象行为。
性能优化:引擎可优化不可扩展对象的内存结构(实际效果因引擎而异)。
示例:
基础使用:
js// 非严格模式:静默操作 console.log(obj.b); // undefined // 严格模式:抛出错误 "use strict"; obj.c = 3; // TypeError: Cannot add property c, object is not extensible
允许修改或删除现有属性:
jsconst obj = { a: 1 }; Object.defineProperty(obj, 'a', { writable: true, configurable: true }); Object.preventExtensions(obj); obj.a = 10; // 修改成功 delete obj.a; // 删除成功 console.log(obj); // {}
原始类型参数处理:
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()
形成递进限制。
obj:
object
,要封闭的目标对象。返回:
obj:
object
,返回被封闭的原对象(obj)。若参数为原始类型,返回转换后的包装对象。
核心行为:
禁止新增属性:
jsconst obj = { a: 1 }; Object.seal(obj); obj.b = 2; // 静默失败(严格模式下报错) console.log(obj.b); // undefined
禁止删除属性:
jsdelete obj.a; // 静默失败(严格模式下报错) console.log(obj.a); // 1
禁止修改属性描述符:
jsObject.defineProperty(obj, "a", { enumerable: false }); // TypeError: Cannot redefine property: a
允许修改属性值:
jsobj.a = 10; // 成功(假设属性 `writable: true`) console.log(obj.a); // 10
对比 preventExtensions 和 freeze:
Object.seal()
:等效于Object.preventExtensions()
+ 设置所有属性的configurable: false
。Object.freeze()
:等效于Object.seal()
+ 设置所有属性的writable: false
。
方法 新增属性 删除属性 修改属性值 修改属性描述符 Object.preventExtensions()
❌ 禁止 ✅ 允许 ✅ 允许 ✅ 允许(若可配置) Object.seal()
❌ 禁止 ❌ 禁止 ✅ 允许 ❌ 禁止(除writable设为false) Object.freeze()
❌ 禁止 ❌ 禁止 ❌ 禁止 ❌ 禁止 相关操作:Object.isSealed(obj):检测封闭状态。
jsconsole.log(Object.isSealed(obj)); // true
注意事项:
不可逆操作:一旦对象被封闭,无法解除封闭状态。
严格模式下的行为:在严格模式中,违反封闭规则的操作会抛出错误:
js"use strict"; const sealedObj = Object.seal({}); sealedObj.newProp = 1; // TypeError: Cannot add property newProp
原始类型参数:
非严格模式:原始值被转换为包装对象,但无法修改:
jsconst numObj = Object.seal(42); // 转换为 Number 对象 numObj.newProp = 1; // 无效(原始值的包装对象不可扩展)
严格模式:直接报错:
js"use strict"; Object.seal(42); // TypeError: 42 is not an object
浅层封闭:Object.seal() 仅封闭目标对象自身的属性,若属性值为对象,需递归封闭以实现深度不可变:
jsfunction deepSeal(obj) { Object.seal(obj); Object.values(obj).forEach(val => { if (typeof val === "object" && val !== null) deepSeal(val); }); }
应用场景:
固定对象结构:确保对象属性不被意外添加或删除(如配置对象、枚举常量)。
安全沙箱:限制第三方库对关键对象的修改。
性能优化:引擎可优化不可变对象的内存结构(实际效果因引擎而异)。
示例:
基本使用:
jsconst 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()
形成递进关系。
obj:
object
,要冻结的目标对象。返回:
obj:
object
,返回被冻结的原对象(obj)。若参数为原始类型,返回转换后的包装对象。
核心行为:
禁止任何修改:
jsconst obj = { a: 1 }; Object.freeze(obj); // 新增属性(禁止) obj.b = 2; // 静默失败(严格模式下报错) // 删除属性(禁止) delete obj.a; // 静默失败(严格模式下报错) // 修改属性值(禁止) obj.a = 10; // 静默失败(严格模式下报错) // 修改属性描述符(禁止) Object.defineProperty(obj, "a", { value: 100 }); // TypeError
浅层冻结:冻结仅作用于对象自身的直接属性,嵌套对象不受影响:
jsconst obj = { nested: { b: 2 } }; Object.freeze(obj); obj.nested.b = 20; // 允许(需递归冻结实现深度不可变)
相关操作:Object.isFrozen(obj):检测冻结状态
jsconsole.log(Object.isFrozen(obj)); // true
对比 preventExtensions 和 seal:
Object.seal()
:等效于Object.preventExtensions()
+ 设置所有属性的configurable: false
。Object.freeze()
:等效于Object.seal()
+ 设置所有属性的writable: false
。
方法 新增属性 删除属性 修改属性值 修改属性描述符 Object.preventExtensions()
❌ 禁止 ✅ 允许 ✅ 允许 ✅ 允许(若可配置) Object.seal()
❌ 禁止 ❌ 禁止 ✅ 允许 ❌ 禁止(除writable设为false) Object.freeze()
❌ 禁止 ❌ 禁止 ❌ 禁止 ❌ 禁止
注意事项:
不可逆操作:冻结后的对象无法解冻,需通过克隆新对象恢复可变性。
严格模式下的错误处理:在严格模式中,任何违反冻结规则的操作都会抛出错误:
js"use strict"; const frozen = Object.freeze({ a: 1 }); frozen.a = 2; // TypeError: Cannot assign to read-only property 'a'
性能优化:冻结对象可能帮助 JavaScript 引擎优化内存管理(如 V8 引擎的隐藏类优化)。
实现深度冻结:递归冻结所有嵌套对象:
jsfunction 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; // 严格模式报错
应用场景:
- 定义常量:全局配置、枚举值等需完全不可变的场景。
- 保护数据:防止第三方库或用户代码意外修改核心数据。
- 函数式编程:配合纯函数使用,确保输入数据不可变。
- 性能敏感场景:不可变数据便于引擎优化(如 React 状态管理)。
示例:
基本使用:
jsconst 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 }
原始类型参数:
js// 非严格模式:返回包装对象(无实际冻结效果) const numObj = Object.freeze(42); // 转换为 Number 对象 numObj.newProp = 1; // 无效(原始值不可变) // 严格模式:直接报错 "use strict"; Object.freeze(42); // TypeError: 42 is not an object
isExtensible()【
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
isFrozen()【
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
isSealed()【
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
迭代操作
entries()【
Object.entries():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
values()【
Object.values():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
keys()【
Object.keys():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
原型操作
getPrototypeOf()
Object.getPrototypeOf():(obj)
,用于获取对象的原型([[Prototype]]
) 的方法。
obj:
object
,要获取原型的目标对象。返回:
obj:
object|null
,返回对象的原型。若没有返回null。
核心行为:
获取普通对象的原型
jsconst obj = { a: 1 }; const proto = Object.getPrototypeOf(obj); console.log(proto === Object.prototype); // true(普通对象的原型是 Object.prototype)
获取构造函数实例的原型
jsfunction Person(name) { this.name = name; } const alice = new Person("Alice"); console.log(Object.getPrototypeOf(alice) === Person.prototype); // true
处理原始类型参数
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
特殊对象的原型
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
特性:
__proto__ 的替代方案:
obj.__proto__
是非标准属性,而Object.getPrototypeOf()
是 ECMAScript 标准方法,推荐优先使用。jsconst obj = {}; console.log(Object.getPrototypeOf(obj) === obj.__proto__); // true(效果相同)
原型链的动态性:若通过
Object.setPrototypeOf()
修改对象原型,Object.getPrototypeOf()
会返回最新值:jsconst obj = {}; const newProto = { b: 2 }; Object.setPrototypeOf(obj, newProto); console.log(Object.getPrototypeOf(obj) === newProto); // true
不可变对象的原型:使用
Object.freeze()
或Object.seal()
不影响原型获取:jsconst frozenObj = Object.freeze({}); console.log(Object.getPrototypeOf(frozenObj) === Object.prototype); // true
对比 instanceof:
特性 Object.getPrototypeOf()
instanceof
返回值 直接返回原型对象。 返回布尔值,判断构造函数是否在原型链中。 动态性 始终反映当前原型。 依赖构造函数的 prototype
属性。适用场景 精确获取原型对象。 快速判断实例类型。
应用场景:
检查继承关系:验证对象是否属于特定构造函数或类的实例。
原型链操作:动态修改或分析对象的继承结构。
深拷贝工具:递归复制对象及其原型链属性。
多态性检查:判断对象是否具备原型链上的方法或属性。
setPrototypeOf()
Object.setPrototypeOf():(obj, prototype)
,用于动态修改对象的原型([[Prototype]]
) 的方法。它允许在运行时改变对象的继承关系,但因其性能开销较大,通常仅在特殊场景(如动态继承、原型链修复)中使用。
- obj:
object
,要修改原型的目标对象。 - prototype:
object|null
,新的原型对象或 null(表示无原型)。若为非对象或不可扩展对象,抛出 TypeError。 - 返回:
- obj:
object
,返回修改后的原对象(obj)。若操作失败(如参数无效),抛出错误。
核心行为:
修改对象的原型链:
jsconst parent = { greet() { return "Hello!" } }; const child = {}; // 将 child 的原型设为 parent Object.setPrototypeOf(child, parent); console.log(child.greet()); // "Hello!"(继承父原型方法)
设置为 null 以移除原型:
jsconst obj = {}; Object.setPrototypeOf(obj, null); console.log(obj.toString); // undefined(无原型链方法)
严格模式下的参数限制:
非对象参数会报错:
js"use strict"; Object.setPrototypeOf(42, {}); // TypeError: Object.setPrototypeOf called on non-object
无效的原型参数(如非对象且非
null
)会报错:jsObject.setPrototypeOf({}, 123); // TypeError: Object prototype may only be an Object or null
特性:
__proto__的替代方案:
obj.__proto__ = parent
是非标准属性,Object.setPrototypeOf()
是 ECMAScript 标准方法,推荐优先使用后者。性能问题:动态修改原型会破坏 JavaScript 引擎的优化(如 V8 的隐藏类机制),导致性能下降,应尽量避免高频使用。
不可扩展对象的限制:若
prototype
参数是不可扩展对象(Object.preventExtensions()
、Object.seal()
、Object.freeze()
),会抛出错误:jsconst proto = Object.preventExtensions({}); Object.setPrototypeOf({}, proto); // TypeError: #<Object> is not extensible
原型链循环检测:若设置的原型链形成循环(如
A
的原型是B
,而B
的原型是A
),会抛出错误:jsconst A = {}; const B = {}; Object.setPrototypeOf(A, B); Object.setPrototypeOf(B, A); // TypeError: Cyclic __proto__ value
对比 Object.create():
方法 作用 适用场景 Object.setPrototypeOf()
修改已存在对象的原型 动态调整继承关系、原型链修复。 Object.create()
创建时指定原型的新对象 初始化对象继承结构。
示例:
动态继承
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
修复原型链:
jsfunction 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():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
getOwnPropertySymbols()【
Object.getOwnPropertySymbols():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
groupBy()【
Object.groupBy():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
hasOwn()【
Object.hasOwn():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js
is()【
Object.is():()
,
:``,
:``,
:``,
返回:
:``,
语法特性:
****:
js****:
js****:
js
应用场景:
****:
js****:
js****:
js
示例:
****:
js****:
js****:
js