JavaScript 中配置属性

Posted by cl9000 on May 14, 2020

达到完美境界并不是无以复加,而是无可去除。——<安托万·德·圣·埃克苏佩里>

可以在 Javascript 中配置对象属性,例如将属性设置为伪私有或只读。这个特性从ECMAScript 5.1开始就可用了,因此所有最新的浏览器都支持它。

要做到这一点,你需要像这样使用Object原型的defineProperty方法:

1
2
3
4
5
6
7
8
var a = {};
Object.defineProperty(a, 'readonly', {
value: 15,
writable: false
});

a.readonly = 20;
console.log(a.readonly); // 15

语法如下:

1
Object.defineProperty(dest, propName, options)

或者对于多个定义:

1
2
3
4
Object.defineProperties(dest, {
propA: optionsA,
propB: optionsB, //...
})

其中选项包括以下属性:

  • Value: 如果属性不是 getter (见下文),Value是一个强制属性。{a: 12} === Object.defineProperty(obj, 'a', {value: 12})
  • 可写: 设置为只读。注意,如果属性是嵌套对象,那么它的属性仍然是可编辑的。
  • 枚举: 将属性设置为hidden。这意味着 for ... of 循环和 stringify 不会在结果中包含属性,但是属性仍然在那里。注意:这并不意味着财产是私有的!它仍然可以从外部访问,这只是意味着它不会被打印。
  • 可配置的: 将属性设置为不可修改的,例如,不允许删除或重定义。同样,如果属性是嵌套对象,则其属性仍然是可配置的。

因此,为了创建私有常量属性,您可以像这样定义它:

1
Object.defineProperty(obj, 'myPrivateProp', {value: val, enumerable: false, writable: false, configurable: false});

除了配置属性外,由于第二个参数是字符串,defineProperty 还允许我们定义动态属性。例如,假设我要根据一些外部配置创建属性:

1
2
3
4
5
6
7
8
9
10
var obj = {
getTypeFromExternal(): true // illegal in ES5.1
}

Object.defineProperty(obj, getTypeFromExternal(), {value: true}); // ok

// For the example sake, ES6 introduced a new syntax:
var obj = {
[getTypeFromExternal()]: true
}

但这还不是全部!像其他OOP语言一样,高级属性使我们能够创建getter和setter!在这种情况下,不能使用 writable,enumerable和configurable性能,而是:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Foobar () {
var _foo; // true private property

Object.defineProperty(obj, 'foo', {
get: function () { return _foo; }
set: function (value) { _foo = value }
});

}

var foobar = new Foobar();
foobar.foo; // 15
foobar.foo = 20; // _foo = 20

除了封装和高级访问器的明显优势外,您还会注意到我们没有“调用”该吸气剂,而是仅“获取”了该属性而没有括号!这太棒了!例如,假设我们有一个带有长嵌套属性的对象,如下所示:

1
var obj = {a: {b: {c: [{d: 10}, {d: 20}] } } };

现在,我们无需创建a.b.c[0].d(其中一个属性可以解决undefined并引发错误),而可以创建一个别名:

1
2
3
4
5
Object.defineProperty(obj, 'firstD', {
get: function () { return a && a.b && a.b.c && a.b.c[0] && a.b.c[0].d }
})

console.log(obj.firstD) // 10

总结

如果您定义了一个没有 setter的getter并且仍然尝试设置一个值,那么您将得到一个错误!当使用诸如 $.extend或的辅助功能时,这一点尤其重要 _.merge。小心!

参考

关注【公众号】,了解更多。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!