ECMAScript 5 属性描述符与对象控制详解

作者:半夏

时间:2026-10-28

浏览:356

本文深入解析 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; //fail

Object.seal

Object.seal 使对象仅允许修改现有属性值(若属性为只读,则连值也无法修改):


代码如下:

var obj = { };
obj.attr = 1;
Object.seal(obj);
obj.attr = 1.5;
delete obj.attr; // fail

Object.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 环境。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章