songbensong songbensong
首页
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
HTML/CSS
JavaScript
计算机网络
操作系统
更多
  • 分类
  • 标签
GitHub (opens new window)

松本松

一直在路上
首页
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
HTML/CSS
JavaScript
计算机网络
操作系统
更多
  • 分类
  • 标签
GitHub (opens new window)
  • 排序算法

    • 1
    • 归并排序
    • 快速排列
    • 冒泡排序
  • 大数相加
  • vue响应式
  • JS算法题
simonzhangs
2022-09-01

vue响应式

// vue响应式原理
const Observer = function(data) {
    // 循环修改每个属性,添加get set
    for(let key in data) {
        defineReactive(data,key);
    }
}

const defineReactive = function(obj,key) {
    // 局部变量dep,用于get set内部调用
    const dep = new Dep();
    // 获取当前值
    let val = obj[key];
    Object.defineProperty(obj,key, {
        // 当前属性可被循环
        enumerable: true,
        // 当前属性可被修改
        configurable: true,
        get() {
            // 调用依赖收集器中的addSub,用于收集当前属性与watcher中的依赖关系
            dep.depend();
            return val;
        },
        set(newVal) {
            if(newVal === val) {
                val = newVal;
                // 当值发生变更时,通知依赖收集器,更新每个需要更新的watcher
                dep.notify();
            }
        }
    })
}

const observe = function(data) {
    return new Observer(data);
}

const Dep = function() {
    const self = this;
    // 收集目标
    this.target = null;
    // 存储收集器中需要通知的Watcher
    this.subs = [];
    // 当有目标时,绑定Dep和watcher的关系
    this.depend = function() {
        if(Dep.target) {
            Dep.target.addDep(self);
        }
    }
    // 为当前收集器添加Watcher
    this.addSub = function(watcher) {
        self.subs.push(watcher);
    }
    this.notify = function() {
        for(let i=0;i<self.subs.length;i +=1) {
            self.subs[i].update();
        }
    }
}

const Watcher= function(vm, fn) {
    const self = this;
    this.vm = vm;
    // 将当前Dep.target 指向自己
    Dep.target = this;
    this.addDep = function(dep) {
        dep.addSub(self);
    }
    this.update= function() {
        console.log('in watcher update');
        fn();
    }
    this.value = fn();
    Dep.target = null;
}

const Vue = function(options) {
    const self = this;
    // 将data赋值给this._data,源码此处通过proxy代码劫持数据
    if(options && typeof options.data === 'function') {
        this._data = options.data.apply(this);
    }
    // 挂载函数
    this.mount = function() {
        new Watcher(self,self.render)
    }
    // 渲染函数
    this.render = function() {
        with(self) {
            this._data.text;
        }
    }
    // 监听this._data
    observe(this._data)
}

const vue = new Vue({
    data() {
        return {
            text: 'Hello world!'
        }
    }
})

vue.mount();
vue._data.text = '123';
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
编辑 (opens new window)
上次更新: 2022/09/18, 15:06:58
大数相加

← 大数相加

最近更新
01
DOM事件流 && DOM0 - DOM3 事件模型 && DOM事件流应用场景(冒泡、事件委托)
09-18
02
必备书单
09-11
03
url全过程
09-10
更多文章>
Theme by Vdoing | Copyright © 2022-2025 simonzhangs | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式