这是原文链接:Our Backwards DOM Event Libraries

浏览器APIs

先简单回顾一下各个浏览器提供了哪些绑定事件的接口。

IE浏览器提供了element.attachEvent接口,可以绑定事件到元素上面。

document.body.attachEvent(
'onclick',
function() {
alert('body clicked');
});

其他浏览器则提供了element.addEventListener接口,我们比较熟悉的是绑定一个函数到元素上。

document.body.addEventListener(
'click',
function() {
alert('body clicked');
},
false);

许多javascript程序员还不知道其实还可以传递一个object给addEventListener当作第二个参数,当事件被触发时,该object的handleEvent方法被调用。

document.body.addEventListener(
'click',
{
handleEvent: function() {
alert('body clicked');
}
},
false);

使用object作为第二个参数有一个重要的特征:handleEvent属性的函数值只会在事件触发的时候会被调用。这意味着我们改变handleEvent属性的函数值,那么事件触发时就会调用不同的函数,也就是延迟绑定。举个例子:

var obj = {};

document.body.addEventListener('click', obj, false);

// click body will error in some browsers because
// no handleEvent method on obj obj.handleEvent = function() {alert('alpha');}; // click body and see alert "alpha" obj.handleEvent = function() {alert('beta');}; // click body and see alert "beta" document.body.removeEventListener('click', obj, false); // click body and see nothing

跨浏览器的库

我们实现跨浏览器的应用时,不应该因为不同浏览器的混乱的APIs写出糟糕而重复的代码,有一个好主意就是抽象出不同的APIs,实现我们自己的事件库。

不同的库有不同的APIs,但是每个库都有一个类似下面的接口:

LIB_addEventListener(
document.body,
'click',
function() {
alert('body clicked');
});

关于javascript中this的技巧

这些库都有一个常见的问题:如果事件触发,我们调用的是视图对象的一个方法就会有问题。举个例子,比如下面的代码。handleClick方法中this的值是window对象。所以alert会显示undefined,而不是我们期待的alpha。

function ViewObject() {
this.data = 'alpha';
LIB_addEventListener(
document.body,
'click',
this.handleClick);
}
ViewObject.prototype.handleClick = function() {
alert(this.data);
};

这些库中已经给出了解决办法,就是指定一个额外的参数作为this的值。这同样有利于解除事件监听。举例如下,alert会显示alpha。

function ViewObject() {
this.data = 'alpha';
LIB_addEventListener(
document.body,
'click',
this.handleClick,
this);
}
ViewObject.prototype.handleClick = function() {
alert(this.data);
};
ViewObject.prototype.destroy = function() {
LIB_removeEventListener(
document.body,
'click',
this.handleClick,
this
);
};

目前的API仍然有一个隐藏的问题:当LIB_addEventListener被调用时,监听函数就已经被绑定了。这时如果我们改变handleClick的函数值并且尝试删除监听函数,就会遇到问题。

var vo = new ViewObject();

// click on the body and see alert "alpha"

vo.handleClick = function() {
alert('beta');
}; // click on the body and still see "alpha" vo.destroy(); // click on the body and still see "alpha"!

还有一个问题就是我们采用面向对象的方式编程,但是我们却在关注listener functions而不是listener objects。这种不匹配是寻找更优解的线索。

适配listener objects的API

由于我们经常采用面向对象的方式来编程,所以很有必要让LIB_addEventListener可以接受listener objects(当然也接受listener functions)

var obj = {
handleEvent: function() {
alert('click handler');
}
};
LIB_addEventListener(document.body, 'click', obj);

通常我们会有一个视图对象来处理各种元素的多种事件。不过需要第四个参数来指定方法名称。这仍然可以实现延迟绑定。

var obj = {
handleMouseDown: function() {
alert('mouse down handler');
},
handleMouseUp: function() {
alert('mouse up handler');
}
};
LIB_addEventListener(document.body, 'mousedown', obj, 'handleMouseDown');
LIB_addEventListener(document.body, 'mouseup', obj, 'handleMouseUp');

通过判断第三个参数的类型,该API仍然可以接收listener functions。

LIB_addEventListener(document.body, 'mousedown', function() {
alert('mousedown');
});

不过我们已经没有必要使用listener functions了,因为还需要多此一举指定this object。我们可以直接使用更好的listener object。

以上内容纯属翻译

【译】addEventListener 第二个参数的更多相关文章

  1. addEventListener调用带参数函数

    当传递参数值时,使用"匿名函数"调用带参数的函数: <body> <button id="btn">click me</butto ...

  2. 关于replace()方法中第二个参数的转义问题

    如果你想通过Javascript代码在网页中呈现 \ 字符,则在JS代码中你必须输入两个反斜杠 \\,否则会报错.比如: var a = "\"; alert(a); //chro ...

  3. 字符串正则替换replace第二个参数是函数的问题

    按照JS高程的说法,如下 replace()方法的第二个参数也可以是一个函数.在只有一个匹配项(即与模式匹配的字符串)的情况下,会向这个函数传递3个参数:模式的匹配项.模式匹配项在字符串中的位置和原始 ...

  4. 学习 Message(5): 关于 TApplicationEvents.OnMessage 的第二个参数 可以屏蔽 TWebBrowser右键菜单:

    http://www.cnblogs.com/del/archive/2008/10/25/1319318.html TApplicationEvents.OnMessage 的第二个参数 Handl ...

  5. parseInt第二个参数详解

    前阵子在stackOverflow上看到两个这样的问题: 为什么parseInt(8,3) == NaN,parseInt(16,3) == 1? 为什么parseInt('dsff66',16) = ...

  6. 关于字符串replace方法第二个参数探究

    网上有关replace的文章很多了,这里主要聊聊它的第二个参数.阅读本文需要对replace方法有一定了解.W3school=>replace 我们要把一段字符串中的某些指定字符替换掉,第一时间 ...

  7. IE6/7/8中parseInt第一个参数为非法八进制字符串且第二个参数不传时返回值为0

    JavaScript中数字有十进制.八进制.十六进制.以"0"开头的是八进制,"0x"或"0X"开头的是十六进制. parseInt用来把字 ...

  8. ***php解析JSON二维数组字符串(json_decode函数第二个参数True和False的区别)

    客户端的请求体中的数据:[{"msg_id": 1, "msg_status": "HAS_READ" }, { "msg_id& ...

  9. Listen第二个参数的意义

    今天主要回顾下listen的第二个参数的意义. 话说现在现在都是用框架写业务代码.真的很少在去关注最基本的socket函数的意义了.该忘得都忘得差不多了.~~~  要慢慢捡起来.  主要是在看redi ...

随机推荐

  1. 栈的讲解 和 栈的生长方向 源代码技巧分析,简直没SEI 啦

    函数的局部变量,都是存放在"栈"里面,栈的英文是:STACK.STACK的大小,我们可以在stm32的启动文件里面设置,以战舰stm32开发板为例,在startup_stm32f1 ...

  2. Spark笔记--使用Maven编译Spark源码(windows)

    1. 官网下载源码 source code,地址: http://spark.apache.org/downloads.html 2. 使用maven编译: 注意在编译之前,需要设置java堆大小以及 ...

  3. hdu Co-prime

    题意:求出在一个区间[A,B]内与N互质的个数 . 思路: 先求出n的质因子,然后求出与N的质因子不互质的个数然后总个数减去就是.用位运算二进制表示那个因子用到过,实现容斥原理.在1到n之间是c倍数的 ...

  4. 改进了UI的界面

    小峤提醒我,千万要记住, 调用JS之前,一定要先加载哟~~~ <!--[if lt IE 9]> <script src="/static/js/jquery1.11.1. ...

  5. treap修订

    #include<cstdio> #include<cmath> #include<algorithm> #include<ctime> #includ ...

  6. Hadoop Compression

    文件压缩主要有两方面的好处:一方面节省文件存储空间:另一方面加速网络数据传输或磁盘读写.当处理大规模的数据时这些效果提升更加明显,因此我们需要仔细斟酌压缩在Hadoop环境下的使用.   目前已经存在 ...

  7. oracle触发器使用总结

    1.说明 1)触发器是一种特殊的存储过程,触发器一般由事件触发并且不能接受参数,存储器由语句块去调用 2)触发器分类: 1.DML触发器: 创建在表上,由DML事件引发 2.instead of触发器 ...

  8. mysql 安装截图

    这里有3个选项, 1.Developer Machine(开发机器),个人用桌面工作站,占用最少的系统资源 2.Server Machine(服务器),MySQL服务器可以同其它应用程序一起运行,例如 ...

  9. iOS开发之自定义输入框(利用UITextField及UITextView)

    drawRect的工作原理:首先苹果是不推荐我们直接使用drawRect进行工作的,直接调用他也是没有任何效果的.苹果要求我们调用UIView类中的setNeedsDisplay方法,则程序会自动调用 ...

  10. label标签的属性

    //label标签的属性 - (void)viewDidLoad { //初始化一个label1标签对象,初始化有很多方法,最原始的就是init,此处用带有frame的方法 UILabel *labe ...