总
以下代码均可以在nodejs和chrome的console里运行
以下均未考虑兼容,空判断,父类属性,解除绑定, 多层关系, 循环调用,多次调用等
Step 1 接管赋值和取值
1 2 3 4 5 6 7 8 9 10 11 12 13
| const demo = {}; demo._dAtA = {}; Object.defineProperty(demo, 'x', { get: function(){ return demo._dAtA['x'] * 2; }, set(val){ console.log(val); demo._dAtA['x'] = val; } }) demo.x = 123 console.log(demo.x)
|
专门做了个赋值取值不一致的乘2
Step 2 函数订阅与触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Demo { subs = [] sub(fn) { this.subs.push(fn) } unsub(fn) { for(let i = this.subs.length - 1;i >= 0 ;i--){ if(this.subs[i] === fn){ this.subs.splice(i,1); return } } } notify() { console.log('nofity start'); for(let i = 0; i < this.subs.length; i ++){ (this.subs[i])(); } console.log('nofity end'); } }
const d = new Demo();
const hello0 = ()=>{console.log('hello 0')} d.sub(hello0) d.notify() d.unsub(hello0) d.notify()
d.sub(()=>{console.log('hello 1')}) d.unsub(()=>{console.log('hello 1')}) d.notify()
|
专门写了两种,对于函数指针不了解的,也可以通过这个理解一下
Step 3 data + computed
有了上面的基本工具,结合一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| 'use strict'; class Sub{ subs = [] sub(fn) { this.subs.push(fn) } notify(){ this.subs.forEach(fn=>{fn()}); } }
let curV = null; function defineReactive(obj, key, value, db){ let subs = new Sub(); obj[db][key] = value; Object.defineProperty(obj, key, { get(){ if(curV){ if(!(curV.vm === obj && curV.key === key)){ const rv = curV; subs.sub(()=>{ rv.vm[rv.key] = rv.fn(); console.log(`\t[info][${rv.key}] set to [${rv.vm[rv.key]}]`); }); } } return obj[db][key]; }, set(v){ obj[db][key] = v subs.notify(); } }) }
function defineComputed(obj, key, fn) { curV = {vm: obj, key, fn: fn.bind(obj)}; let d = (fn.bind(obj))(); defineReactive(obj, key, d, '_computed'); curV = null; }
class VDemo{ constructor(config){ const d = config.dAtA(); this._data = {}; for(let key in d) { defineReactive(this, key, d[key], '_data'); } this._computed = {} for(let key in config.computed){ defineComputed(this, key, config.computed[key]) } } }
const vDemo = new VDemo({ dAtA(){ return { vAl0: 'hey', vAl1: 'world' } }, computed: { x() { return this.vAl0 + ' ' + this.vAl1; }, y() { return 'y: ' + this.x; } } })
console.log(vDemo.vAl0) console.log(vDemo.vAl1) console.log(vDemo.x) vDemo.vAl0 = 'hello' console.log(vDemo.x) vDemo.vAl1 = ' ?' console.log(vDemo.x) console.log(vDemo.x) console.log(vDemo)
|
这样,改变值,依赖的值就会自动跟着变化,而在依赖的值不变时,不会多次调用函数。
相关文档
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty