响应式
Vue 最让人熟知的就是双向绑定,这基于它优秀的响应式设计。
#
getter/setter实现一个函数convert
- 传入一个对象作为参数
Object.defineProperty
实现对象 properties 的 getter 和 setter
核心代码
function convert(obj) { Object.keys(obj).forEach((key) => { let value = obj[key]; Object.defineProperty(obj, key, { get: function () { console.log(`getting key "${key}": ${value}`); return value; }, set: function (newValue) { console.log(`setting key "${key}": ${newValue}`); value = newValue; }, }); });}
#
dependency tracking依赖追踪——订阅者/发布者模式
- 创建一个包含
depend
,notify
方法的类 - 创建一个自动更新的高阶函数
autorun
,update
function 作为 input
核心代码
class Dep { constructor() { this.subs = new Set(); }
depend() { if (activeUpdate) { this.subs.add(activeUpdate); } }
notify() { this.subs.forEach((sub) => sub()); }}
let activeUpdate;
// WTFfunction autorun(update) { function wrapperUpdate() { activeUpdate = wrapperUpdate; update(); activeUpdate = null; } wrapperUpdate();}
#
mini observer合并convert()
,autorun()
,在此之前,rename convert()
to observe()
observe()
将对象的 properties 变成响应式,对每个 property 都分配一个Dep
实例。autorun()
接受一个更新函数,并在更新函数订阅的 property 发生变化时重新运行它。
核心代码
function observe(obj) { Object.keys(obj).forEach((key) => { let value = obj[key]; let dep = new Dep(); Object.defineProperty(obj, key, { get: function () { dep.depend(); return value; }, set: function (newValue) { const isChanged = value !== newValue; if (isChanged) { value = newValue; dep.notify(); } }, }); });}
class Dep { constructor() { this.subs = new Set(); }
depend() { if (activeUpdate) { this.subs.add(activeUpdate); } }
notify() { this.subs.forEach((sub) => sub()); }}
let activeUpdate;
function autorun(update) { function wrapperUpdate() { activeUpdate = wrapperUpdate; update(); activeUpdate = null; } wrapperUpdate();}