vue2源码解析(this.属性获取值)

83 阅读1分钟

vue2中为什么可以直接使用 this.属性,this.方法,本文提供源码教学地址,与自己实现的简化版代码

源码教学地址

juejin.cn/post/701092…

简化版

 // 检测属性是否为对象的自有属性
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    function hasOwn (obj, key) {
        return hasOwnProperty.call(obj, key)
    }

    // 空函数,占个位
    function noop(a,b,c){}

    // Object双向绑定的描述
    var sharedPropertyDefinition = {
        enumerable: true,
        configurable: true,
        get: noop,
        set: noop
    };

    // 自定义代理
    function proxy (target, sourceKey, key) {
        sharedPropertyDefinition.get = function proxyGetter () {
            return this[sourceKey][key]
        };
        sharedPropertyDefinition.set = function proxySetter (val) {
            this[sourceKey][key] = val;
            // 渲染视图
        };
        Object.defineProperty(target, key, sharedPropertyDefinition);
    }

    // 初始化data值
    function initData(vm){
        // vm._data,直接将data数据拉平在vm下?
        // 不行,这样就没法Object.defineProperty双向绑定值了,set中修改自己会报错
        // function set(v){
        //    this.name = v
        // } 
        // 为什么要双向绑定?
        // 修改修改数据后需要重新渲染视图
        let data = vm._data  = vm._option.data
        let keys = Object.keys(data)
        let len = keys.length
        while(len-- > 0){
            proxy(vm,'_data',keys[len])
        }
    }     

    // 初始化methods值
    function initMethod(vm){
        let methods = vm._option.methods
        let data = vm._option.data
        for(let k in methods){
            if(data && hasOwn(data,k)){
               throw Error('data与methods中存在重复属性')
               return 
            }
            // 不修改this执指向,this = Person,“this.name" 也就获取不到值了。
            vm[k] = typeof methods[k] !== 'function' ? noop : methods[k].bind(vm);
        }
        
    }
       
    
    function Person(option){
        let vm = this
        vm._option = option
        if(option.data){
            initData(vm)
        }
        if(option.methods){
            initMethod(vm)
        }

    } 

    const h  = new Person({
        data:{
            name: 'Tom',
            age: 25
        },
        methods:{
           say(){
                console.log(`My name is ${this.name}`)
           } 
        }
    })
    
    h.say()

总结

生成一个新的对象,用object.defineProperty 做代理,将data,methods中的值拉平到第一层。

  // h的结构
  //Person {
  //  _option: { data: { name: 'key', age: 25 }, methods: { say: [Function: say] } },
  //  _data: { name: 'key', age: 25 },
  //  age: [Getter/Setter],
  //  name: [Getter/Setter],
  //  say: [Function: bound say]
  //}