vue响应式原理

  • 什么是vue响应式
    Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新 。 --官方文档
    例如
 <div id="app">
        <div>{{price}}</div>
        <div>{{num}}</div>
        <div>{{total}}</div>
    </div>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                price: 1,
                num: 2
            },
            computed: {
                total() {
                    return this.price * this.num
                }
            }
        })

vue总共执行了三步

  • price变化更新页面
  • num变化更新页面
  • 调用tatal函数计算属性,更新页面

total值是计算的相对应结果,这个不难理解,但是当data中数据发生变化的时候,total也发生了变化,这个也能计算出来,但是存在一个疑问?

vue是怎么知道data中的数据发生改变的呢?
这是我们会思考,如果把tota的计算的结果保存起来,在下次需要的时候,再次调用即可l

		var price = 1
        var num = 3
        var total = 0
        var taget = function() { //taget存储了一个匿名函数
            return total = price * num
        }
        taget()
        //缓存起来,在需要的时候调用
        var storage = []
        record()
        function record() {
            storage.push(taget)
        }
        function replay() {
            storage.forEach(item => item())
        }
        price = 44
        replay()
        console.log(total);

不难看出当price发生变化的时候,调用replay方法执行taget方法,功能能实现,但是我们需要封装一个类,来进行对目标的管理,在需要重新执行的时候通知执行

 class Dep {
            constructor(){
                this.subArr=[]
            }
            depand(){
                if(taget&&!this.subArr.includes(taget)){
                    this.subArr.push(taget)
                }
            }
            notify(){
                this.subArr.forEach(item=>item())
            }
        }

定义了一个dep类,用来管理所有的依赖,现在用来记录函数的是depand函数,用来通知的函数是notify
然而我们在每次创建一个dep类时,不应该还是使用watcher函数来监听数据的变化,而不是用target函数

watcher(()=>{
	total=price*num
})

现在可以实现一下watcher函数

 function watcher(func){
            target=func
            dep.depend()
            target()
            target=null
  }

我们已经实现一个简单的dep类,我们说观测的是一个一个的数据,现在我们可以把这些数据以属性值的方式写入对象

let data={price:1,num:3 }

这时就可以观测对象的每一个属性,通过Object.defineProperty()的setter和getter的方法来进行监测

 let data = {
            price: 1,
            num: 3
        }
        Object.defineProperty(data, 'price', {
            get() {
                console.log('获取属性时触发');
            },
            set(newVal) {
                console.log(newVal);
            }
        })

get方法每当读取data中price的值时就会触发的函数
set方法每当设置data中price的值时就会触发
目前我们通过get记录了price依赖项,但属性值发生变化的时候就去执行set
对于dep类来说:
1 当price被读取时,就带调用dep.depand()来记录当前目标函数
2 当price被写时,就调用dep.notify()函数去只想所有的目标函数

var data={
	price:1,
	num:3
}
var target =null
 class Dep {
            constructor(){
                this.subArr=[]
            }
            depand(){
                if(taget&&!this.subArr.includes(taget)){
                    this.subArr.push(taget)
                }
            }
            notify(){
                this.subArr.forEach(item=>item())
            }
        }

整合之后的全部代码

var data = {
            price: 1,
            num: 3
        }
        var target = null
        class Dep {
            constructor() {
                this.subArr = []
            }
            depand() {
                if (target && !this.subArr.includes(target)) {
                    this.subArr.push(target)
                }
            }
            notify() {
                this.subArr.forEach(item => item())
            }
        }
        Object.keys(data).forEach(item => {
            let value = data[item]
            const dep = new Dep()
            Object.defineProperty(data, item, {
                get() {
                    dep.depand()
                    return value
                },
                set(newval) {
                    value = newval
                    dep.notify()
                }
            })

            function watcher(func) {
                target = func
                dep.depand()
                target()
                target = null
            }
            watcher(() => {
                total = data.price * data.num
                console.log(total);
            })
        })

当明白了这些官网的这张图就不难理解了,data中的数据price和num始终是被监听的,但数据变化时就会depand函数就会去收集所有的依赖数据,而notfiy就会执行目标函数,从而更新视图,watcher把需要监听的函数添加到target中
vue响应式原理_第1张图片

你可能感兴趣的:(vue响应式原理)