昔登铜井望法华,葱茏螺黛浮蒹葭。今登法华望铜井,湖水迷茫烟色瞑。-- 《登法华寺山顶》
Proxy是什么
Proxy是JS标准内置对象中的一个对象。用于创建一个对象的代理。从而实现对对象操作的拦截及自定义,功能类似于Object.defineProperty();
Proxy语法解读
const res = new Proxy(target,handler);
target
表示要包装的目标对象,可以是任意类型数组,函数,对象...
。handler
通常是一个函数作为属性的对象,比如{get:function(obj,prop){...}}
handler通常有以下几个方法
- hander.get(target,property,receiver)。
target
表示目标对象。property
表示被获取的属性名。receiver
表示Proxy或者继承Proxy的对象。这个方法可以用来拦截属性值得读取操作。
const res = new Proxy({}, {
get: function(target, prop, receiver) {
console.log("called: " + prop);
return 'test';
}
});
console.log(res.a); // "called: a"
// test
- handler.set(target, property, val)。
target
表示目标对象。property
表示被设置的属性名。val
表示新的属性值。这个方法可以用来设置属性值得读取操作。
const res = new Proxy({}, {
set: function(target, prop, val) {
target[prop] = val
return true;
}
});
res.test = '123'
console.log(res.test);//123
Vue中的proxy.js文件
/* not type checking this file because flow doesn't play well with Proxy */
import config from 'core/config'
import { warn, makeMap } from '../util/index'
let initProxy
if (process.env.NODE_ENV !== 'production') {
const 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
)
const warnNonPresent = (target, key) => {
warn(
`Property or method "${key}" is not defined on the instance but ` +
'referenced during render. Make sure that this property is reactive, ' +
'either in the data option, or for class-based components, by ' +
'initializing the property. ' +
'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
target
)
}
const hasProxy =
typeof Proxy !== 'undefined' &&
Proxy.toString().match(/native code/)
if (hasProxy) {
const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact')
config.keyCodes = new Proxy(config.keyCodes, {
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
}
}
})
}
const hasHandler = {
has (target, key) {
const has = key in target
const isAllowed = allowedGlobals(key) || key.charAt(0) === '_'
if (!has && !isAllowed) {
warnNonPresent(target, key)
}
return has || !isAllowed
}
}
const getHandler = {
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
const options = vm.$options
const handlers = options.render && options.render._withStripped
? getHandler
: hasHandler
vm._renderProxy = new Proxy(vm, handlers)
} else {
vm._renderProxy = vm
}
}
}
export { initProxy }
makeMap()
方法。
这个方法创建了一个Map结构,并且返回了一个方法用来检测指定的key是否在这个Map中。
export function makeMap (
str: string,
expectsLowerCase?: boolean): (key: string) => true | void {
const map = Object.create(null)
const list: Array = str.split(',')for (let i = 0; i map[list[i]] = true
}return expectsLowerCase
? val => map[val.toLowerCase()]
: val => map[val]
}
接下来判断浏览器是否支持proxy
const hasProxy =
typeof Proxy !== 'undefined' &&
Proxy.toString().match(/native code/)
之后将配置中keycodes做一层代理
const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact')
config.keyCodes = new Proxy(config.keyCodes, {
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
}
}
})
}
之后定义hasHandler和getHandler
const hasHandler = {
has (target, key) {
const has = key in target
const isAllowed = allowedGlobals(key) || key.charAt(0) === '_'
if (!has && !isAllowed) {
warnNonPresent(target, key)
}
return has || !isAllowed
}
}
const getHandler = {
get (target, key) {
if (typeof key === 'string' && !(key in target)) {
warnNonPresent(target, key)
}
return target[key]
}
}
最后,定义了initProxy方法。
将vue实例vm作为参数,根据实例的options.render切换了hander,然后有在vm实例上定义了_renderProxy
作为vm的代理。
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
}
}
那么问题来了,options.render是个什么鬼?
明天接着看看吧。
最后说两句
- 动一动您的小手,
「点个赞吧」
- 都看到这里了,不妨
「扫码加个关注」
![f60a4fea9963301f4887bc66083da8fc.png](https://i-blog.csdnimg.cn/blog_migrate/43873c1bfc07db5615d966881613e284.jpeg)