ECMAScript 5中的属性描述符详解


Posted in Javascript onMarch 02, 2015

属性描述符是ES5中新增的概念,其作用是给对象的属性增加更多的控制。

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 的写法看似更为复杂。但是,它最大的奥秘在于其第三个参数。

数据描述符

假设我们希望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 可以将其“藏”起来:
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定义为只读属性,然后又重新定义为可写。所以对attr的写入是成功的。

存取描述符

存取描述符类似面向对象中的get/set访问器。

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 可以使对象仅剩属性值可以修改(如果属性为只读,则连属性值都无法修改):
var obj = { };

obj.attr = 1;

Object.seal(obj);

obj.attr = 1.5;

delete obj.attr; // fail

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 相关文章推荐
强制设为首页代码
Jun 19 Javascript
不错的一个日期输入 动态
Nov 06 Javascript
jQuery判断元素是否是隐藏的代码
Apr 24 Javascript
基于jQuery的倒计时插件代码
May 07 Javascript
js新闻滚动 js如何实现新闻滚动效果
Jan 07 Javascript
Javascript alert消息换行的方法
Aug 07 Javascript
javascript跨域总结之window.name实现的跨域数据传输
Nov 01 Javascript
Json按某个键的值进行排序
Dec 22 Javascript
JavaScript函数表达式详解及实例
May 05 Javascript
node.js 模块和其下载资源的镜像设置的方法
Sep 06 Javascript
JS/CSS实现字符串单词首字母大写功能
Sep 03 Javascript
vue递归获取父元素的元素实例
Aug 07 Javascript
JS+CSS实现可以凹陷显示选中单元格的方法
Mar 02 #Javascript
JavaScript数组常用方法
Mar 02 #Javascript
使用npm发布Node.JS程序包教程
Mar 02 #Javascript
js实现点击链接后窗口缩小并居中的方法
Mar 02 #Javascript
运行Node.js的IIS扩展iisnode安装配置笔记
Mar 02 #Javascript
Javascript动画的实现原理浅析
Mar 02 #Javascript
JavaScript页面模板库handlebars的简单用法
Mar 02 #Javascript
You might like
一个简单的PHP入门源程序
2006/10/09 PHP
优化PHP代码的53条建议
2008/03/27 PHP
php冒泡排序、快速排序、快速查找、二维数组去重实例分享
2014/04/24 PHP
php删除数组中重复元素的方法
2015/12/22 PHP
jquery ajax 同步异步的执行 return值不能取得的解决方案
2012/01/08 Javascript
js动态添加onload、onresize、onscroll事件(另类方法)
2012/12/26 Javascript
js实现基于正则表达式的轻量提示插件
2015/08/29 Javascript
js鼠标按键事件和键盘按键事件用法实例汇总
2016/10/03 Javascript
React-Native实现ListView组件之上拉刷新实例(iOS和Android通用)
2017/07/11 Javascript
javascript高仿热血传奇游戏实现代码
2018/02/22 Javascript
微信小程序动画(Animation)的实现及执行步骤
2018/10/28 Javascript
Javascript组合继承方法代码实例解析
2020/04/02 Javascript
Vue3+elementui plus创建项目的方法
2020/12/01 Vue.js
[01:03:27]NAVI vs EG 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
[40:03]RNG vs VG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[01:11:11]Alliance vs RNG 2019国际邀请赛淘汰赛 败者组BO1 8.20.mp4
2020/07/19 DOTA
Python functools模块学习总结
2015/05/09 Python
Python常用的爬虫技巧总结
2016/03/28 Python
Python使用正则表达式抓取网页图片的方法示例
2017/04/21 Python
Python实现连接postgresql数据库的方法分析
2017/12/27 Python
python 简单照相机调用系统摄像头实现方法 pygame
2018/08/03 Python
详解python:time模块用法
2019/03/25 Python
python 实现Flask中返回图片流给前端展示
2020/01/09 Python
python标准库OS模块函数列表与实例全解
2020/03/10 Python
Python列表切片常用操作实例解析
2020/03/10 Python
使用Keras实现简单线性回归模型操作
2020/06/12 Python
vscode调试django项目的方法
2020/08/06 Python
波兰快递服务:Globkurier.pl
2019/11/08 全球购物
SHEIN美国:购买时髦的女性服装
2020/12/02 全球购物
四个太阳教学反思
2014/02/01 职场文书
小学生综合素质评语
2014/04/23 职场文书
我爱我家教学反思
2014/05/01 职场文书
捐款感谢信
2015/01/20 职场文书
毛主席纪念堂观后感
2015/06/17 职场文书
《确定位置》教学反思
2016/02/18 职场文书
pytorch加载预训练模型与自己模型不匹配的解决方案
2021/05/13 Python