不畏惧失败是创造力的一个基本要素。——<艾尔文·兰德博士>
在 Javascript
里配置对象属性是可以实现的,比如将一个参数设为伪私有或者只读。这个特性从 ECMAScript 5.1
开始就可以使用了,因此近来的浏览器都是支持的。 要实现这些功能,你需要使用 Object
的原型方法 defineProperty
,像这样:
1 | var a = {}; |
语法如下:
1 | Object.defineProperty(dest, propName, options); |
options
包含如下的属性:
value
: 如果参数不是getter
(请看下文),value
是必须的。{a: 12} === Object.defineProperty(obj, 'a', {value: 12})
writable
: 将参数设为只读。需要注意的是如果参数是嵌套对象,它的元素仍是能可修改的。enumerable
: 将参数设为隐藏。这意味着for ... of
循环和stringify
的结果里不会包含这些参数,但是这个参数还是存在的。提示:这并不意味着参数是私有的!他依旧可以从外界访问,只是意味着不会被打印。configurable
: 将属性设置为不能更改,比如:防止参数被删除或重新定义。如果此对象是一个嵌套对象,他的参数依旧是可配置的。
所以如果想创建私有静态变量,你可以这样定义:
1 | Object.defineProperty(obj, 'myPrivateProp', {value: val, enumerable: false, writable: false, configurable: false}); |
除了配置属性,由于 defineProperty
第二个参数是字符串,所以允许我们定义动态变量 (defineProperty)
。例如,我们可以说我们要根据一些外部配置创建一个属性:
1 | var obj = { |
还没有结束!高级特性允许我们创建 getter 和 setter ,就像其他面向对象(OOP)语言!这种情况下,我们不能使用 writable
、enumerable
和 configurable
参数,而是:
1 | function Foobar () { |
除了封装与先进的访问器这些明显的优点,你还发现我们并没有“调用” getter
,而是不需要使用小括号直接“取得”了属性!这太棒了!例如,我们可以想象我们有一个多层嵌套对象,像这样:
1 | var obj = {a: {b: {c: [{d: 10}, {d: 20}] } } }; |
现在我们不需要调用 a.b.c[0].d
(其中某个属性可能是 undefined
且抛出错误),我们可以创建一个别名:
1 | Object.defineProperty(obj, 'firstD', { |
提示
如果你定义了 getter
而没有定义 setter
却仍要给它赋值,你将会得到一个错误。这在使用像 $.extend
或 _.merge
这样的辅助方法时是尤为重要的。要小心!
链接
- MDN - defineProperty
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty - MDN - Defining properties in JavaScript
https://bdadam.com/blog/defining-properties-in-javascript.html
参考
关注【公众号】,了解更多。
赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!