Vueソース-2.データハイジャック

4892 ワード

  • src/indexを新規作成します.js
  • import { initMixin } from "./init"
    function Vue(options) {
        //    Vue       
        this._init(options)
    }
    //            Vue        
    initMixin(Vue)
    export default Vue
    
  • 新規src/init.js
  • import { initState } from './state';
    //          init    
    export function initMixin(Vue) {
        //      
        Vue.prototype._init = function(options) {
            //      
            const vm = this; // vue      this.$options            
            vm.$options = options
            //      
            initState(vm)
        }
    }
    
  • src/stateを新規作成します.js
  • import { observe } from "./observer/index"
    export const initState = function(vm) {
        let opts = vm.$options
        console.log(opts);
        // vue          、    、    、      、 watch
        if(opts.props) {
            initProps(vm)
        }
        if(opts.methods) {
            initMethods(vm)
        }
        if(opts.data) {
            initData(vm)
        }
        if(opts.computed) {
            initComputed(vm)
        }
        if(opts.watch) {
            initWatch(vm)
        }
    }
    function initData(vm) {
        //         
        let data = vm.$options.data //       data
        /**
         * 1. data._data           data   
         * 2.    data                data()
         */
        data = vm._data = typeof data == 'function' ? data.call(vm) : data
        //             ,          -     
        // MVVM                 
        //      object.defineProperty()       get 、set   
        observe(data) //      
    }
    
  • src/observer/indexを新規作成します.js
  • /**
     * 1.   data     ,    Object.defineProperty      es5    
     * 2. Object.defineProperty      ie8     ,   vue2      ie8    
     */
    import { isObject, def } from '../utils/index';
    import { arrayMethods } from './array.js'
    class Observer {
        constructor(value) {
            // vue          ,              ,     set   get   
            //    vue3.0     proxy   ,proxy     ,          get   set   ,      2-3 
            def(value, '__ob__', this)
            if(Array.isArray(value)) {
                //                  ,         
                //             push shift unshift
                //               
                value.__proto__ = arrayMethods //          
                this.observerArray(value)
            } else {
                this.walk(value)
            }
        }
        observerArray(data) {
            data.forEach(item => {
                observe(item)
            })
        }
        walk(data) {
            let keys = Object.keys(data)
            keys.forEach(key => {
                defineReactive(data, key, data[key]) //        
            });
        }
    }
    
    function defineReactive(data, key, value) {
        observe(value) //         
        Object.defineProperty(data, key, {
            get() { //            
                return value
            },
            set(newValue) { //               
                if(newValue === value) return
                observe(newValue) //           ,                
                value = newValue
            }
        })
    }
    
    export function observe(data) {
        let isObj = isObject(data)
        if(!isObj) {
            return
        }
        //                
        return new Observer(data)
    }
    
  • src/utils/indexを新規作成します.js
  • //        
    export function isObject(data) {
        return typeof data === 'object' && data !== null
    }
    //           
    export function def(data, key, value) {
        Object.defineProperty(data, key, {
            enumerable: false,
            configurable: false,
            value
        })
    }