1. 导读

  • 大家都知道前端的三大框架是具有响应式的。但是其实他们内部实现的原理却是不一样的
  • 这里就将手写各大前端框架的响应性 demo
    1
    2
    3
    4
    5
    6
    7
    react => 一个函数重写 onChange 和 value
    // <input
    // value="state.xxx"
    // onchange="()=>{ setState(xxx)}"
    // />
    vue => object.definedProperty => proxy
    anguluar => 脏数据 检测所有的数据 拦截

vue

object.definedProperty

用法
  • object.definedPropertyjs ES6API
  • 提供了对于对象的拦截处理的能力
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Object.defineProperty(obj, 'foo',{
    value:
    // 不允许重复定义
    configurable:false,
    // 不允许迭代
    enumerable: fasle,
    // 不允许重复赋值
    writable: false,
    get:
    set:
    })
    #
    Object.defineProperties(obj,{
    foo:{
    value:
    ...
    }
    })
    demo
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function convert(obj) {
    Object.keys(obj).forEach(key => {
    let internalValue = obj[key]
    Object.defineProperty(obj, key, {
    get() {
    console.log(`get${key}:${internalValue}`);
    return internalValue;
    },
    set(newValue) {
    console.log(`get${key}:${internalValue}`);
    internalValue = newValue
    }
    })
    })
    }
    const obj = { foo: 123, sads: 2 }
    convert(obj)
    console.log(obj)

订阅者模式

依赖跟踪
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
// depend notify:当依赖更改的时候重新执行
// 当调用 dep.notify() 就重新执行
// () => { dep.depend() console.log('updated') }
<script>
window.Dep = class Dep {
constructor() {
this.subscribers = new Set()
}
depend() {
if (activeUpdate) {
this.subscribers.add(activeUpdate)
}
}
notify() {
this.subscribers.forEach(sub => sub())
}
}
let activeUpdate
function autorun(update) {
function wrappedUpdate() {
// 当依赖关系变化的时候 重新执行autoru内部的东西
activeUpdate = wrappedUpdate
update()
activeUpdate = null
}
}
const dep = new Dep()
autorun(() => {
dep.depend()
console.log('updated')
})
// should log: "updated"

dep.notify()
// should log: "updated"
</script>
observe
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
<script>
function isObject (obj) {
return typeof obj === 'object'
&& !Array.isArray(obj)
&& obj !== null
&& obj !== undefined
}
function observe (obj) {
if (!isObject(obj)) {
throw new TypeError()
}
Object.keys(obj).forEach(key => {
let internalValue = obj[key]
let dep = new Dep()
Object.defineProperty(obj, key, {
get () {
dep.depend()
return internalValue
},
set (newValue) {
const isChanged = internalValue !== newValue
if (isChanged) {
internalValue = newValue
dep.notify()
}
}
})
})
}
window.Dep = class Dep {
constructor () {
this.subscribers = new Set()
}
depend () {
if (activeUpdate) {
// register the current active update as a subscriber
this.subscribers.add(activeUpdate)
}
}
notify () {
// run all subscriber functions
this.subscribers.forEach(subscriber => subscriber())
}
}
let activeUpdate
function autorun (update) {
function wrappedUpdate () {
activeUpdate = wrappedUpdate
update()
activeUpdate = null
}
wrappedUpdate()
}
</script>
使用
1
2
3
4
5
6
7
8
9
10
const state = {
count: 0
}
observe(state)
autorun(() => {
console.log(state.count)
})
// should immediately log "count is: 0"
state.count++
// should log "count is: 1"

proxy

  • 未完待续

React

  • 未完待续

Angular

  • 未完待续