React-事件补遗-Proxy
上一篇留了一个代理Proxy
没覆盖到,因为之前没怎么使用过,所以这篇补充一下相关内容。
Proxy
用于定义基本操作自定义行为(比如:属性查找get
,赋值set
,枚举、函数调用等)。使用Proxy
代理,可以在目标对象(target)进行操作之前,进行过滤和额外操作。
Proxy
基本使用
var p = new Proxy(target, handler);
target
:代理虚拟化的对象,会用Proxy包装。可以是任何类型的对象,包括数组(native array)、函数(function),甚至另外一个Proxy。
handler
:包含各种属性访问的方法,定义操作到达时进行何种操作。类似于操作系统中的traps
概念。
注意,后面的操作,如果要通过handler的方法,所有操作必须都是在实例p上,而非原始的target对象上。
这里列举handler
里方法中几个会用到的:
handler.apply(target, thisArg, argumentsList)
:以函数方式调用时的方法(trap);
handler.construct(target, argumentsList, newTarget)
:使用new操作符时的方法(trap);
handler.get(target, property, receiver)
:取值时的方法(trap);
handler.set(target, property, value, receiver)
:赋值时的方法(trap)。
React
中Proxy
处理事件
React
中的合成事件(SyntheticEvent
)就是使用代理实现的。每个具体事件,都带有不同的属性接口(interface
),比如鼠标事件需要有点击位置(clientX、clientY)等,过渡事件有属性名(propertyName)等。每个都按同样的层次逆向扩展:具体事件 > 抽象层1 > … > 抽象层n > 基础合成事件。比如鼠标事件(SyntheticMouseEvent
)的生成过程如下:
SyntheticMouseEvent.call(instance, a1, a2, a3, a4)
=SyntheticUIEvent.call(instance, a1, a2, a3, a4)
=SyntheticEvent.call(instance, a1, a2, a3, a4)
SyntheticMouseEvent
、SyntheticUIEvent
、SyntheticEvent
的关系:
SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
SyntheticEvent
对象的处理。直接跳到该文件,可以看到,合成事件主要使用的就是代理(Proxy
),最终在apply
方法(trap),返回另外一个Proxy
,也是赋值时实际用到的:
SyntheticEvent = new Proxy (SyntheticEvent, {
construct: function (target, args) {
return this.apply(target, Object.create(target.prototype), args);
},
apply: function (constructor, that, args) {
return new Proxy(constructor.apply(that, args), {
set: function (target, prop, value) {
...
target[prop] = value;
return true;
}
}
}
});
这里construct
使用了this.apply(...)
,即无论使用call/apply
或者使用new
操作符,都会转到apply
统一处理,最终都返回对应的新Proxy
对象。
另外,apply里的set,还判断了在新增属性时,预处理(提供警告)的功能:合成事件是有池的,用过之后会被清空并返回池中,达到复用效果以提高性能。所以在其上添加的属性,会被清空,除非是永久化(isPersistent)的事件。
调用过程
new SyntheticMouseEvent
// ... 中间几层call调用
-SyntheticEvent.call
=SyntheticEvent代理(Proxy)的apply方法
-SyntheticEvent.apply // 调用SyntheticEvent的函数方法,扩展this(即SyntheticMouseEvent)对象
-返回新的Proxy对象,target为扩展后的SyntheticMouseEvent
SyntheticEvent
初始化时,会从this.constructor
(这里是SyntheticMouseEvent
)里取interface
的字段来添加属性,这里的作用域this
是由call
函数的第一个参数(thisArgs
)指定的作用域。
后面为SyntheticMouseEvent
添加属性(_dispatchListener
、_dispatchInstances
等),都会通过新Proxy
的set
方法(trap)。
SyntheticEvent的作用总结
1、为各类事件制定统一的初始化、销毁行为;
2、使用代理,降低了代码耦合度(与具体事件无关),方便扩展和修改;
3、使用pool,提高复用率,避免资源浪费。
Proxy使用注意
相对来说,handler
内容比较固定,常用的就是set
、get
、construct
、apply
。
var handler = {
get: function(obj, prop) {
console.log('call get method');
return prop in obj ?
obj[prop] : 'default value';
},
set: function (obj, prop, value) {
console.log('call set method');
obj[prop] = value;
return true;
}
};
target的类型
target
决定了生成的代理对象的种类。比如,当target
是对象时,不能使用new
或apply
来进一步新建对象或调用函数方法。当target
是数组时,可以用push
、pop
等方法。当target
是函数是,可以使用new
来生成目标对象,使用apply/call
来调用函数。
1、对象(字面量或数组等)
var p = new Proxy({}, handler);
p.t = 123; // 'call set method'
console.log(p.t); // 'call get method'
比如可以在set里添加校验等内容,get里添加格式化输出等。
2、function
或另一个Proxy
var p = new Proxy(function() {}, handler);
var instance = new p();
如果handler
里定义了construct
方法,使用new
时,会进入该方法。
如果handler
里定义了apply
方法,使用apply/call
时,会进入该方法。
学习了,完全看不懂的技术知识
可惜不是网页代理。
貌似非常久没来了,最近都不更新生活篇了啊。
@郑永 说的是哦,最近好像都没更新生活篇,安排上
收藏学习了
还是得从基础知识一步一步来,这个目前还看不懂
谷歌seo优化