VUE响应式原理-如何追踪变化

Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。这使得状态管理非常简单直接

如何追踪变化

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setterObject.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <script type="text/javascript">
            let oldArrPrototype = Array.prototype;
            // 继承
            let proto = Object.create(oldArrPrototype);
            ['push', 'shift', 'unshift','splice'].forEach(method => {
                proto[method] = function() {
                    // 切片编程
                    // 更新视图
                    updateView();
                    oldArrPrototype[method].call(this, ...arguments)
                }
            })


            // 观察函数
            function observer(target) {
                if (typeof target !== 'object' || target === null) {
                    return target;
                }
                if (Array.isArray(target)) {
                    target.__proto__ = proto;
                    // target.constructor.prototype = proto;
                }
                for (let key in target) {
                    /*
                        target:对象本身
                        key:对象的属性
                        target[key]:对象的值                    
                    */
                    definedReactive(target, key, target[key])
                }
            }

            // defineProperty函数
            function definedReactive(target, key, value) {
                // 重新观察一下传过来的值
                observer(value); //递归
                Object.defineProperty(target, key, {
                    // get 读取属性值触发
                    get() {
                        return value;
                    },
                    // 修改属性值触发,默认有参数,是最新值
                    set(newValue) {
                        // 为了方式更改后的值也是对象
                        observer(newValue);
                        // 判断新值和旧值是否相同
                        // 如果不同,改变旧值,更新视图
                        if (newValue !== value) {
                            value = newValue;
                            updateView(value);
                        } else {
                            return newValue;
                        }
                    }
                })
            }

            // 更新视图方法
            function updateView(value) {
                console.log("更新视图" + value)
            }
            // 使用Object.defineProperty可以给属性重新定义属性,给属性增加getter,setter
            // 这样给属性增加或者读取属性是都会触发getter 或者 setter
            let data = {
                name: "oldValue",
                onj: {
                    name: "szx"
                },
                a: null,
                n:[1,2,3]
            }
            // 定义一个观察函数,只要数据发生变动会触发更新视图的方法
            observer(data)

            // data.name = "newValue"

            // data.a = {
            //         name: "100"
            //     },
            //     data.a.name = 200
            data.n.splice(0)
            console.log(data)

            // 如果属性不存在,即没有事先在data里面定义,赋值不存在的属性值的时候不会触发更新
        </script>
    </body>
</html>

 

posted @ 2020-06-17 13:37  Y-X南川  阅读(426)  评论(0编辑  收藏  举报