除了直接定义以外,属性还可以用存取器(accessor)定义。其中,存值函数称为setter,使用set命令;取值函数称为getter,使用get命令。
存取器提供的是虚拟属性,即该属性的值不是实际存在的,而是每次读取时计算生成的。利用这个功能,可以实现许多高级特性,如每个属性禁止赋值。例如:
var o = { get p() { return 'getter'; }, set p(value) { console.log('setter: ' + value); } };
在上面代码中,o对象内部的get和set命令,分别定义了p属性的取值函数和存值函数。定义了这两个函数之后,对p属性取值时,取值函数会自动调用;对p属性赋值时,存值函数会自动调用。
o.p // "getter" o.p = 123 // "setter: 123"
注意,取值函数Getter不能接受参数,存值函数Setter只能接受一个参数(即属性的值)。另外,对象也不能有与取值函数同名的属性。例如,上面的对象o设置了取值函数p以后,就不能再另外定义一个p属性。
【示例1】存取器往往用于属性的值需要依赖对象内部数据的场合。
var o ={S $n : 5, get next() { return this.$n++ }, set next(n) { if (n >= this.$n) this.$n = n; else throw '新的值必须大于当前值'; } }; o.next // 5 o.next = 10; o.next // 10
在上面代码中,next属性的存值函数和取值函数,都依赖于对内部属性$n的操作。
【示例2】存取器也可以通过Object.defineProperty定义。
var d = new Date(); Object.defineProperty(d, 'month', { get: function () { return d.getMonth(); }, set: function (v) { d.setMonth(v); } });
上面代码为Date的实例对象d,定义了一个可读写的month属性。
【示例3】存取器也可以使用Object.create方法定义。
var o = Object.create(Object.prototype, { foo: { get: function () { return 'getter'; }, set: function (value) { console.log('setter: '+value); } } });
如果使用上面这种写法,属性foo必须定义一个属性描述对象。该对象的get和set属性,分别是foo的取值函数和存值函数。
【示例4】利用存取器,可以实现数据对象与DOM对象的双向绑定。
Object.defineProperty(user, 'name', { get: function () { return document.getElementById('foo').value; }, set: function (newValue) { document.getElementById('foo').value = newValue; }, configurable: true });
上面代码使用存取函数,将DOM对象foo与数据对象user的name属性,实现了绑定。两者之中只要有一个对象发生变化,就能在另一个对象上实时反映出来。