Posts List

从一道面试题谈谈 setTimeout 和 setInterval

最近有看到一道题目,使用 JavaScript,隔一秒打印一个数字,比如第 0 秒打印 0,第 1 秒打印 1 等等,如何去实现? 假如我们尝试使用 setTimeout 去实现: for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, i * 1000); } 这样可以么,执行的结果是什么呢?你可以将这段代码粘贴到 浏览器的 Console 中运行一下。结果是,每隔一秒打印一个 5 ,一共打印 5 次。这是为什么呢,为什么不是打印 0, 1, 2, 3, 4 呢?众所周知,JavaScript 是一种单线程语言,主线程的语句和方法会阻塞定时任务的执行,在 JavaScript 执行引擎之外,存在一个任务队列。当代码中调用 setTimeout 方法时,注册的延时方法会挂在浏览器其他模块处理,等达到触发条件是,该模块再将要执行的方法添加到任务队列中。这个过程是与执行引擎主线程独立,只有在主线程方法全部执行完毕的时候,才会从该模块的任务队列中提取任务来执行。这就是为什么 setTimeout 中函数延迟执行的时间往往大于设置的时间。 因此,对于上述的代码块,每一个 setTimeout 函数都被添加到了任务队列中。然后,这还涉及到了函数作用于的问题。因为当任务队列中的函数执行的时候,其作用域其实是全局作用域。setTimeout 中的打印函数执行的时候就会在全局作用域中寻找变量 i,而此时全局作用域的变量 i 的值已经变成 5 了。这也就是为什么打印的数字都是 5。那么应该如何达到我们一开始预期的效果呢?这里我们就需要考虑到函数执行上下文的问题,可以通过立即执行函数(IIFE)来改变函数作用域。 for (var i = 0; i < 5; i++) { (function(i) { setTimeout(function() { console.

出去就餐并且理解Express.js的基本知识

Going out to eat and understanding the basics of Express.js出去就餐并且理解Express.js的基本知识 原文:Going out to eat and understanding the basics of Express.js 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 如果你曾经去过一个坐下来就餐的餐厅,那么你可以了解 Express 的基础知识。 但是,如果你刚刚开始构建你的第一个 Node.js 后端……你可能并不会很顺利。 是的 - 如果你曾经有过 JavaScript 经验,学习 Node 肯定更容易。 但是,在构建后端时面临的挑战与在前端使用JavaScript 时所面临的挑战完全不同。 当我学习Node时,我选择了困难的方式。 我一遍又一遍地学习电子书,写作教程和视频,直到我终于明白我为什么要做我正在做的事情。 有一个更简单的方法。 我打算用一个餐馆的比喻来解释你的第一个应用程序的四个关键部分。 Express.js 是一个组织你的代码的流行框架,我会为任何初学者推荐它。 稍后我会进一步解释。 下面是我们将会涉及到的四个关键部分: The require statements Middleware Routing App.

JavaScript是如何工作的:引擎,运行时间以及调用栈的概述

JavaScript是如何工作的:引擎,运行时以及调用栈的概述 原文:How JavaScript works: an overview of the engine, the runtime, and the call stack 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT 随着JavaScript变得越来越流行,团队在多个层级都对它进行利用-前端,后端,混合应用,嵌入式设备以及更多。 正如GitHut stats所展示的那样,JavaScript是Github上面最活跃以及总Push次数最多的语言。在其它类别中也不会落后太多。 (获取最新的 GitHub language stats). 如果项目对于JavaScript越来越依赖,这意味着为了构建好的软件开发者必须利用这个JS提供的一切并且对于生态系统的内部有着更深的理解。 因此,尽管每天有很多开发者在使用JavaScript,但并不知道内部到底发生了什么。 概览 几乎每个人都已经听说过V8引擎的概念,并且很多知道JavaScript是单线程的或者它是使用一个回调队列的。 在这篇博文中,我们将会详细讲述所有概念并且解释JavaScript是如何真正运行的。在了解这些细节之后,你将能够写出能够适宜地利用提供的API的更好的,非阻塞的app。 如果对于JvaScript来说还不是很了解,这篇博文将会帮助你理解为什么JavaScript和别的语言相比如此“奇怪”。 如果你是一个有经验的JavaScript开发者,希望这篇文章能够让你对你每天使用的JavaScript Runtime是如何真正工作的。 JavaScript 引擎 最流行的JavaScript引擎的例子之一就是谷歌的V8引擎。比如Chrome以及Node.js内部就是使用V8引擎。下面是一个简单的视图示例: 引擎主要由两个部分组成: 内存堆——这是内存分配发生的地方 回调——这是你代码执行时的栈帧。 Runtime 有很多浏览器中的API几乎都被JavaScript开发者使用过(比如:’setTimeout’)。然而这些API并不是由引擎提供的。 那么,它们是从哪来的呢? 事实证明这有一点复杂。 因此,虽然我们有引擎但实际上是有更多。我们有那些由浏览器提供的Web API,像DOM, AJAX, setTimeout以及更多。

通过利用immutability的能力编写更安全和更整洁的代码

通过利用immutability的能力编写更安全和更整洁的代码 原文:Write safer and cleaner code by leveraging the power of “Immutability” 译者:neal1991 welcome to star my articles-translator , providing you advanced articles translation. Any suggestion, please issue or contact me LICENSE: MIT Immutability是函数式编程的重要基础之一。它允许你能编写更安全以及更整洁的代码。我将会通过一些JavaScript例子来向你展示如何来达到immutability。 根据维基百科: 不可变对象是一个在创建之后不能修改其状态的对象。这正与可变对象相反,它能够在创建之后被修改。在某些情况下,对象被认为是不可变的,即使其内部的某些属性发生改变,但是从外部的角度来看这个对象的状态看起来还是没有发生变化的。 Immutable数组 数组是理解immutability如何工作的很好的起点。让我们一起来看一看。 const arrayA = [1, 2, 3]; arrayA.push(4); const arrayB = arrayA; arrayB.push(5); console.log(arrayA); // [1, 2, 3, 4, 5] console.log(arrayB); // [1, 2, 3, 4, 5] 这个例子将arrayA的引用分配给arrayB,因此这个push方法在这两个变量中都会添加5这个值。我们的代码间接地修改其它的值,这并不是我们想要的。这也违反了immutability的原则。

菜鸟程序员成长史 --记 Github 1000+ contributions

其实一直以来想写一篇文章总结这几年的技术学习,刚好趁着自己的第一次github contribution 达到1000+,写篇文章总结以下。本文篇幅较长,我会分为几个章节来分别阐述。 博客篇 为什么我要把博客放在第一位呢?因为我认为博客是developer学习技术的平台,也是developer分享知识的平台,博客差不多也就相当于是developer的名片。现如今,博客平台形形色色,有老牌的博客园,CSDN,也有现在比较新潮的SegmentFault,掘金,开发者头条,知乎等等。现在博客的形式已经发展得多种多样,现如今新潮的犹如各种各样的专栏等等。当然,在这么多博文中,有很多质量很高的文章,也有很多滥竽充数的垃圾文章。下面,我就就我个人的了解探探我接触的这些博客平台,仅是个人观点。 Github 哈哈。我为什么把Github列到博客篇呢?其实现在Github几乎已经成为了我生命中不可或缺的一部分,每天打开电脑的一件事,基本就是打开Github看看。作为世界上最大的同性交友网站,Github对于程序猿来说绝对是生命中不可或缺的部分。在此,我主要说说Github作为博客方面的内容。 很多人认为Github只不过是一个代码托管的地方,为什么会和博客有关系呢?其实,现在很多人都是在Github的issue里面开博客,因为issue里面方便作者和读者的沟通,而且支持markdown格式,各种功能也是很丰富。对于比较关注的博客,你可以设置watch,这样你就可以了解issue里面的每一次变化,并且还会有相应的邮件通知。在此,给出几个我关注的几个人的Github博客: iCSS:讲解CSS的,有的还是蛮有趣的。 梁少峰的个人博客:讲解vue讲解的很透彻,百度大牛,我觉得有些博文挺值得看,而且值得多看几遍,不过我好像都没看完。他的博文还是需要深度挖掘的。 ccforward/cc:应该是当初关注他的一个知乎爬虫,他的博客内容我没有看太多,但是内容貌似还不错。 underscore-analysis:解析underscroe源代码的,挺不错的,我看过一两篇,值得多读几篇,我自己也该去读了。 Front-end-tutorial:内容很多,我没有过多了解,可以了解一下。 以上就是我了解的一些在Github上面的博客,因为在Github我没有特别关注这方面,所以还不是特别多,当然Github也不是我主要逛博客的地方。 CSDN CSDN是我开启个人技术博客的地方,感兴趣的地方去我的博客逛逛http://blog.csdn.net/neal1991 。我应该是从2015年4月份开始写博客的,博客的内容主要有我研究生期间一开始做的道路识别的一些研究的论文,虽然这个方向没搞下去,这个方向的确很有前景,只能说老板很有眼光,但我没能力,没能搞下去。其它的也包括一些开发过程遇到的坑之内的,面试经历,技术文章翻译。老实说,CSDN现在的确不是一个很好的平台,因为本身它就偏老,在markdown的显示不是很完美,在移动端显示不是很好,还有一点很重要,广告特别多,还是莫名其妙的,看起来很讨厌。其实我一直都想弃坑,奈何就是github国内访问速度不稳定,还有毕竟在这边维护这么久了,所以还是一直维护着。在CSDN上,我基本上都是去写博客,基本不会在它上面浏览技术博客,因为它的浏览界面实在是太杂乱了,没有重点。这可能也是老牌博客的一个缺点,可能一时半会也没办法改过来。下面我主要讲一些我自己的一些比较稍微有用的博客内容: combox系列问题集:当初做winform开发遇到的问题,记得当初最坑爹的是调试combox的时候,visual studio老是崩溃,后来发觉居然是有道翻译的锅,也是醉了。。。 独立成分分析:这个应该是当初一个讨论班里面要做的一个presentation,我把内容整理出来写了这篇博文,阅读量快2000了,好像是我博客里面阅读次数最多的了。 如何查找django安装路径:非常简单的一个问题,但是当初搜遍了,没找到解决方法。 mongoose对象无法新增删除属性:当初在处理mongo遇到的一个问题,是个坑。 第一个chrome extension:第一次写chrome extension,没有想象中的那么复杂,不过还是有一些方法的,貌似360有翻译过谷歌相关的文档。老实说,谷歌真的很良心,现在很多开发者文档都已经是中文的了。 第一个pwa:第一次写progressive web application,其实写pwa和写其它单页面应用没有特别大的区别。pwa也是我非常看到的技术栈,我觉得这个比小程序好上一百倍,只不过现在在国内还是不温不火,但是我觉得很肯能哪一天就星星之火,可以燎原了。 鉴于CSDN平台的种种,我的确越来越不太愿意在这上面写文章。而且我最近的文章一向是以翻译国外技术文章为主,毕竟还是菜,所以只能靠英语吃饭啦。 掘金 老实说,掘金应该是同类这种网站访问量比较大的。的确,里面有不少的精品内容,当然也会参杂很多乱七八糟的东西。其实,现在一般的原创博主都不会只在一个平台发文章,所以基本上你这个平台看得到的,在其它平台也差不多都能看到。只不过我现在基本不看掘金了,因为他们的编辑对新人极度不友善,极度不友好。 众成翻译 360的一个专门翻译技术博客为主的平台,目前应该还是比较小众。360的前端其实还是蛮不错的,尤其是他们的齐舞团队,里面也有很多大牛。这个平台里面的文章一半质量还是比较高的,而且这个平台翻译操作也是蛮舒适的,感兴趣的非常值得试一试。而且他们的群沟通都很流畅,不像掘金那帮人。。。无力吐槽。 知乎 我本身一向是很排斥知乎的。讲心里话,知乎里面百分之八十的人都是在写故事,骗关注的,我也不明白知乎为什么充斥了这么多天天无事可做的人。当然,不可否认的是,知乎里面还是存在百分之二十的精品内容的,这也是让我能够忍受那剩余的百分之八十垃圾的原因。知乎里面那些回答我觉得没有太大的意义,看了也就是笑一笑,一般都是用来刷新三观用的,在此,我仅说一些技术专栏: 饿了么前端:饿了么现在前端的确搞得风生水起,尤其是pwa,感觉他们是这方面搞得国内最为成熟的一家。可能并不是,但他们肯定是分享这方面内容最多的公司。感觉饿了么前端蛮多大牛,不过感觉他们都喜欢混国外圈,黄玄基本都是在medium发文章的。。。 某熊的全栈之路:这个应该是infoq的专栏,这个编辑每个礼拜会发一个国内外最新技术的文章集合,基本是前端为主。内容比较新颖,基本上最时髦的都在这里面。 Think In Vue:意如其名,现在vue在国内真的很火。火到我觉得用react的撕逼应该撕不过vue,vue的作者尤雨溪在知乎也是很活跃的,经常手撕任何喷vue的人,还有看他阮一峰每日一喷很有意思。阮老师也是个很有意思的人,感觉天天都有人喷他,但是阮老师的心态丝毫不受影响,剖有大师风范。不过值得一提的是,阮老师博客的广告位可价值不菲哦~~ 美团点评技术博客:算得上是大厂,值得一看。 知乎乱,前端乱,如何乱中取胜,就是要保持一颗平常心。 开发者头条 不温不火的平台,文章质量还行。我一般发文章这个里面也会发一份。感觉里面的内容偏机器学习以及架构方面,而且这发文章可以攒IO币,可以换书哟。 Medium 国外的一个博客平台,访问需要翻墙。这是国外一个专门写story的地方,样式很好看,应该算得上是国外非常知名的一个博客平台了。当然了,里面的内容也是多姿多彩的,同时里面的技术文章质量也有很多很高的文章。现在国内技术圈翻译的大多数文章基本都是来自于这个平台。 Quora 国外一个和知乎一样的网站。不过知乎由于国内人数优势,火爆异常。Quora则是不温不火,而且上面还有不少华人。我关注过一段时间,但貌似都没什么特别的内容。 以上基本就是我所有的对于一些博客平台的了解,可能不包含所有,但基本都是我自己的个人的亲身经历。可能部分言辞颇为激烈,但也都是我的肺腑之言。 微信公众号 微信公众号作为一种特殊的平台,现在也成为一种传播渠道,有点类似于报看订阅的形式。但这不一定是一种非常有效的传播方式,感觉深度还是不够的,我比较喜欢在电脑上看文章,因为在手机上看文章难以持续地专注于一篇有内容的文章,一般就只能浅尝则止。所以我一般都是把链接转到我的微信PC版,然后再用浏览器打开,下面介绍一些我关注的一些技术类公众号: 前端之巅:我之前提过的,应该是infoQ的平台,其实和之前的知乎专栏应该是重叠的。 奇舞周刊:360奇舞团队,前面也介绍过了,国内的知名的前端团队,会有一些比较有价值的文章。 前端早读课:每天早上都会发送推文,但是文章质量嘛,参差不齐,基本上都是别人的文章。 FEX:百度FEX团队,收集最新技术文章,但是排版比较差,比较原始。 神秘的程序员们:里面会有一些脑洞大开的漫画,而且会有程序猿和产品经理以及架构师撕逼的故事,很有趣。 Github 为什么我要把Github单独作为一章节来讲呢?因为它实在太重要了!!!以至于我除了它,根本不想去尝试其它类似的平台。关于Github可以讲的东西太多太多,它带给程序员的则是无穷的魅力。在此,我也仅就几个方面谈谈我的个人理解: star篇 Star是衡量一个开源项目是否受欢迎的重要标准之一(当然也有很多是骗star的)。其实,现在很多人看到一个项目都会去star,但是后续是否会关注,当然也就不一定了。曾经有一段时间,我对star深深着迷(其实现在还是很着迷),我每天都希望有人能给我的项目star,看着别人上千的star我都会超级羡慕。但我其实也能够深深体会到做一个开源项目的不容易,开发者有一个idea往往很简单,但是要去实现它,推广它,完善它。这真的很难很难,而且还会有各种各样形形色色的人问你各种问题,给你提出各种要求,这些都是很痛苦的。但是我依然希望自己有一天还是能够成为一名出色的开源项目的开发者。下面我就挑一些我star的项目来讲一讲: prepack:前几天,前端圈最火的技术,编译优化,facebook总是走在潮流之端。

你可能不知道谷歌浏览器开发工具的其他用处

原文链接 原文链接似乎翻墙才可以访问 译者:neal github: https://github.com/neal1991 你可能不知道谷歌浏览器开发工具的其他用处 Chrome内嵌开发者工具。它具有丰富的功能特色,比如元素,网络以及安全。今天,我们将完全关注javascript的console. 当我才开始编程的时候,我只是将console用作纪录服务器的响应。但是后来经过一些教学的帮助,我开始发现console可以做的更多。 在这我们讲一些你可以用console做更多有用的事情。如果你是用chrome浏览这篇文章,你可以马上就试试效果。 选择节点元素 如果你熟悉jquery的话,你应该知道$(‘.class’)和$(‘#id’)事多的么的重要。你可以根据id或者类名选择相应的元素。 同样你可以在console使用同样的方式来访问元素。$(‘tagName’) $(‘.class’) $(‘#id’)和document.querySelector(“)是等同的。这个将返回文档中第一个匹配这个选择器的元素。 你可以用$$(‘tagName’)来访问,注意这边的两个美元符号可以访问所有符合这个选择器的元素。这些元素会组成一个数组 2.将你的浏览器转化成一个编辑器 你是否想过可以直接在浏览器中直接编辑?答案是肯定的,你可以将你的浏览器转化成一个文本编辑工具。你可以在dom元素中任意添加或者删除文本。 你不需要检测html中的元素。取而代之,你只要去console里面输入以下: document.body.contentEditable = true 3.寻找dom中元素绑定的事件 当调试的时候你可能希望知道dom元素中绑定的事件。console工具能使你很轻松就找到这些事件。getEventListeners($(‘selector’))将会返回一个数组包含所有事件的对象。你可以展开这个对象看到所有的事件: 如果希望找到某个特定事件的监听,你可以这么做: getEventListeners($(‘selector’)).eventName[0].listener 这将展示所有和这个事件相关的监听。比如: getEventListeners($(‘.firstName’)).click[0].listener 4.监听事件 如果你想监听特定元素绑定的事件的时候,你也可以在console里面这么做。你可以使用以下的这些命名: monitorEvents($(‘selector’))将会监听符合这个选择器的元素的所有事件,并且将会显示这些事件当事件被触发的时候。 monitorEvents($(‘selector’),‘eventName’)将会监听符合这个选择器的特定事件。你可以将事件的名称作为一个参数传入到这个函数中。 monitorEvents($(‘selector’),[‘eventName1’,‘eventName2’….])将会监听符合这个选择器的事件。 unmonitorEvents($(‘selector’))这个会停止监听并且在console里面显示出所有的事件。 5.找到语句块执行的时间 console里面有一个很重要的函数叫做console.time(‘labelTime’)能够启动一个计时器。另外又一个函数叫做console.timeEnd(‘labelName’)能够结束相应的计时器。 比如我们想看到一个循环的执行时间,我们可以做如下处理: console.time('myTime'); //Starts the timer with label - myTime for(var i=0; i < 100000; i++){ 2+4+5; } console.timeEnd('mytime'); //Ends the timer with Label - myTime //Output - myTime:12345.00 ms 6.

javascript中的对象字面量为啥这么酷

原文链接 : Why object literals in JavaScript are cool 原文作者 : Dmitri Pavlutin 译者 : neal1991 个人主页:http://neal1991.pythonanywhere.com 在ECMAScript 2015之前,Javascript中的对象字面量(也称为对象初始化器)是非常基础的。能够定义两种类型的属性: 成对出现的名称以及相应的值{ name1: value1 } Getters { get name(){..} } 以及setters { set name(val){..} } 可以用于动态的属性值。 遗憾的是,这个对象字面量可能会出现下面这样的情况: var myObject = { myString: 'value 1', get myNumber() { return this._myNumber; }, set myNumber(value) { this._myNumber = Number(value); } }; myObject.myString; // => 'value 1' myObject.

javascript中无法将string转化为json对象

在一次项目之中,我要对请求的相应做一些处理,得到的响应差不多是这中格式‘{total:1,result:[{“age”:1}]}‘.可以看到我拿到的这个相应和JSON的格式是非常相似的,一开始我认为只要用JSON.parse进行转化,但是这始终会报错,无法进行转化。后来我用了个笨办法把前面的东西都去掉了拿到’[{“age”:1}]‘进行转化。 后来我又找一找这个问题的原因,原来是我这个字符串中的key没有用双引号进行包裹,这并不是一个合法的JSON格式,它可以被人为是一个Javascript对象,但还不是一个合法的JSON,所以无法解析。JSON对象是由对象成员组成,而成员是由key-value键值组成。key值是一个字符串,字符串由unicode字符组成,用双引号包围,用反斜杠转义。可以是单个字符。 但是在现实应用中,很少有人知道JSON里的key需要双引号来包裹的,浏览器里面的属性都是没有双引号的,从而返回的结果无法解析。 知道问题的原因,就自然而然有相应的解决办法了。第一个办法就是本办法,手工加上双引号,也就是用正则表达式匹配;另外一个方法就是用eval直接执行, var obj = eval('('+str')') 不过你需要了解这个str里面到底有什么,这样才能防止一些恶意程序,避免带来安全问题。

判断数组中元素多个属性是否重复

js中判断数组元素的重复的方法有很多,可以用hash的方法或者排序之后再进行比较,但是我们这里说的case是这样的。假设我有一个数组[{name:'neal',age:'18'},{name:'neal',age:'18'},{name:'jane',age:'20'}].假如数组中元素name和age这两个属性都相同我们则给这个元素加一个属性flag设置为true,否则设置为false.其实就是判断数组中元素中多个属性是否重复的问题了。 这种问题有一个比较死的方法就是拿两个循环来做处理 for (var i = 0,len = collection.length;i < len;i++) { var count = 0; for (var j = 0;j < len;j++) { if (collection[i].name === collection[j].name && collection[i].age === collection[j].age) { count = count + 1; } } if (count > 1) { collection[i].flag = true; } else { collection[i].flag = false; } } return collection; }; 另外一种方法是使用underscore.js里面的方法了,不过由于underscore一次只能按照一个属性来groupBy,所以也需要多次嵌套 collection = _.groupBy(collection,'name'); for (var i in collection) { if (collection[i].

js的事件流理解

面试问到js的事件流,当时说的不是很清楚,现在觉得有必要把这个弄清楚。 事件捕获和事件冒泡 事件流描述的是从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。 事件流主要分为两种,即事件捕获和事件冒泡,这二者接受事件处理的顺序不同。假设下面的代码: <body> <div id="outer"> <div id="inner"></div> </div> </body> 这两个事件流分别的是IE公司和netspace公司提出来的,冒泡事件流支持的浏览器更多。 冒泡事件流中,事件的传递顺序是从子元素向父元素传递。假设我们给div绑定一个click事件。那么在冒泡事件流中,事件的传递顺序是:inner->outer->body。然而捕获事件流的顺序则截然想法:body->outer->innner。 DOM事件流 DOM2级事件规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。还是以上面的代码为例,单击inner则会按照下面的顺序触发事件:document->html->body->outer->ineer->outer->body->html->document。在DOM事件流中,实际的目标inner在捕获阶段不会接受到事件。这意味着在捕获阶段,事件到outer就停止了,下一个阶段是“处于目标”阶段,于是事件在inner 上发生,并在事件处理中呗看成是冒泡阶段的一部分。然后,冒泡阶段发生,事件又传播回文档。 事件处理程序 响应某个时间的函数叫做事件处理程序。DOM0级的事件处理程序很简单,onclick就是常用的DOM0级事件处理函数,只会在冒泡阶段被处理。 而DOM2级事件定义了两个方法用于处理置顶和删除事件处理程序的操作addEventListener()和removeEventListener(),所有DOM节点都包含这两个方法,并且它们都接受3个参数:要处理的事件名,作为事件处理的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序,反之则是在事件冒泡阶段处理程序。DOM2级方法添加事件处理程序的好处是可以添加多个事件处理程序,会按照添加顺序被处理(无论是捕获还是冒泡)。 而IE不同的它有自己的方法attachEvent()和detachEvent,这两个接受相同的两个参数:事件处理程序名称和事件处理程序函数。 跨浏览器的事件处理程序 var EventUtil = { addHandler: function(element,type,handler) { if (element.addEventListener) { element.addEventListener(type,handler,false); } else if (element.attachEvent) { element.attachEvent('on'+type,handler); } else { element['on'+type] = handler; } }, removeHandler: function(element,type,handler) { if (element.removeEventListener) { element.removeEventListener(type,handler,false); } else(element.detachEvent) { element.detachEvent('on' +type,handler); } else { element['on'+type] = null; } } }