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 相关文章推荐
javascript中注册和移除事件的4种方式
Mar 20 Javascript
JavaScript之IE的fireEvent方法详细解析
Nov 20 Javascript
JavaScript DOM进阶方法
Apr 13 Javascript
jQuery 判断图片是否加载完成方法汇总
Aug 10 Javascript
跟我学习javascript的循环
Nov 18 Javascript
JavaScript面向对象之私有静态变量实例分析
Jan 14 Javascript
原生js实现addclass,removeclass,toggleclasss实例
Nov 24 Javascript
在javascript中,null>=0 为真,null==0却为假,null的值详解
Feb 22 Javascript
Angular 4.x 动态创建表单实例
Apr 25 Javascript
快速使用node.js进行web开发详解
Apr 26 Javascript
浅谈vue首屏加载优化
Jun 28 Javascript
el-select数据过多懒加载的解决(loadmore)
May 29 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
drupal 代码实现URL重写
2011/05/04 PHP
微博短链接算法php版本实现代码
2012/09/15 PHP
php setcookie(name, value, expires, path, domain, secure) 参数详解
2013/06/28 PHP
PHP开发之归档格式phar文件概念与用法详解【创建,使用,解包还原提取】
2017/11/17 PHP
javascript 仿QQ滑动菜单效果代码
2010/09/03 Javascript
统计jQuery中各字符串出现次数的工具
2012/05/03 Javascript
js计算精度问题小结
2013/04/22 Javascript
JavaScript控制listbox列表框的项目上下移动的方法
2015/03/18 Javascript
浅谈JSON.parse()和JSON.stringify()
2015/07/14 Javascript
jquery+html5时钟特效代码分享(可设置闹钟并且语音提醒)
2020/03/30 Javascript
jquery淡入淡出效果简单实例
2016/01/14 Javascript
JS实现拖拽的方法分析
2016/12/20 Javascript
使用D3.js制作图表详解
2017/08/13 Javascript
JS模拟超市简易收银台小程序代码解析
2017/08/18 Javascript
详解Node.js 中使用 ECDSA 签名遇到的坑
2018/11/26 Javascript
layer的prompt弹出框,点击回车,触发确定事件的方法
2019/09/06 Javascript
jquery实现掷骰子小游戏
2019/10/24 jQuery
详解vue-template-admin三级路由无法缓存的解决方案
2020/03/10 Javascript
[46:16]2018DOTA2亚洲邀请赛3月30日 小组赛B组 iG VS VP
2018/03/31 DOTA
[01:32]寻找你心中的那团火 DOTA2 TI9火焰传递活动今日开启
2019/05/16 DOTA
使用Python的Scrapy框架十分钟爬取美女图
2016/12/26 Python
python实现人脸识别经典算法(一) 特征脸法
2018/03/13 Python
python3获取两个日期之间所有日期,以及比较大小的实例
2018/04/08 Python
django与小程序实现登录验证功能的示例代码
2019/02/19 Python
Django REST framework 分页的实现代码
2019/06/19 Python
Python 字符串、列表、元组的截取与切片操作示例
2019/09/17 Python
解决pyqt5异常退出无提示信息的问题
2020/04/08 Python
一款简洁的纯css3代码实现的动画导航
2014/10/31 HTML / CSS
纯CSS3大转盘抽奖示例代码(响应式、可配置)
2017/01/13 HTML / CSS
学习新党章思想汇报
2014/01/09 职场文书
共产党员承诺书
2014/03/25 职场文书
离婚协议书范本样本
2014/08/19 职场文书
社区关爱留守儿童活动方案
2014/08/22 职场文书
2015年乡镇流动人口工作总结
2015/05/12 职场文书
2019消防宣传标语!
2019/07/10 职场文书
MongoDB误操作后使用oplog恢复数据
2022/04/11 MongoDB