存取器(accessor)
除了直接定義以外,屬性還可以用存取器(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屬性。
存取器往往用于,屬性的值需要依賴對象內部數據的場合。
var o ={
$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的操作。
存取器也可以通過Object.defineProperty定義。
var d = new Date();
Object.defineProperty(d, 'month', {
get: function () {
return d.getMonth();
},
set: function (v) {
d.setMonth(v);
}
});
上面代碼為Date的實例對象d,定義了一個可讀寫的month屬性。
存取器也可以使用Object.create方法定義。
var o = Object.create(Object.prototype, {
foo: {
get: function () {
return 'getter';
},
set: function (value) {
console.log('setter: '+value);
}
}
});
如果使用上面這種寫法,屬性foo必須定義一個屬性描述對象。該對象的get和set屬性,分別是foo的取值函數和存值函數。
利用存取器,可以實現數據對象與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屬性,實現了綁定。兩者之中只要有一個對象發(fā)生變化,就能在另一個對象上實時反映出來。