在我们实际项目中,有可能会遇到监听一个对象的属性变化(当然,全局变量可以看做window对象的属性)而执行某些操作。get/set分别对属性的获取/赋值进行监听斌并执行某些操作。
对于cookie应该都不陌生,它执行document.cookie='a=1'
的时候并不会覆盖原来的cookie,而是覆盖原来的a的值或则追加一个a。当然,这里cookie是不是通过getter/setter来实现的不做深究,我们就拿实现一个类似的对象来作为例子。
初始化声明
var test = {
_cookie: '',
get cookie() {
console.log('get cookie');
return this._cookie;
},
set cookie(val) {
console.log('set cookie: ' + val);
// TODO 对_cookie和val进行判断是否有某个值再进行追加或则覆盖操作。
// 字符串的操作这里就不多写了
this._cookie = val;
return val;
}
}
test.cookie; // get cookie '' 这里执行了get的函数
test.cookie = 1; // set cookie 1 1 这里执行了set的函数
注意,这里值是存在_cookie里面而不是cookie里面的。因为如果还是存在cookie属性里面当set的时候我们会去执行this.cookie = val
,这样又会去执行set,就会无限循环了。
defineGetter/defineSetter
对于某些已经存在的对象我们无法直接在声明的时候声明getter/setter,可以使用这两个函数进行操作。例如作为window属性的全局变量。
var _test = '';
window.__defineGetter__('test', function(){
console.log('get test');
return this._test;
});
window.__defineSetter__('test', function(val) {
console.log('set test');
// TODO 某些操作
this._test = val;
return this._test;
});
test; // get test ''
test = 2; // set test 2
注意,这个方法不再推荐使用,这里拿出来只是见见而已,而且某些浏览器貌似不再至此这玩意了。ES5添加了新的方法。
defineProperty/defineProperties
defineProperty/defineProperties
不只是对于get/set的声明,同时还能添加/修改对象属性特性描述(可枚举、可修改、可设置),有兴趣的可以去看看对象属性描述,本文不做详解。
var _test = '';
Object.defineProperty(window, 'test', {
get(){
console.log('get test');
return this._test;
},
set(val){
console.log('set test');
// TODO 某些操作
this._test = val;
return this._test;
}
});
test; // get test ''
test = 2; // set test 2
Object.defineProperties
只是对defineProperty
的扩展,一次性添加/修改多个对象属性特性描述。
var _a = '', _b = '';
Object.defineProperties(window, {
a: {
get(){
console.log('get a');
return this._a;
},
set(val){
console.log('set a');
// TODO 某些操作
this._a = val;
return this._a;
}
},
b: {
get(){
console.log('get b');
return this._b;
},
set(val){
console.log('set b');
// TODO 某些操作
this._b = val;
return this._b;
}
}
});
a; // get a ''
b; // get b ''
a = 1; // set a 1
b = 1; // set b 1
注意,defineProperty/defineProperties都是Objet的方法,操作对象作为第一个参数传入。
扩展
如果只是对对象属性的监听,ES6提供了更加高级的类—Proxy
(代理)。直接监听所有对象的所有属性,而且不用申明_xxx。
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log('get ' + key);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log('set ' + key + ':' + value);
return Reflect.set(target, key, value, receiver);
}
});
obj.a = 1; // set a:1
obj.b = 2; // set b:2
当然,这么牛逼的玩意肯定不会只有这点作用,具体可以自己去研究。