Monthly Archives: 六月 2019

Hello World 他山石

defineProperty

学习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