从vue源码来看Proxy的用途
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).MDN Proxy
MDN表述该对象构造器是用于对某对象定义用户自定义行为的。那么,这到底是什么意思呢?我们下面直接来分析一下Vue源码中应用到Proxy对象的地方,来理解该对象构造器的作用。
Proxy在Vue中的应用
首先我们来看一看Vue源码的 1430行
/* not type checking this file because flow doesn't play well with Proxy */
var initProxy;
{
var allowedGlobals = makeMap(
'Infinity,undefined,NaN,isFinite,isNaN,' +
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
'require' // for Webpack/Browserify
);
var warnNonPresent = function(target, key) {
warn(
"Property or method \"" + key + "\" is not defined on the instance but " +
"referenced during render. Make sure to declare reactive data " +
"properties in the data option.",
target
);
};
var hasProxy = typeof Proxy !== 'undefined' &&
Proxy.toString().match(/native code/);
if (hasProxy) {
var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta');
config.keyCodes = new Proxy(config.keyCodes, {
set: function set(target, key, value) {
if (isBuiltInModifier(key)) {
warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key));
return false
} else {
target[key] = value;
return true
}
}
});
}
var hasHandler = {
has: function has(target, key) {
var has = key in target;
var isAllowed = allowedGlobals(key) || key.charAt(0) === '_';
if (!has && !isAllowed) {
warnNonPresent(target, key);
}
return has || !isAllowed
}
};
var getHandler = {
get: function get(target, key) {
if (typeof key === 'string' && !(key in target)) {
warnNonPresent(target, key);
}
return target[key]
}
};
initProxy = function initProxy(vm) {
if (hasProxy) {
// determine which proxy handler to use
var options = vm.$options;
var handlers = options.render && options.render._withStripped
? getHandler
: hasHandler;
vm._renderProxy = new Proxy(vm, handlers);
} else {
vm._renderProxy = vm;
}
};
}
首先,我们要明白一件事情,vue放弃了对ie9以下的支持。即使这样,由于Proxy作为一个es6的新特性,支持度依然不高,作者也只是尝试着使用了一下。下面我们来一步一步讲解。
源码讲解
var allowedGlobals = makeMap(
'Infinity,undefined,NaN,isFinite,isNaN,' +
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
'require' // for Webpack/Browserify
);
该处定义了所允许的全局对象类型。
var warnNonPresent = function(target, key) {
warn(
"Property or method \"" + key + "\" is not defined on the instance but " +
"referenced during render. Make sure to declare reactive data " +
"properties in the data option.",
target
);
};
该处定义了一个报警方法,传入键名或方法名,log显示一条警告
var hasProxy = typeof Proxy !== 'undefined' &&
Proxy.toString().match(/native code/);
该处是对es6特性Proxy的检测, 其检测手段是确认Proxy是原生实现并未被用户代码所覆盖。
var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta');
config.keyCodes = new Proxy(config.keyCodes, {
set: function set(target, key, value) {
if (isBuiltInModifier(key)) {
warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key));
return false
} else {
target[key] = value;
return true
}
}
});
该段代码对config.keyCodes对象进行了代理,其意义在于禁止用户修改Vue内建的一些按键值,这些按键值和按键名是对应的。如果用过Vue的用户应该知道,Vue在事件对象上对一些常用按键和常用操作进行了内建(这个内建过程被用eval函数压缩了,由一堆代码段构成的,没什么看头),作者肯定不希望也不允许用户修改配置的时候覆盖了内建内容。于是,当我们做config.keyCodes[‘stop’] = xxx这样的操作的时候,Vue就会告诉你说“你这个人,不老实,为什么想着改我东西”,直接打出禁止改写内建配置的警告。如果非内建内容,那么可以直接设置上。
initProxy = function initProxy(vm) {
if (hasProxy) {
// determine which proxy handler to use
var options = vm.$options;
var handlers = options.render && options.render._withStripped
? getHandler
: hasHandler;
vm._renderProxy = new Proxy(vm, handlers);
} else {
vm._renderProxy = vm;
}
};
这句话就不再解释了,类似上面。不过读者可能会问has是什么? 那么下面我们来讲解一下Proxy的各个参数
Proxy所需参数
两个, var b = new Proxy(a, { has: fn xxx, get: fn xxx, set: fn xxx …. })
target 被代理的对象
handler 处理器对象
用来定义我们对该对象的各种操作
完整的handler处理器对象内容:
{
get: '咋获取',
set: '咋设置',
deleteProperty: '咋删除',
enumerate: '咋枚举',
ownKeys: '咋获取所有该对象的属性键 ',
has: '问你有没有, 比如 "xxx" in target',
defineProperty: '如何defineProperty, 这个我们也是可以代理的',
getOwnPropertyDescriptor: '获取属性描述的代理',
getPrototypeOf: '找原型时候的代理',
setPrototypeOf: '设置对象原型的时候的代理',
isExtensible: '判断对象是否可扩展的时候的代理',
preventExtensions: '设置阻止对象扩展的时候的代理',
apply: '执行调用操作的时候的代理',
construct: '执行实例化的时候的代理'
}
以上皆是函数~~
所以Proxy的作用是?
拦截,预警,上报,扩展功能,统计,强化对象…能想得到的都能沾到点边,这里Vue的代码主要将代理运用于拦截。并且由于规范依然在发展,所以大家慎用。。。