学习VUE“双向绑定”的实现,DOM变化时,同步给js变量,这一层比较容易理解,使用DOM的事件绑定就好了;但是当js变量发送变化时,是如何监控到、然后更新到DOM的,这点就比较有意思的。
看VUE代码,里面使用了ES5新加入的“Object.defineProperty()”,属性拦截器
看名字就比较好理解,使用defineProperty定义的属性,可以针对getter,和setter操作做监控、拦截,比如下面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | let o = {}; Object.defineProperty(o, 'b', { configurable: true, enumerable: true, get: function(){ console.log('get run'); //log1 }, set: function(v){ console.log('set run', v); //log2 } }); setInterval(function(){ o.b = new Date().toLocaleString(); console.log('o.b, ', o.b); //log3 undefined }, 3000); |
这样,每隔3秒,log2,o.b赋值时,log2,就会被打印出来
但是,下面的反应比较奇怪,getter也被拦截了,log3位置,打印出来的是“undefined”。。。
这是因为getter里没有返回值
但是如果你胆敢在getter“return this.b”,运行时就会死循环,因为如果this.b又会去调getger
(是的,这就是js。。。增加一个看似“美丽强大”的新特性的同时,还给你附加几个坑,等你往里跳。。。。。)
那么,还能不能让人好好使用这个拦截器哪?
当然可以,这里,我们可以加一个“中间变量”过渡,setter时,给中间变量赋值;getter时,return这个中间变量,就不会死循环了
当然,还可以借助经典的“function-Class”定义,对整个过程做封装,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function O1(){ let v1; //中间变量 Object.defineProperty(this, 'v1', { get: function(){ console.log('get run', v1); return v1; }, set: function(v){ v1 = v; console.log('set run', v); } }); } var o1 = new O1(); setInterval(function(){ o1.v1 = new Date().toLocaleString(); console.log('o1.v1, ', o1.v1); }, 3000); |
———
转载请注明出处: http://www.jiangkl.com/2019/06/js_defineproperty