思考一个问题
我们现在很多人都在使用大火的mvvm框架,(vue,react)等。会对页面上的一些属性做双向绑定处理,我们修改数据的时候,页面的DOM也会随着自动更新。是不是很方便。
涉及到的知识点
仔细研究一下javascript
,其实原生的javascript
就已经提供了监听对象的属性变化的方法,那就是我们非常熟悉的getter & setter
,对的你没听错,不要以为这个特性只存在于后端语言,其实javascript
中也存在着这个特性,而且没有浏览器的兼容性问题,只不过我们很少用。
Object.defineProperty(obj,prop,descriptor) 目前兼容性做的不错,移动端上兼容绝大部分的浏览器,PC上也能够兼容到IE9及以上。注意,该方法在IE8上也是能够使用的,但是其只能够传入DOM对象,如果传入其他对象会报错。可能有人会对该方法的作用产生疑问,其实该方法极大的优化了对象的获取和修改属性方式。
本文并没有使用到configurable``writable``enumerable
等配置,有兴趣的话可以自行查阅资料。
那怎么实现呢
我们接下来就拿Object.defineProperty举个栗子 首先我们给obj对象添加一个可以监听的变化的属性:
let obj = {}
obj._show = false
Object.defineProperty(obj, 'show', {
get: function() {
alert(this._show)
return this._show
},
set: function(val) {
console.log(val)
this._show = val
}
})
如果我们执行obj.show = "true"
, 那么就会在控制台打印true。
如果我们执行let a = obj.show
,则会在页面弹出显示为false的警告框。
其实讲到这里,我们已经实现了我们自己想要的结果。
不过细心的童鞋可能会问:我们不是已经有一个show属性么,为什么要再额外定义一个变量_show呢,这不是多余的么 满足该同学的好奇心,我们把代码修改成下面这样。
let obj = {}
Object.defineProperty(obj, 'show', {
get: function() {
alert(this.show)
return this.show
},
set: function(val) {
console.log(val)
this.show = val
}
})
我们运行一下这个代码。
什么情况,栈溢出。为啥陷入了一个打印show属性值的死循环呢?我们明明只执行了一次的赋值操作。 因为在set
的内部,我们又执行了一次this.show = val
的操作,他又会触发set
,陷入了死循环当中无法自拔。
所以我们引入了一个额外的_show
参数。
其实我们在使用很多第三方类库的时候会看到很多_开头的属性,其实这些很大一部分就是来自于get/set
ES6中的Proxy?
ES6
中的Proxy
也可以实现同样的功能。本质原理其实都是一样的。
我们熟悉的vue框架是用Object.defineProperty
实现的数据双向绑定,vue
的开发者也明确表示,在下一个大版本,将用Proxy
,全面代替Object.defineProperty
。
具体Proxy相关的用法,网上有很多很多,可以随便看看。
自定义属性监听器
export class ProxyDispatcher {
static apply (object) {
object.addPropertyListener = ProxyDispatcher.prototype.addPropertyListener
}
addPropertyListener(propertyName, listener) {
const _this = this
_this[`_${propertyName}`] = _this[propertyName]
Object.defineProperty(_this, propertyName, {
get: function() {
return _this[`_${propertyName}`]
},
set: function(newValue) {
_this[`_${propertyName}`] = newValue
listener(newValue)
}
})
}
}
然后我们在想用的地方添加属性监听就好了
ProxyDispatcher.apply(this)
this.addPropertyListener('show', () => {
this.showChange();
})
我们就可以在自己的组件轻松的添加属性监听,并定义自己的个性回调了。
再也不需要暴露什么show()
hide()
blabla的方法了。是不是很简单方便。
小哥哥小姐姐转载希望附个出处哟^_^