vue原理分析(八)研究new Vue()中的initProxy
在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/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook$1(vm, 'created');
......
}
接下来我们逐步分析,先分析initProxy(vm)
Vue.prototype._init = function (options) {
......
{
initProxy(vm);
}
......
}
查看initProxy源码
initProxy = function initProxy(vm) {
if (hasProxy) {
// determine which proxy handler to use
const 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);
else
warnNonPresent(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);
else
warnNonPresent(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属性。