ECMAScript 5 属性描述符与对象控制详解
本文深入解析 ECMAScript 5 引入的属性描述符机制,详细阐述 Object.defineProperty 方法的使用。内容涵盖数据描述符(writable、enumerable、configurable)与存取描述符(get/set)的具体应用,以及 Object.preventExtensions、Object.seal 和 Object.freeze 对对象状态的严格控制,旨在提升代码的严谨性与安全性。
属性描述符概述
属性描述符是 ECMAScript 5 标准中引入的重要概念,其核心作用在于为对象的属性提供更为精细的控制机制。
Object.defineProperty
理解属性描述符的关键在于掌握 Object.defineProperty 方法。该方法用于在对象上定义新属性或修改现有属性的行为,其函数原型如下:
代码如下:
Object.defineProperty(obj, prop, descriptor)使用示例:
代码如下:
var obj = { };
Object.defineProperty(obj, 'attr', { value: 1 });上述代码为 obj 对象添加了一个名为 attr 的属性,并赋予值 1。其效果等同于直接赋值:
代码如下:
var obj = { };
obj.attr = 1;虽然 Object.defineProperty 的语法看似比直接赋值复杂,但其核心价值体现在第三个参数 descriptor 中,它允许开发者对属性进行细粒度控制。
数据描述符详解
数据描述符
若希望将 attr 设置为只读属性,可以通过设置 writable 数据描述符来实现:
代码如下:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false
});
console.log(obj.attr);
obj.attr = 2; // fail
console.log(obj.attr);运行上述代码会发现,两次打印的 attr 值均为 1,表明赋值操作失败。这种静默失败在复杂代码中难以排查。若在严格模式下运行,赋值操作将抛出异常:
代码如下:
'use strict'; // 进入严格模式
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false
});
obj.attr = 2; // throw exception另一个数据描述符 enumerable 用于控制属性是否可被枚举。普通定义的属性默认可在 for...in 循环中枚举:
代码如下:
var obj = { };
obj.attr = 1;
for (var i in obj) { console.log(obj[i]); }
通过设置 enumerable 为 false,可以将属性隐藏:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
enumerable: false
});
for (var i in obj) { console.log(obj[i]); }执行上述代码,控制台无输出,因为 attr 属性已不可枚举。
此时可能产生疑问:已设置的属性描述符是否可修改?例如,能否将只读属性改为可写?这取决于 configurable 描述符,它控制属性描述符本身是否可被更改:
代码如下:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false,
configurable: true
});
Object.defineProperty(obj, 'attr', {
writable: true
});
obj.attr = 2;上述代码先将 attr 设为只读,随后通过重新定义将其改为可写,因此后续赋值成功。
存取描述符应用
存取描述符
存取描述符类似于面向对象编程中的 getter/setter 访问器:
代码如下:
var obj = { };
Object.defineProperty(obj, 'attr', {
set: function(val) { this._attr = Math.max(0, val); },
get: function() { return this._attr; }
});
obj.attr = -1;
console.log(obj.attr); // 0在上述代码中,对 attr 的访问实际转化为对内部属性 _attr 的操作,且 set 函数限制了最小值为 0。
获取属性描述符
获取属性描述符
前文主要介绍如何设置属性描述符,若需获取已设置的描述符信息,可使用 Object.getOwnPropertyDescriptor 方法:
代码如下:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false,
configurable: true
});
var desc = Object.getOwnPropertyDescriptor(obj, 'attr');
console.dir(desc);
对象控制方法
对象控制
前文所述 Object.defineProperty 操作的是对象属性,而以下三个方法直接作用于对象整体:
Object.preventExtensions 使对象无法添加新属性:
代码如下:
var obj = { };
obj.attr = 1;
Object.preventExtensions(obj);
obj.attr2 = 2; //failObject.seal
Object.seal 使对象仅允许修改现有属性值(若属性为只读,则连值也无法修改):
代码如下:
var obj = { };
obj.attr = 1;
Object.seal(obj);
obj.attr = 1.5;
delete obj.attr; // failObject.freeze
Object.freeze 使对象完全不可修改:
代码如下:
var obj = { };
obj.attr = 1;
Object.freeze(obj);
obj.attr = 1.5; // fail
obj.attr2 = 2; //fail若要判断对象是否曾被 preventExtensions、seal 或 freeze 处理,可分别调用 Object.isExtensible、Object.isSealed 和 Object.isFrozen,这三个方法用法简单,此处不再赘述。
综上所述,属性描述符能严格限制对象行为,增强代码严谨性。不足之处在于 ES5 仅在 IE9 及以上版本基本实现(且 IE9 不支持严格模式)。鉴于国内 IE8 仍有较高市场份额,该技术目前主要适用于移动端浏览器和 Node.js 环境。
JavaScript闭包与类(Class)的区别及适用场景对比
2026-11-05 15:48:57
JavaScript入门要学ES6吗?let与箭头函数等新特性解析
2026-11-05 14:49:16
JavaScript 8种数据类型详解:基本类型与引用类型的区别
2026-11-05 14:25:15
怎么在JavaScript中使用async/await优化Ajax异步流程
2026-11-05 13:56:15
JavaScript replace回调函数实现动态正则替换逻辑
2026-11-05 13:52:13
