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 相关文章推荐
jQuery toggle()设置CSS样式
Nov 05 Javascript
JavaScript简介
Feb 15 Javascript
javascript实现的固定位置悬浮窗口实例
Apr 30 Javascript
JS中生成随机数的用法及相关函数
Jan 09 Javascript
Linux下为Node.js程序配置MySQL或Oracle数据库的方法
Mar 19 Javascript
修复jQuery tablesorter无法正确排序的bug(加千分位数字后)
Mar 30 Javascript
Bootstrap自动适应PC、平板、手机的Bootstrap栅格系统
May 27 Javascript
javascript基础知识之html5轮播图实例讲解(44)
Feb 17 Javascript
微信小程序-getUserInfo回调的实例详解
Oct 27 Javascript
详解vue-cli 脚手架 安装
Apr 16 Javascript
vue中nextTick用法实例
Sep 11 Javascript
vue制作抓娃娃机的示例代码
Apr 17 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
163的邮件用phpmailer发送(实例详解)
2013/06/24 PHP
PHP获取POST数据的几种方法汇总
2015/03/03 PHP
Javascript条件判断使用小技巧总结
2008/09/08 Javascript
JavaScript中几种常见排序算法小结
2011/02/22 Javascript
JavaScript—window对象使用示例
2013/12/09 Javascript
js获取和设置属性的方法
2014/02/20 Javascript
jquery使用animate方法实现控制元素移动
2015/03/27 Javascript
判断访客终端类型集锦
2015/06/05 Javascript
jquery实现移动端点击图片查看大图特效
2020/09/11 Javascript
vue2.0父子组件间通信的实现方法
2017/04/19 Javascript
JavaScript之json_动力节点Java学院整理
2017/06/29 Javascript
第一个Vue插件从封装到发布
2017/11/22 Javascript
vue2.0 和 animate.css的结合使用
2017/12/12 Javascript
JSX在render函数中的应用详解
2019/09/04 Javascript
Vue-CLI与Vuex使用方法实例分析
2020/01/06 Javascript
[48:22]VGJ.S vs VG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
virtualenv实现多个版本Python共存
2017/08/21 Python
django用户注册、登录、注销和用户扩展的示例
2018/03/19 Python
Python3实现将本地JSON大数据文件写入MySQL数据库的方法
2018/06/13 Python
解决python写入mysql中datetime类型遇到的问题
2018/06/21 Python
使用python将时间转换为指定的格式方法
2018/11/12 Python
对pycharm 修改程序运行所需内存详解
2018/12/03 Python
Python中一般处理中文的几种方法
2019/03/06 Python
python利用re,bs4,requests模块获取股票数据
2019/07/29 Python
Python 多线程搜索txt文件的内容,并写入搜到的内容(Lock)方法
2019/08/23 Python
python实现把二维列表变为一维列表的方法分析
2019/10/08 Python
TensorFlow使用Graph的基本操作的实现
2020/04/22 Python
python如何输出反斜杠
2020/06/18 Python
Saks Fifth Avenue澳洲/亚太地区:萨克斯第五大道精品百货店
2019/06/09 全球购物
校运会广播稿100字
2014/01/27 职场文书
幼师个人总结范文
2015/02/28 职场文书
讲文明倡议书
2015/04/29 职场文书
乡镇法制宣传日活动总结
2015/05/05 职场文书
论语读书笔记
2015/06/26 职场文书
篮球赛闭幕式主持词
2015/07/03 职场文书
详解CSS中postion和opacity及cursor的特性
2022/08/14 HTML / CSS