zoukankan      html  css  js  c++  java
  • Vue的数据响应式原理

    数据响应式原理在面试的时候会经常遇到,今天搞懂了,分享一下。
     
    //使用了观察者模式
    //总体思路:
    //   1、observe(){} 监听数据的函数
    //   2、对象拦截函数
    //   3、数组劫持函数
    let data = {
        username:'Ycenkun',
        age:'18',
        company:{
            name:'杭州'
        },
        arr:[1,2,3,4,5,6]
    }
    //数组劫持函数
    const proto = Object.create(Array.prototype)//创建一个新对象,使用现有对象为新创建的对象提供__proto__
    //新对象proto具有数组原型上所有的方法
    const arrMethods = ['push','pop','shift','unshift','join','indexof','slice','splice','reverse','sort']
    arrMethods.map((item)=>{
        proto[item] = function(){ //假如执行了push方法,那么就相当于执行了这个函数,而且这个proto已经成为data实例的原型方法
            Array.prototype.push.call(data.arr,...arguments) //既然重写这个方法,那么就要真正再实现这个方法,即再利用原型上的方法,不过需要改变this指向
            render(item,...arguments)
        }
    })



    //需要监听数据的函数 【数据改变会走set(){},但是由于set不能识别对象 所以set函数中也会用到这里】
    function observe(data){
        // console.log(data)
    //判断对象的类型
        if(Array.isArray(data)){ //如果是数组,要用数组劫持来处理
            // console.log(data)
            data.__proto__ = proto  //data是一个实例化的数组(我们不让他走自己的原型对象上的方法,
                                    //而是我做一个必要的多此一举,自己控制原型对象的方法,所以触发原型对象的方法的时候,
                                    //我们可以做一些自己想做的事情) data.__proto__就指向数组原型对象,而proto恰好是数组原型对象内的
                                    //所有方法,那么即把数组的方法又全部继承给了data这个数组
        }                           //data的方法是继承于proto 然而proto的方法被重写了
        if(Object.prototype.toString.call(data) == '[object Null]'){ //空的不做任何处理
            return 
        }
        if(Object.prototype.toString.call(data) == '[object Object]'){  //如果是对象 交给对象拦截处理
            // console.log(data)
            for(let key in data){
                reactive(data,key,data[key])   //调用对象拦截函数处理
            }
        } 
    }
    //对象拦截函数
    function reactive(obj,attr,value){
        observe(value) //当初始值是对象的时候,需要重新再走一次监听函数  递归直到剥离出value不是对象而是个值
        Object.defineProperty(obj,attr,{
            get(){ //获得初始值
                return value;
            },
            set(val){  //获得最新值,数据只要改变就要走到这里重新操作,所以数据一旦改变就会触发
                // console.log(`${attr}发生了改变,变成${val}`); //监听到数据改变
                // observe(val)   //当改变的值是个对象的时候,需要再走一次监听函数,剥离出来最终改变的值
                render(attr,val)
            }
        })
    }
    function render(who,res){
        console.log(`${who}发生了改变,改变的值是${res}`)
    }
    observe(data)


    //node.js环境下测试:

    // data.username = 'Cooper';
    // data.age = 25;
    // data.company={
    //     name:'山东'
    // }
    //data.company.name='山东'
    // data.arr.push(456)
  • 相关阅读:
    webpack 配置缓存
    Python-----多线程threading用法
    LINUX 编程定位工具gstack,pstack
    数据库session立即生效(64---8192) SCOPE参数
    shell中wait命令详解
    Go语言学习笔记
    使用go语言数据库
    Oracle数据库管理----性能优化
    数据库索引实例
    Linux串口设置及编程(转)
  • 原文地址:https://www.cnblogs.com/yangqinqiang/p/13618505.html
Copyright © 2011-2022 走看看