深入理解 Getter和Setter 对对象的属性监听
2019-01-26 21:31 龙恩0707 阅读(2122) 评论(3) 编辑 收藏 举报阅读目录
- 一:理解普通对象在声明时添加 get、set
- 二:Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__
- 三:Object.defineProperty
- 四:Object.defineProperties
- 五:Proxy
一:理解普通对象在声明时添加 get、set
在做vue的时候,我们经常会看到 data里面的属性 都有 get 和 set方法,如下所示:
如上vue中data里面它有两个属性,一个xxx 数组 和 一个 testA对象,但是都有get和set方法。也就是说在vue中data里面的每个属性都有两个相对应的get和set方法。为什么会有这样的呢?下面我们先来看一个普通的对象,如下代码所示:
const obj = { name: 'kongzhi', _age: 30, get age() { return this._age; }, set age(x) { this._age = x; } }; console.log(obj);
打印会如下所示:
当我们继续打印如下信息:
console.log(obj._age); // 输出:30 console.log(obj.age); // 输出:30 // 设置值 obj.age = 31; console.log(obj.age); // 输出:31 console.log(obj.age()); // Uncaught TypeError: obj.age is not a function
如上代码演示所示,我们在对象里面使用 get 或 set定义的 age, 它只是obj中的一个属性,它并不是方法,因此如上我们使用获取属性的值或设置属性的值操作是正常的,当我们使用 obj.age() 把它当做一个方法调用的时候,它会报错。因此在vue中所有的属性有get、set这样的,当我们自动给某个属性赋值的时候,它会自动调用 set对应的方法,当我们获取某个属性的时候,它会自动调用get方法。但是我们不能手动调用 set/get xxx() 中的xxx这样的方法。
二:Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__
上面只是在声明obj对象的时候,编写get和set 对应的属性。但是如果已经存在的对象的时候,再想继续添加 get/set呢?那只有使用
Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 了,如下代码演示:
const obj = { name: 'kongzhi', _age: 30 }; obj.__defineGetter__('age', function(){ console.log('监听到正在获取属性age的值'); return this._age; }); obj.__defineSetter__('age', function(value) { console.log('监听到正在设置属性age的值为:' + value); this._age = value; }); /* * 打印:监听到正在获取属性age的值 * 输出:30 */ console.log(obj.age); // 打印:监听到正在设置属性age的值为:31 obj.age = 31; /* * 打印:监听到正在获取属性age的值 * 输出: 31 */ console.log(obj.age);
但是呢?Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 这个方法已经不推荐使用了,并且随着以后浏览器的发展,可能会不再支持该方法,那怎么办呢?当然会有新的替代方案的,我们继续往下讲。
三:Object.defineProperty
该方法它是由两部分组成,分别是:数据描述符和访问器描述符,数据描述符的含义是:它是一个包含属性的值,并说明这个属性值是可读或不可读的对象。访问器描述符的含义是:包含该属性的一对 getter/setter方法的对象。
那么具体项了解该方法的使用及详解,请看我这篇文章(https://www.cnblogs.com/tugenhua0707/p/10261170.html),下面看使用 Object.defineProperty 来监听对象属性值的变化,如下代码:
const obj = { name: 'kongzhi', _age: 30 }; Object.defineProperty(obj, 'age', { get() { console.log('监听到正在获取属性age的值'); return this._age; }, set(value) { console.log('监听到正在设置属性age的值为:' + value); this._age = value; return this._age; } }); /* * 打印:监听到正在获取属性age的值 * 输出:30 */ console.log(obj.age); // 打印:监听到正在设置属性age的值为:31 obj.age = 31; /* * 打印:监听到正在获取属性age的值 * 输出: 31 */ console.log(obj.age);
四:Object.defineProperties
Object.defineProperties 是对 Object.defineProperty的扩展的,它可以一次性添加多个/修改多个对象属性描述符。
如下代码演示:
const obj = { _name: 'kongzhi', _age: 30 }; Object.defineProperties(obj, { age: { get() { console.log('监听到正在获取属性age的值'); return this._age; }, set(value) { console.log('监听到正在设置属性age的值为:' + value); this._age = value; return this._age; } }, name: { get() { console.log('监听到正在获取属性name的值'); return this._name; }, set(value) { console.log('监听到正在设置属性name的值为:' + value); this._name = value; return this._name; } } }); /* * 打印:监听到正在获取属性age的值 * 输出:30 */ console.log(obj.age); // 打印:监听到正在设置属性age的值为:31 obj.age = 31; /* * 打印:监听到正在获取属性age的值 * 输出: 31 */ console.log(obj.age); console.log('-------下面是对象name属性的监听-------'); /* * 打印:监听到正在获取属性name的值 * 输出:kongzhi */ console.log(obj.name); // 打印:监听到正在设置属性name的值为:longen obj.name = 'longen'; /* * 打印:监听到正在获取属性name的值 * 输出: longen */ console.log(obj.name);
五:Proxy
那么具体了解Proxy是啥,是干啥使用的,请看我这篇文章(https://www.cnblogs.com/tugenhua0707/p/10306793.html);
那么它也可以监听对象属性值的变化,如下代码演示:
const target = { name: 'kongzhi' }; const handler = { get: function(target, key) { console.log(`${key} 被读取`); return target[key]; }, set: function(target, key, value) { console.log(`${key} 被设置为 ${value}`); target[key] = value; } }; const testObj = new Proxy(target, handler); /* 获取testObj中name属性值 会自动执行 get函数后 打印信息:name 被读取 及输出名字 kongzhi */ console.log(testObj.name); /* 改变target中的name属性值 打印信息如下: name 被设置为 111 */ testObj.name = 111; console.log(target.name); // 输出 111