JS第五周
事件
定义:事件就是一件事情或者一个行为(对于元素来说,它的很多事件都是天生自带的),只要我们去操作这个元素,就会触发这些行为
事件就是元素天生自带的行为,我们操作元素,就会触发相关的事件行为
1.oBox.onclick=function(){};
元素天生自带的事件
鼠标事件
click
点击,PC端是点击,移动端的click代表单击
移动端使用click会有300MS延迟的问题,第一次点击后,如果在300MS内又点击了,浏览器认为其不是单击
dblclick
双击
mouseover
鼠标经过
mouseout
鼠标移出
mouseenter
鼠标进入
mouseleave
鼠标离开
mousemove
鼠标移动
mousedown
鼠标按下(鼠标左右键都起作用,它是按下即触发,click是按下抬起才会触发,而且是先把down和up触发,才会触发click)
mouseup
鼠标抬起
mousewheel
鼠标滚轮滚动,只要鼠标滚轮在滚动;而scroll是滚动条在滚动,让滚动条滚动有多种方式,可以用鼠标移动,也可以用滚轮移动,也可以用pagedown
键盘事件
keydown
键盘按下,ASCII码中对应的十进制的值(字母大写,其他如数字没有区别)
keyup
键盘抬起
keypress
和keydown类似,只不过keydown返回的是键盘码,keypress返回的是ASCII码值,ASCII码中对应的十进制的值(字母小写,其他如数字没有区别)
input(oninput,内容发生改变,就会触发事件)
由于PC端有实体物理键盘,可以监听到键盘的按下和抬起,但是移动端是虚拟触控键盘,所以keydown,keyup在大部分手机上都没有,我们使用input事件统一代替他们(内容改变事件)
表单元素常用事件
focus
获取焦点
blur
失去焦点
change(内容发生改变,鼠标按别的地方才会触发事件)
内容改变
其它常用事件
load
加载完成
unload
用户离开页面
点击某个离开页面的链接
-在地址栏中输入了新的URL
使用前进或者后退按钮
-关闭浏览器
-重新加载页面
beforeunload
优先于unload事件,可以阻止onunload事件的执行
beforeunload事件在新窗口被打开的时候并不会执行,只在刷新和关闭时执行
scroll
滚动条滚动事件
resize
大小改变事件
1.window.onresize=function(){};
2.当浏览器窗口大小发生改变,会触发这个事件,执行对应的事情
移动端手指事件
单手指操作
touchstart
手指按下
touchmove
手指移开
touchend
手指离开
touchcancel
因为意外情况导致手指操作取消
多手指操作
gesturestart
多手指按下
gesturechange
手指改变
gestureend
手指离开
H5的AUTO/VIDEO音视频事件
canplay
可以播放,播放过程中可能出现由于资源没有加载完成导致的卡顿
canplaythrougth
资源加载完成,可以正常无障碍播放
页面(浏览器)事件
移动端和PC端都有
load
加载成功
error
加载失败
readystatechange
AJAX状态改变
scroll
滚动
resize
改变大小
window.onresize浏览器窗口大小改变触发
事件绑定
给元素天生自带的事件行为绑定方法,当事件触发,会把对应的方法执行
1.oBox.onclick=function(){};
DOM0级事件绑定
语法:[element].onxxx=function(){};
每一个元素对象都是对应类的实例,浏览器天生为其设置了很多私有属性和公有的属性方法,而onclick就是其中的一个私有属性(事件类私有属性,还有很多其它的事件私有属性),这些属性默认值是null
原理:就是给元素的某一个事件私有属性赋值(浏览器会建立监听机制,当我们触发元素的某个行为,浏览器会自己把属性中赋的值去执行)
DOM0事件绑定:只允许给当前元素的某个事件行为绑定一个方法,多次绑定,后面绑定的内容会替换前面绑定的,以最后一次绑定的方法为准
1.box.onclick=function(){
2. console.log(1);
3.}
4.
5.box.onclick=function(){
6. console.log(2);
7.}
8.
9.最后输出了2;
DOM2级事件绑定
增加语法:[element].addEventListener(“xxx”,function(){},false);
移除语法:[element].removeEventListener(“xxx”,function(){},false);
addEventListener,removeEventListener这两个方法都是EventTarget.prototype上的方法
IE6~8增加:[element].attachEvent(“onxxx”,function(){});
IE6~8移除:[element].detachEvent(“onxxx”,function(){});
DOM2事件可以给当前元素的某一个事件行为绑定”多个不同的方法”
1. function fn1(){console.log(1);}
2. function fn2(){console.log(2);}
3. function fn3(){console.log(3);}
4. function fn4(ev){
5. console.log(4,this===box,ev.target);
6. box.removeEventListener('click',fn5);
7. box.removeEventListener('click',fn8);
8. }
9. function fn5(){console.log(5);}
10. function fn6(){console.log(6);}
11. function fn7(){console.log(7);}
12. function fn8(){console.log(8);}
13. function fn9(){console.log(9);}
14. function fn10(){console.log(10);}
15. function fn11(){console.log(11);}
16. function fn12(){console.log(12);}
17.
18. box.addEventListener('click',fn1);
19. box.addEventListener('click',fn3);
20. box.addEventListener('click',fn5);
21. box.addEventListener('click',fn7);
22. box.addEventListener('click',fn9);
23. box.addEventListener('click',fn2);
24. box.addEventListener('click',fn2);//=>重复
25. box.addEventListener('click',fn2);//=>重复
26. box.addEventListener('mouseenter',fn2);//=>增加到事件池中的
27. box.addEventListener('click',fn4);
28. box.addEventListener('click',fn6);
29. box.addEventListener('click',fn8);
30. box.addEventListener('click',fn10);
31. box.addEventListener('click',fn11);
32. box.addEventListener('click',fn12);
33.
34.
35.//=>输出结果
36.//2,1,3,5,7,9,2,4,6,10,11,12
DOM2事件要注意堆内存的问题
1.//=>变量提升阶段,fn1被声明加定义,地址指向第二个函数(console.log(2))的空间地址aaa,接下来JS代码自上而下执行,给box的click事件绑定了一个方法(该方法是addEventListener的一个私有变量,只是和全局中的指向同一个堆内存),方法的堆内存指向aaa,同时向浏览器的事件池中添加一个click事件的方法,再往下执行,执行removeEventListener方法,并把fn1也传给他作为私有变量,但是也是指向全局下的空间地址,执行时找到fn1的空间地址,把它从事件池中移除,此时全局下的fn1还是存在的,只是从事件池中移除了而已
2.function fn1(){
3. console.log(1);
4.}
5.function fn1(){
6. console.log(2);
7.}
8.box.addEventListener("click",fn1,false);
9.setInterval(function(){
10. box.removeEventListener("click",fn1,false);
11.},5000);
12.setTimeout(function () {
13. fn1();
14.},6000);
15.//=>页面加载完成5s内点击box都会执行fn1,5s后fn1从事件池内清除,但是全局下的fn1还是存在的,所以第6s还是会输出2
DOM2的兼容问题
谷歌 VS IE高版本:谷歌在移除事件绑定的时候,如果移除操作放在正要执行的方法之前(例如:点击的时候,正要执行FN8,但是在执行FN4的时候,我们把FN8从事件池中移除了),谷歌下是立即移除生效,第二次也不再执行FN8了,而IE是当前本次不生效,下一次点击才生效,第一次点击还是要执行FN8的;
标注 VS IE低版本
标准:addEventListener/removeEventListener
IE低版本:attachEvent/detachEvent
this问题:标准浏览器中,行为触发方法执行,方法中的this是当前元素本身,IE低版本中THIS指向了WINDOW;DOM0级事件IE低版本,高版本和标准浏览器中this都指向绑定的当前元素
重复问题:标准浏览器中的事件池是默认去重复的,同一个元素的同一个事件行为不能出现相同的绑定方法,但是IE低版本的事件池机制没有那么完善,不能默认去重,也就是可以给同个元素的同个事件绑定相同的方法了
顺序问题:标准浏览器是按照向事件池中存放的顺序依次执行的,而IE低版本是乱序执行的,没有规律
DOM0事件绑定和DOM2事件绑定的区别
1.机制不一样
DOM0采用的是给私有属性赋值,所以只能绑定一个方法
DOM2采用的是事件池机制,所以能绑定多个不同的方法
2.移除的操作
DOM0级事件只要手动赋值为NULL即可移除,所以不必须要考虑绑定的是什么方法
DOM2在移除的时候必须清楚要移除哪一个方法,才能在事件池中移除掉,所以基于DOM2做事件绑定,尽量不要绑定匿名函数,都绑定实名函数
1.box.onclick=function(){};
2.box.onclick=null;//=>赋值为null就移除了(所以不需要考虑绑定的是谁)
3.
4.box.addEventListener("click",function(){console.log(1);});
5.
6.box.removeEventListener("click",function(){
7. console.log(1);
8.})
9.//=>移除的并不是上面刚刚增加的方法,addEventListener和removeListener都是EventTarget原型上的方法,相当于调取原型上的方法并执行,所以括号里的相当于实参,那么就是这个函数的私有变量方法被执行的时候,fn指向一个堆内存,下面的被执行的时候,fn又指向另外一个堆内存
3.DOM2事件绑定中增加了一些DOM0无法操作的事件行为,例如:DOMContentLoaded事件(当页面中的HTML结构加载完成就会触发执行)
1.box.addEventListener("DOMCotentLoaded",fn);//=>可以
2.
3.box.onDOMContentLoaded=fn;//=>不可以,box没有这个属性
4.--------------
5.window.onload=function(){
6. //=>当页面中的资源都加载完成(HTML结构加载完、CSS和JS等资源加载完成等)才会触发执行,而且只能执行一次
7.}
8.window.addEventListener("load",function(){});//=>这样处理就可以执行多次了
9.
10.--------
11.jQuery中传递的selector是函数也是模拟了window.onload的方法,但是等到页面中的HTML结构加载完成就会执行,jQuery中使用的是DOM2事件,就是基于DOMContentLoad完成的,所以可以执行多次
12.else if ( jQuery.isFunction( selector ) ) {
13. return typeof rootjQuery.ready !== "undefined" ?
14. rootjQuery.ready( selector ) :
15. selector( jQuery );
16. }
17.rootjQuery=jQuery(document);//=>把document转换为JQ对象
18.所以$(function(){})相当于$(document).ready(function(){})
19.//=>原理:基于DOMContentLoaded完成的(IE中用的是onreadystatechange监听的,在document.readyState==="complete"的时候执行函数)
20.
21.jQuery.ready.promise = function( obj ) {
22. if ( !readyList ) {
23. readyList = jQuery.Deferred();
24. if ( document.readyState === "complete" ) {//=>标准浏览器中的
25. setTimeout( jQuery.ready );
26. } else if ( document.addEventListener ) {
27. document.addEventListener( "DOMContentLoaded", completed, false );
28. window.addEventListener( "load", completed, false );
29. } else {//=>IE中的
30. document.attachEvent( "onreadystatechange", completed )
31. window.attachEvent( "onload", completed );
JQ中的事件绑定
on/off:基于DOM2事件绑定实现时间的绑定和移除(兼容所有的浏览器)
1.$(document).on("click",fn);
2.$(document).off("click",fn);
one:只绑定了一次,第一次执行完成后,会把绑定的方法移除(基于ON/OFF完成的,在on的事件的末尾加上移除这个事件)
1.function fn(){
2. $(document).off("click",fn);
3.}
4.$(document).on("click",fn);
click/mouseover/mouseout…:JQ提供快捷绑定方法,但是这些方法最后都是基于ON/OFF完成的
1.$(document).click(fn);
delegate:事件委托方法
1.$(document).delegate("#box","click",fn)
2.//=>把点击事件委托给document,不管点击文档中的哪一个元素,都会触发文档的点击行为,第一个参数代指事件源是
bind/unbind:正常绑定
事件中低版本浏览器和标准浏览器的区别
1、:给事件绑定的方法被触发是低版本浏览器不会给事件传递事件对象,需要通过window.event获取,对应的事件对象上的一些属性的兼容问题
2、:冒泡传播的机制,标准浏览器是一直传播到window,IE高版本浏览器是传播到window,但是少了document,IE低版本浏览器一直传播到html为止
3、:DOM2事件的相关兼容问题:语法、this指向、重复问题、事件池顺序
事件对象
事件对象中记录了很多属性名和属性值(存储当前鼠标操作的信息),这些信息中包含了当前操作的基础信息,例如:鼠标点击位置的x/y轴坐标,鼠标点击的是谁(事件源)等信息
每一次事件触发浏览器传递进来的事件对象其实是一个实例,例如MouseEvent是MouseEvent这个类的实例
MouseEvent
鼠标事件对象
1.box.onclick=function(ev){
2. console.log(ev.target);
3.};
KeyboardEvent
键盘事件对象
1.button.onkeydown=function(ev){
2. console.log(ev.code);
3.};
Event
普通事件对象
1.window.onscroll=function(ev){
2. console.log(ev.preventDefault);
3.}
FocusEvent
表单事件对象
1.myInput.onfocus=function(ev){
2. console.log(ev.target);
3.};
WheelEvent
鼠标滚轮滚动对应的时间对象
1.myInput.onmousewheel=function(ev){
2. console.log(ev.target);//=>body
3.};
MouseEvent/wheelEvent中常用的属性
type
记录的是事件类型
path
记录的是事件冒泡传播的路径
[div
target
事件源(操作的是那个元素),MouseEvent实例上的私有属性
低版本浏览器中不存在target,所以低版本浏览器下,使用srcElement
clientX/clientY
当前鼠标出发点距离当前可视窗口左上角的x/y轴轴坐标,MouseEvent实例上的私有属性
pageX/pageY
当前鼠标出发点距离BODY(第一屏幕)左上角的X/Y轴坐标,MouseEvent实例上的私有属性
低版本浏览器中不存在pageX/pageY,所以低版本浏览器下,使用scrollTop+clientY
preventDefault
阻止默认行为,不兼容IE6~8,Event这个类原型上的方法
低版本浏览器中不存在preventDefault,所以低版本浏览器下,使用returnValue=false
stopPropagation
阻止事件的冒泡传播,不兼容IE6~8,Event这个类原型上的方法
低版本浏览器中不存在stopPropagation,所以低版本浏览器下,使用cancelBubble=true
兼容低版本浏览器
处理兼容,低版本中没有的属性,我们手动设置,按照自己有的先获取到值,然后赋值给和标准对应的新属性,后期再使用的时候,直接按照高版本的使用即可
低版本浏览器中对应的属性其实事件对象上都有,所以也可以统一用低版本浏览器那一套属性来进行操作
1.box.onclick=function(ev){
2. if(!ev){
3. let ev=window.event;
4. ev.target=ev.scrElement;
5. ev.pageX=ev.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft);
6. ev.pageY=ev.clientY+(document.documentElement.scrollTop||document.body.scrollTop);
7. ev.preventDefault=function(){
8. ev.returnValue=false;
9. }
10. ev.stopPropagation=function(){
11. ev.cancleBubble=true;
12. }
13. ev.which=ev.keyCode;
14. }
15. ev.preventDefault();
16. ev.stopPropagation();
17.};
18.
19.----------------
20.也可以用到谁就处理谁的兼容
21.box.onclick=function(ev){
22. ev=ev||window.event;
23. var target=ev.target||ev.scrElement;
24. ev.preventDefault?ev.preventDefault():ev.returnValue=false;
25.};
KeyboardEvent中常用的属性
code
当前按键”keyE”
key
当前按键”e”
which/keyCode
当前按键的ASCII编码
1.keyCode是用于兼容IE的
2.
3.let code=ev.which||ev.keyCode;
常用键盘码
左-上-右-下:37-38-39-40
Backspace:8
Enter:13
Space:32
数字键:48~57
小写字母:65~90
Delete:46
Shift:16
Alt:18
Ctrl:17
ESC:27
事件的默认行为
事件本身就是天生就有的,某些事件触发,即使你没有绑定方法,也会存在一些效果,这些默认效果就是”事件的默认行为”
举例1--A标签
A标签的点击操作就存在默认行为
1、 页面跳转
2、锚点定位(HASH定位[哈希定位])
首先会在当前页面URL地址栏末尾设置一个HASH值,浏览器检测到HASH值后,会默认定位到当前页面中ID和HASH相同的盒子的位置(基于HASH值我们还可以实现SPA单页面应用)
举例2--input标签
1.输入内容可以呈现到文本框中
2.输入内容的时候会把之前输入的一些信息呈现出来(并不是所有浏览器和所有情况都有)
举例3--submit标签
1.点击按钮页面会刷新,在form中设置action属性,点击submit,会默认按照action指定的地址进行页面的跳转,并且把表单中的信息传递进去(非前后端分离中,由服务器进行页面渲染,由其它语言实现数据交互,一般都是这样处理)
1.<form action="http://www.zhufengpeixun.cn/">
2. <input type="submit" value="提交">
3.</form>
如何阻止默认行为
阻止A标签中的默认行为
在结构中阻止
1.<a href="javascript:;">珠峰培训最新视频</a>;
2.javascript:void 0/undefined/null...;
3.
4.//=>冒号和分号之间可以用其它占位
在JS中也可以阻止,给其click事件绑定方法,当我们点击A标签的时候,先触发click事件,其次才会执行自己的默认行为
1.link.onclick=function(ev){
2. ev=ev||window.event;
3. ev.preventDefault?ev.preventDefault():ev.returnValue=false;
4.}
5.
6.-------------
7.link.onclick=function(ev){
8. ev=ev||window.event;
9. return false;//=>原理:点击A的时候,首先触发的是click,其次才会触发它的默认行为(我们在click中返回false,其意思是阻止下一步继续操作)
10.}
input text文本框内最多输入6位
1.myInput.onkeydown = function (ev) {
2. ev = ev || window.event;
3. let value = ev.target.value;
4. let reg = /^\s+|\s+$/g;
5. if (reg.test(value)) {
6. value = value.replace(reg, "");
7. }
8. let len = value.length;
9. if (len >= 6) {
10. let reg = /^(8|13|46|37|38|39|40)$/;
11. if (!reg.test(ev.which)) {
12. ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
13. }
14. }
15.};
事件的传播机制
冒泡传播
触发当前元素的某一个事件(点击事件)行为,不仅当前元素事件行为触发,而且其祖先元素的相关事件行为也会依次被触发,这种机制就是”事件的冒泡传播机制”
事件传播的三个阶段
1、捕获阶段:点击inner的时候,首先会从最外层开始向内查找(找到操作的事件源),查找的目的是,构建出冒泡传播阶段需要传播的路线(查找是按照HTML层级结构找的)
2、目标阶段
把事件源的相关操作行为触发(如果绑定了方法,则把方法执行)
3、冒泡传播
按照捕获阶段规划的路线,自内而外,把当前事件源的祖先元素的相关事件行为依次触发(如果某个祖先元素事件行为绑定了方法,则把方法执行,没绑定方法,行为触发了,什么都不做,继续向上传播即可)
1.window.onclick = function () {
2. console.log('window');
3.};
4.
5.document.onclick = function () {
6. console.log('document');
7.};
8.
9.document.documentElement.onclick = function () {
10. console.log('html');
11.};
12.outer.onclick = function (ev) {
13. console.log('outer');//=>TRUE
14.};
15.
16.inner.onclick = function (ev) {
17. console.log('inner');
18.};
19.//=>inner outer html document window
不同浏览器对于最外层祖先元素的定义是不一样的
谷歌:window->document->html->body
IE高:window->html->body
IE低:html->body…
1、事件对象是用来存储当前本次操作的相关信息,和操作有关,和元素无必然关联
2、当我们基于鼠标或者键盘等操作的时候,浏览器会把本次操作的信息存储起来(标准浏览器存储到默认的内存中(自己找不到),IE低版本存储到window.event中了),存储的值是一个对象(堆内存);操作肯定会触发元素的某个行为,也就会把绑定的方法执行,此时标准浏览器会把之前存储的对象(准确来说是堆内存地址),当做实参传递给每一个执行的方法,所以操作一次,即使再多方法中都有EV,但是存储的值都是一个(本次操作信息的对象而已)
1.//=>三个click事件用的是同一个事件对象
2.let aa = null;
3.document.body.onclick = function (ev) {
4. console.log('body', ev, ev === aa);//=>TRUE
5.};
6.
7.outer.onclick = function (ev) {
8. console.log('outer', ev, ev === aa);//=>TRUE
9.};
10.
11.inner.onclick = function (ev) {
12. ev = ev || window.event;
13. aa = ev;
14.};
15.
想要阻止冒泡传播的话,可以通过事件对象的stopPropagation方法(Event原型上的)
1.document.body.onclick = function (ev) {
2. console.log("body");
3.};
4.
5.outer.onclick = function (ev) {
6. ev = ev || window.event;
7. ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;
8. console.log('outer', ev);
9.};
10.
11.inner.onclick = function (ev) {
12. console.log('inner', ev);
13.};
onmouseenter和onmouseover的区别
1、over属于滑过(覆盖)事件,从父元素进入到子元素,属于离开了父元素,会触发父元素的out,触发子元素的over
2、enter属于进入,从父元素进入子元素,并不算离开父元素,不会触发父元素的leave,触发子元素的enter
3、enter和leave阻止了事件的冒泡传播,而over和out还存在冒泡传播的,所以对于父元素嵌套子元素这种情况,使用over会发生很多不愿意操作的事情,此时我们使用enter会更加简单,操作方便,所以真实项目中enter的使用会比over多
4、over和enter,over先触发;out和leave,out先触发
事件委托(事件代理)
利用事件的冒泡传播机制,如果容器的后代元素中,很多元素的点击行为(其它事件行为也是)都要做一些处理,此时我们不需要再像以前那样一个一个获取一个一个的绑定了,我们只需要给容器的click绑定方法即可,这样不管点击的是哪个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而做不同的事情
发布订阅设计模式(观察者模式)
准备一个容器,把到达指定时候要处理的事情,首先一一的增加到容器中(发布计划并且向计划表中订阅方法),当到达指定时间点,通知容器中的方法依次执行即可
发布订阅设计模式源码
1.(function(){
2. class Subscribe{
3. constructor(){
4. this.pond=[];
5. }
6. add(fn){
7. let pond=this.pond,
8. isExist=false;//=>代表fn在pond中不存在,如果不存在就加入pond中
9. for(let i=0;i<pond.length;i++){//=>那fn和pond中的每一项进行比较,如果有相等的项,证明fn在pond中已经存在了,那么让isExist变成true就不用往里面存了
10. let item=pond[i];
11. item===fn?isExist=true:null;
12. if(isExist){
13. return;
14. }
15. }
16. !isExist?pond.push(fn):null;
17. }
18. remove(fn){
19. let pond=this.pond;
20. for(let i=0;i<pond.length;i++){
21. let item=pond[i];
22. item===fn?pond[i]=null:null;//=>移除的时候赋值为null而不是直接删除掉,因为如果执行容器的时候,假如同时操作了remove函数,那会导致数组的索引发生改变
23. }
24. }
25. fire(...arg){
26. let pond=this.pond;
27. for(let i=o;i<pond.length;i++){
28. if(item===null){//=>把从容器中移除的事件去除掉,而且不执行
29. pond.splice(i,1);
30. i--;
31. continues;
32. }
33. item(...arg);
34. }
35. }
36. }
37. window.Subscribe=Subscribe;
38.})()
jQuery中提供的发布订阅设计模式
1.let $plan=$.Callbacks();//=>创建一个空的计划表:空容器
2.setTimeout(function(){
3. $plan.fire(10,20);//=>fire就是通知容器中的方法按照顺序依次执行的:10和20是执行容器中每一个方法的时候,都给他们传递两个参数值
4.},1000);
5.
6.function fn(){};
7.
8.$plan.add((x,y)=>{//ADD是向容器中增加方法
9. console.log(1);
10.});
11.$plan.add(fn);
12.
13.$plan.remove(fn);//=>remove是从容器中移除方法
Function原型上bind的原理
执行bind方法,会形成一个不销毁的私有栈内存(AAA),返回一个新的匿名函数(每一次返回的都不不一样,不是相同的堆内存)
1.Function.prototype.myBind=function myBind(contexte,...arg){
2.//=>this:当前调取bind方法的函数
3.//=>context:把调取方法的函数中的this改为context
4.//=>arg:需要传递给调取方法的函数的实参
5.//=>以上这些都是执行bind方法中的私有变量
6. let _this=this;
7. return function anonymous(...innerArg){
8.//=>inneArg可能有值,可能没有值,如果把binde的返回结果给元素的时间绑定,则事件触发,执行这个匿名函数,会把事件对象传递进来ev _this.apply(context,arg.contact(innerArg));
9. console.log(this);//=>如果绑定了事件,这里的this指的是绑定事件的元素
10. }
11.}
1.function fn(){
2. console.log(1);
3.}
4.let obj={};
5.box1.onclick=fn.myBind(obj,10);//=>bind方法中的this指的是fn
6.相当于 box1.onclick=function anonymous(ev){
7. fn.apply(obj,[10,ev]);
8. //=>匿名函数中的this指的是box1
9.}
10.//=>当我们触发box的点击行为,执行的是返回的匿名函数