JavaScript Object 对象完全指南:构造、属性与状态控制
本文系统讲解 JavaScript 中 Object 对象的核心用法。涵盖 Object 构造函数的参数行为、原型链相关方法,以及利用 Object.prototype.toString 进行精确类型判断的技巧。重点解析对象属性的元数据模型(value、writable、enumerable、configurable),详细介绍 Object.defineProperty 和 defineProperties 的定义与修改机制。最后深入探讨 preventExtensions、seal 和 freeze 三种对象状态控制方法,帮助开发者实现不可变对象与数据绑定。
Object 构造函数与参数行为
Object 对象在创建时可接受参数: (1)obj 必需。指定分配给 Object 对象的变量名称。 (2)值 可选。可以是任意 JavaScript 基本数据类型(数字、布尔值或字符串)。若传入值为对象,则直接返回该未修改的对象;若值为 null、“未定义”或未提供,则创建一个空对象。
Object 对象的方法与原型链
Object 对象的方法
当 Object 作为构造函数使用时,可接受一个参数。若该参数已是对象,则直接返回该对象;若为原始类型值,则返回对应的包装对象。利用这一特性,可以编写一个判断变量是否为对象的函数。
function isObject(value) {
return value === Object(value);
}
要在 Object 对象上部署方法,主要有两种实现方式。
一是直接部署在 Object 对象本身,二是部署在 Object.prototype 对象上。 Object.keys 方法与 Object.getOwnPropertyNames 方法功能相似,常用于遍历对象属性。两者均接受一个对象作为参数,并返回一个数组,该数组包含对象自身(非继承)的所有属性名。区别在于,前者仅返回可枚举属性,后者还包含不可枚举属性名。鉴于数组存在不可枚举的 length 属性,通常推荐使用 Object.keys 来遍历数组。
JavaScript 未提供直接计算对象属性个数的内置方法,可通过 Object.keys(o).length 或 Object.getOwnPropertyNames(o).length 来获取。
Object.observe 方法用于监听对象属性的变化。
与原型链相关的方法包括:
Object.create():用于生成一个新对象,并指定该对象的原型。 Object.getPrototypeOf():用于获取对象的原型对象。
Object 实例对象的方法包括: Object.prototype.valueOf():该方法返回对象的值,默认情况下返回对象本身。其主要用途是在 JavaScript 进行自动类型转换时,作为默认调用的方法。
Object.prototype.toString():该方法返回对象的字符串形式。当对象参与字符串加法运算时,会自动调用此方法。
通过 call 方法,可以在任意值上调用 Object.prototype.toString 方法,从而判断该值的类型。不同数据类型的 toString 方法返回值如下:
数值:返回 [object Number] 字符串:返回 [object String] 布尔值:返回 [object Boolean] undefined:返回 [object Undefined] null:返回 [object Null] 对象:返回 “[object “ + 构造函数的名称 + “]”
Object.prototype.toString.call(2) // "[object Number]"
Object.prototype.toString.call('') // "[object String]"
利用上述特性,可以编写一个比 typeof 运算符更准确的类型判断函数。
var type = function (o){
var s = Object.prototype.toString.call(o);
return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};
type({}); // "object"
type([]); // "array"
type(5); // "number"
在上述 type 函数的基础上,还可以扩展出专门判断特定类型数据的方法。
['Null', 'Undefined', 'Object', 'Array', 'String', 'Number',
'Boolean', 'Function', 'RegExp', 'Element', 'NaN', 'Infinite'
].forEach(function (t) {
type['is' + t] = function (o) {
return type(o) === t.toLowerCase();
};
});
type.isObject({}); // true
type.isNumber(NaN); // false
type.isElement(document.createElement('div')); // true
对象属性模型与描述符
对象的属性模型
在 JavaScript 内部,每个属性都对应一个 attributes 对象,用于保存该属性的元信息。使用 Object.getOwnPropertyDescriptor 方法,可以读取对象 o 的属性 p 的 attributes 对象。attributes 对象包含以下元信息:
value:表示该属性的值,默认为 undefined(只要 writable 和 configurable 有一个为 true,即可修改)。 writable:表示属性的值(value)是否可改变,默认为 true。 enumerable:表示该属性是否可枚举,默认为 true,即该属性会出现在 for…in 和 Object.keys() 等操作中。通常,系统原生属性(非用户自定义)为不可枚举。 configurable:表示“可配置性”,默认为 true。若设为 false,则无法删除该属性,也不能修改 attributes 对象(value 属性除外,若 writable 为 true,仍可改变 value)。configurable 属性控制了 attributes 对象的可写性。 getter:表示该属性的取值函数,默认为 undefined。 setter:表示该属性的存值函数,默认为 undefined。
var o = { p: 'a' };
Object.getOwnPropertyDescriptor(o, 'p');
// Object {
// value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }
Object.defineProperty 方法允许通过定义 attributes 对象来定义或修改一个属性,并返回修改后的对象。格式如下:
Object.defineProperty(object, propertyName, attributesObject) Object.defineProperty 方法接受三个参数:第一个是属性所在的对象,第二个是属性名(应为字符串),第三个是属性的描述对象。通过此方法定义属性时,属性对象的 writable、configurable、enumerable 三个属性的默认值均为 false。
Object.defineProperty(o, "p", {
value: "bar"
});
Object.getOwnPropertyDescriptor(o, 'p');
// Object {
// value: "bar",
// writable: false,
// enumerable: false,
// configurable: false
// }
若需一次性定义或修改多个属性,可使用 Object.defineProperties 方法。需要注意的是,一旦定义了取值函数 get(或存值函数 set),就不能将 writable 设为 true,也不能同时定义 value 属性,否则将报错。
var o = Object.defineProperties({}, {
p1: {value: 123, enumerable: true},
p2: {value: "abc", enumerable: true},
p3: {
get: function () {
return this.p1 + this.p2
},
enumerable: true,
configurable: true
}
});
enumerable 可用于设置“秘密”属性。若某属性的 enumerable 为 false,则 for..in 循环、Object.keys 方法和 JSON.stringify 方法均无法获取该属性,但仍可通过 o.xx 直接获取其值。
for…in 循环与 Object.keys 方法的区别在于,前者包含对象从原型继承的属性,而后者仅包含对象自身的属性。若需获取对象自身的所有属性(无论 enumerable 值),可使用 Object.getOwnPropertyNames 方法。
可配置性决定变量是否可被删除(delete)。使用 var 命令声明变量时,变量的 configurable 为 false;不使用 var 命令声明变量(或通过属性赋值方式声明)时,变量的可配置性为 true。这表明,delete 命令只能删除对象的属性。
var a1 = 1; // configurable: false
a2 = 1; // configurable: true(等价于this.a2 = 1)
除直接定义外,属性还可使用存取函数(accessor)定义。其中,存值函数称为 setter,使用 set 命令;取值函数称为 getter,使用 get 命令。利用存取函数,可实现数据对象与 DOM 对象的双向绑定。
Object.defineProperty(user, 'name', {
get: function () {
return document.getElementById("foo").value
},
set: function (newValue) {
document.getElementById("foo").value = newValue;
},
configurable: true
});
对象状态控制与防篡改
控制对象状态
JavaScript 提供了三种方法,用于精确控制对象的读写状态,防止对象被意外修改。保护层级由弱到强依次为:preventExtensions、seal 和 freeze。
Object.preventExtensions 方法使对象无法再添加新属性,但仍可使用 delete 命令删除现有属性。Object.isExtensible 方法用于检查是否可以为一个对象添加属性。
Object.seal 方法使对象既无法添加新属性,也无法删除旧属性。Object.seal 还会将现有属性的 attributes 对象中的 configurable 属性设为 false,使得 attributes 对象不可再改变。Object.isSealed 方法用于检查对象是否使用了 Object.seal 方法。
Object.freeze 方法使对象无法添加新属性、无法删除旧属性、也无法改变属性值,使该对象实际上变为常量。Object.isFrozen 方法用于检查对象是否使用了 Object.freeze() 方法。
使用上述方法锁定对象的可写性后,仍可通过改变该对象的原型对象来为其增加属性。
var o = new Object();
Object.preventExtensions(o);
var proto = Object.getPrototypeOf(o);
proto.t = "hello";
o.t
// hello
一种解决方案是,将原型也冻结住。
var o = Object.seal(
Object.create(Object.freeze({x:1}),
{y: {value: 2, writable: true}})
);
Object.getPrototypeOf(o).t = "hello";
o.t // undefined
PS: Object 对象包含在所有其他 JavaScript 对象中;其所有方法和属性均可用于所有其他对象。方法可在用户定义的对象中重新定义,并由 JavaScript 在适当时间调用。toString 方法是频繁重新定义的 Object 方法的一个示例。 在此语言参考中,每个 Object 方法的说明均包括内部 JavaScript 对象的默认和对象特定的实现信息。 IE 兼容方面,微软 MSDN 文档指出“已在 Internet Explorer 6 之前的 Internet Explorer 中引入 Object Object”,因此无需担心兼容性问题。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
