在Vue.prototype._init 中有一些init函数,今天我们来研究这些init函数
Vue.prototype._init = function (options) {......{initProxy(vm);}......initLifecycle(vm);initEvents(vm);initRender(vm);callHook$1(vm, 'beforeCreate', undefined, false /* setContext */);initInjections(vm); // resolve injections before data/propsinitState(vm);initProvide(vm); // resolve provide after data/propscallHook$1(vm, 'created');......
}
接下来我们逐步分析,先分析initProxy(vm)
Vue.prototype._init = function (options) {......{initProxy(vm);}......
}
查看initProxy源码
initProxy = function initProxy(vm) {if (hasProxy) {// determine which proxy handler to useconst options = vm.$options;const handlers = options.render && options.render._withStripped ? getHandler : hasHandler;vm._renderProxy = new Proxy(vm, handlers);}else {vm._renderProxy = vm;}
};
通过判断hasProxy,来执行不同的处理逻辑
我们看下hasProxy的源码
const hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy);
它的作用就是判断当前环境中Proxy是否可用
// determine which proxy handler to use
const options = vm.$options;
const handlers = options.render && options.render._withStripped ? getHandler : hasHandler;
回到代码中,如果当前环境存在Proxy,则执行块内的语句
三元表达式,如果options上存在render属性,且render属性上存在_withStripped属性,则proxy的traps(traps其实也就是自定义方法)采用getHandler方法,否则采用hasHandler方法
接下来看看getHandler和hasHandler方法
const getHandler = {get(target, key) {if (typeof key === 'string' && !(key in target)) {if (key in target.$data)warnReservedPrefix(target, key);elsewarnNonPresent(target, key);}return target[key];}
};
const hasHandler = {has(target, key) {const has = key in target;const isAllowed = allowedGlobals(key) ||(typeof key === 'string' &&key.charAt(0) === '_' &&!(key in target.$data));if (!has && !isAllowed) {if (key in target.$data)warnReservedPrefix(target, key);elsewarnNonPresent(target, key);}return has || !isAllowed;}
};
getHandler方法主要是针对读取代理对象的某个属性时进行的操作。当访问的属性不是string类型或者属性值在被代理的对象上不存在,则抛出错误提示,否则就返回该属性值
hasHandler方法的应用场景在于查看vm实例是否拥有某个属性—比如调用for in循环遍历vm实例属性时,会触发hasHandler方法。
回到initProxy代码中
if (hasProxy) {...vm._renderProxy = new Proxy(vm, handlers)} else {vm._renderProxy = vm}
}
如果Proxy属性存在,则把包装后的vm属性赋值给_renderProxy属性值,否则把vm是实例本身赋值给_renderProxy属性。