作者:kun10
发布时间:March 30, 2010
分类:JavaScript
----------以上是ppk在yahoo演说js events的视频-------------
----以下是本人利用自己的双耳听到的,用自己的脑袋理解和翻译出来的,可以作为参考,以下的“我” 表示PPK,如若误解,深表荣幸----
今天我会说一些关于JavaScript事件的事情,我很希望自己能启发大家一些什么,不过大伙都是高手,不管怎么,我还是要说说JavaScript事件。 大约一年前我打算对JavaScript的事件做一些深入的研究,并且我做了一张兼容性的表,大家可以通过下面这里来访问
http://quirksmode.org/dom/events
那么今天我会和大家谈论4件事情:
首先 会是key事件(按键事件),因为在这里存在很多的困惑,很多是关于他们如何工作的困惑。
然后 我会谈谈change事件,他是我很喜欢的一个事件,不幸的是,它的工作情况有些乱。
第三 ,我会谈谈委派focus事件,当然可能你已经知道了。委派的事件通常只会触发在鼠标或者是键盘事件上,但是我找到了一种办法使它也能够使用在focus上面。
最后 我会说说手机上面的事件,相当诡异的东西。。。
那么首先就来看看键盘事件吧,键盘事件有三个:keydown,keypress和keyup。大多数的人都认为自己很清楚他们在会何时触发,而我在这里要告诉你,其实未必就如你所想的那样。 我们先来看看定义,、 keydown事件:当用户按下键盘上面的一个键时会触发,用户一直按着这个键他就会持续触发。 keypress事件:有一点点的不同,用户按着一个字符键(原文是character key)才触发,就是说用户按了一个能在屏幕上输出字符的按键keypress事件才会触发,比如我们往一个textarea里面输入字符。 keyup事件:很简单,当我们释放一个按键时候会触发。 举一个例子,这样你能更明白些 比方说我按下了一个字母“o”键或是字母“i”键,那么keydown和keypress就都会触发,而当我按下的是一个特殊的按键比如是shift键,那么kyedown会触发,而keypress不会。 keydown和keypress的这种区别最初是由微软提出的,所有的ie都支持这种区分方式,一年前(08年吧)推出的safari3.1也适用这样的方式,不过这只是说明了keydown和keypress存在方式的不同。相比较,firefox和opera会同时触发多个事件,因为此时事件既是一个keydown事件又是一个keypress事件,所以我们应该会同时触发多个事件。这样很好,但是这样却无法解释为什么要同时存在两种事件、而不是一种(keydown)。所以其实我还是很喜欢微软的这种区分的。 好吧,我们再来重温一次概念,keydown会在任何键按下时触发,keypress只是在字符键按下时触发,以上是在ie和safari下的情况,另外,我目前没有google chrome,不过他和safari很相近,所以这个应该也适用于chrome浏览器。
OK,让我们来看一些实际问题,通常我们都会写一段脚本来检测用户按过哪个按钮,然后利用这样的结果做一些有趣的交互应用。
键盘事件拥有两个属性,keyCode和CharCode,他们之间有一些不一样之处。keyCode表示用户按下键的实际的编码,而charCode是指用户按下字符的编码。 因此,当我按下“a键”,我会得到keyCode 65和字母a的charCode 97(注意是小写的字母哦),而当我按下shift键,我会得到keyCode 16,而我不会得到任何的charCode,因为按shift并没输入任何的字符。就这样,很简单吧~~~ 我们现在得到两个属性了,两个属性各自包含了各种的信息,这真是好事~~~
但是接下来我们又遇到问题了,很复杂,无法解释但它就是这样的问题。keyCode属性。在keyDown事件里面,事件包含了keyCode – 用户按下的按键的物理编码。在Onkeypress里,keyCode包含了字符编码,即表示字符的ASCII码。这样的形式适用于所有的浏览器 – 除了火狐 ,它在onkeypress的时候keyCode返回数字0, 别问我为什么,它就这样。然后,火狐在Onkeydown中charCode返回数字0,在 onkeypress里,由charCode返回字符ASCII编码。而这个,只会在Firefox和Safari工作,因为他们是唯一支持charCode的浏览器。(这一段翻译感谢信息学院的AN同学的纠正)
让我们更进一步看点更实际的东西,如果你想获取用户实际敲击的按钮,用keyDown事件来获取事件对象,并获取keyCode ,这在所有浏览器都行的通。另一方面,如果你想获取用户输入的字符,那么就使用keypress来获取,然后获取charCode(火狐和safari)或是keyCode(其他浏览器) 。
然后,我想有时候你也会有阻止某个按钮默认行为的想法,很常见的是方向键 设想你有一个适合于键盘的拖拽菜单,你希望用户用方向键来实现一个拖拽的操作,因此你就要取消方向键的默认行为(使页面向上或是向下滚动),那么一般来说你就会在keyDown事件里面做这件事,因为如我所说的那样----keyDown会在一个按钮被按下时候触发,而keyPress只是在字符键按下时触发,但是很不幸,这样子在opera行不通(当然我得承认我没有测试最新版的opera,也许现在已经修复了这个问题?待测试)。因此,我今天不会讨论在opera下面阻止方向键的方法,很坦诚的说,我还没有一个答案。
这就是键盘事件的一些总结,不会很麻烦吧?我说了几种键盘事件,但是你得注意keydown和keypress的差别。
好了好了,来说说change事件吧。照理论说,change事件应该是很好的一个事件,因为他应该是在表单有变化的时候触发。比如,你想在表单提交时检测一些用户操作表单的事情,比如是检测和验证用户在各个域的输入。当然也有很多时候我们会动态创建一个表单或是表单域或是选框--这样的表单会和用户之间产生很复杂的交互,这时候我们就要知道用户什么时候对表单作了修改,从理论上说,change事件是最合适不过的了。
但是通常,我们总是会被迫去使用focus和blur事件或者是click事件去做检测表单变化的事,而不是用change事件。这是因为change事件不总是能很正常的运行着。我们分三种情况来讨论 1、文本框的变化事件(text field) 2、选择框的变化事件(select box) 3、复选框和单选框的变化事件
从文本框开始说吧,假设用户把焦点移动到了文本框上面(或用鼠标或用键盘的方式),之后又移去了焦点,比如说他进入了下一个文本框的输入。在这样的情况下,change事件不触发,因为没有什么东西改变了---注意,第一个文本框的值并没有改变。但是我们对上述事情稍稍做一些变化,如果我们说,用户点击了文本框,并输入了一些文本,然后再撤去焦点,这就触发了change事件,很好,他在所有浏览器中都如此工作。
然而,当我们使用selectbox的时候问题就来了,选择框事件是你可以想到的最古老的浏览器事件,我想大约在95、96年我们在浏览器中就有了selectbox了,他可能列出了漂亮的链接,并节省了页面的空间。我们已经使用选择框有很长一段时间了,你也可以用鼠标去做一个选择。首先你点击选择框,它便列出了选项,当你再次单击里面的一个选项时,就触发了change事件。因为浏览器知道:“ok,用户已经改变了选择框里面的值了”。这也是用于所有的浏览器。
但是,用户还可以用键盘来操作改变选择框(select)的值,这就为我们使用change事件带来了麻烦。首先用户会把焦点移动到selectBox上面,然后利用方向键来选择他需要的选项。这还不是什么问题,但是这种情况,在IE和opera下面,每当用户按一次方向键(切换选项),change事件就会触发一次。这明显是很大的一个问题,如果一个选项表有20个选项,那么用户从第一个选项移到最后一个就会触发19次change事件,这可以说是ie和opera很严重的一个bug。 而在firefox和safari里面,他们所做的工作就是,允许用户在选项之间用上下键来选择,然后会在用户blur这个选择框的时候触发change事件,通俗的说,你告诉浏览器,我已经选择好了,浏览器你可以用change事件看看我是不是做了改变----像firefox和safari这样的工作方式很好很正确。不过,在IE下面做一些类似于选框导航的工作,当用户用键盘来操作,使用change事件就很容易产生问题。这就是我们对于change事件的首个大问题。
不幸的事继续发生,当我们在复选和单选框上面使用change事件,情况会更糟,我以一个复选框为例,基本上他和单选的工作方式一样。当用户点击了复选框(我不仅仅指用鼠标点选) ,一个点选操作可以通过鼠标或是键盘来达到。总之,这样的一个点击使得复选框的值发生了变化---true or false。按常理这时候change就发生了,因为用户确确实实的改变了东西,这样的一件事也的的确确会在firefox,safari,opera里面发生,但是IE不会 。 IE到底怎么了?你点击了复选框而什么也没有发生。接下来呢,你用鼠标或是键盘把焦点移出这个复选框移到别的复选框上面,原来的这个复选框的blur事件就触发了,同时change事件随之触发。这样的情况对于一些整理表格的操作实现来说是很糟糕的,比如通过复选框来开启表单的隐藏选项,在IE下面你只能在blur一个复选框的时候开启隐藏选项,这样对于用户来说是很困惑的(因为会给用户带来一种滞后的感觉)。这也是IE下面一个很严重的bug。
你可以看到我在ppt上面给W3C也划了一个叉号,因为据我所知w3c的事件标准只是规定了blur,根据标准,一个change事件应该在一个表单域改变并被移去焦点时发生。现在我们可以总结一下,change在文本域里面工作的很不错,当我们用键盘操作select框是它很有意义,而对于单选框和复选框或者是你用鼠标操作select框change事件使用的意义就不太大。(我作为翻译认为这里ppk出现了口误,把鼠标和键盘操作selectbox的情况说反了,大家要看了欢迎纠正,另外ppk貌似也没有提到用鼠标scroll方式操作select框的值的方式)
这就是我们目前遇到的一个问题,而我目前还没有找到一个很好的解决方式。幸运的是,我们可以用click事件或是focus事件或是blur事件做一些弥补,虽然这不会花费太多的精力,但是我还是期望change事件能变得真正的实用。这样我们可以比较统一的用一个事件去侦测一个表单里面的变化并做一些有意思的事。目前这还是我们能期待的。
进入我们今天的第三个话题吧,事件委派(event delegation),我非常确信你(指yahoo的同学们)应该已经知道什么是事件委派,不过其他的人却不知道,我简单的介绍一下。基本来说,事件委派是减少定义事件处理的一种方式,我们用下拉菜单为例。用传统的方式,我们可能要对这个下拉菜单添加很多的事件处理函数,当你的鼠标停留在父级菜单上面,1级子菜单弹出,我们在移动鼠标到1级菜单上面,二级菜单又会出来。而当我们使用事件委派时情况就有所不同,事件委派利用了事件的冒泡,当用户移动鼠标到一个链接(link)上面,触发了链接的mouseover事件,同时通过冒泡mouseover事件冒泡到了链接的上一级元素,直至冒泡到整个文档上面,这个过程会触发链接(link)上级任何一个含有mouseover事件的元素的mouseover事件,比如会冒泡到li和ul的mouseover事件,那我们为什么不把处理事件的函数放在链接的上层呢?这样可以节省众多链接的事件处理函数的绑定。
曾经我的一个客户抱怨他的站点有点慢,尤其是在IE下面,于是我看了源代码,我发现他的下拉菜单有六七十甚至更多的链接,每一个链接绑定了自己的mouseover、mousedown、mouseout事件,这就使得页面变得缓慢了。 因为每一个浏览器都会为单独的事件处理开辟一个单独的内存,更何况是IE(拥有内存泄露的美名)。于是我告诉我的客户事件委派,然后。。。。(网页快起来了)
那么首先让我们来建立一个下拉菜单
<ul>
<li><a href=”#”>Multimedialize</a>
<ul>
<li><a href=”#”>Sound</a></li>
<li><a href=”#”>Java applets</a></li>
</ul></li>
<li><a href=”#”>Ajaxify</a>
<ul>
<li><a href=”#”>Web 2.0</a></li>
<li><a href=”#”>Web 3.0</a></li>
<li><a href=”#”>Web 4.0b</a></li>
</ul></li>
</ul>
我们首先把我们的mouseover和mouseout事件处理函数绑定到ul上面,这在所有浏览器中都行的通。
var dropdown = {
init: function (dropdown) {
dropdown.onmouseover = this.mouseOver;
dropdown.onmouseout = this.mouseOut;
}
}
不过如果一个用户不用鼠标,而是想用键盘操作打开这个下拉菜单,我们又该怎么做呢?这个问题有个我们带来了一个重要的主题,设备的独立性(让网页支持多种设备的操作)。这也是我想向大家解说的,我们做的东西要兼容各种设备。 基本的规则是,所有带有“mouse”在名字里面的事件,只是在你真正使用鼠标的时候工作。 听起来很简单吧,不过这总会被很多人忽视。因此,我们需要用户使用键盘的时候能告诉我们用户何时是鼠标移入何时又是鼠标移出的事件,那么目前看最合适不过的就是focus和blur事件。因此,如果事件通过鼠标mouseover或是键盘focus冒泡到上面的元素,冒泡到达ul时我们就执行目标函数展开菜单。当鼠标mouseout或者是键盘blur冒泡上去时,我们就执行关闭菜单的函数。但是问题在于,这不可行,因为focus和blur事件不会冒泡。
这就带给我们另一个问题,什么事件支持冒泡?什么事件又不支持冒泡? 我们先把事件分为两类:一类是设备事件(鼠标或是键盘按键事件),另一类是界面事件。
鼠标和键盘事件是在使用输入设备的时候触发的,我还在做一个更好的定义,不过基本是这个意思,基本上用户所作的就是点击鼠标按键、点击键盘按键、移动鼠标或其他的一些事,总之是和一个具体的外接设备相关的,这些事件的例子如,mouseout,mouseover,click,keydown,keypress,顺便说一声click是唯一既迟滞鼠标触发又支持键盘触发的事件:你用鼠标点击会触发click,用键盘tab移动焦点到目标然后回车也会触发click。click是很少的能够工作于多种设备下的事件。因此,一个click事件是很安全的。其他的一些设备事件总是只支持某一个设备,最后要说的,就是以上提及的这些事件支持冒泡,直到document级。
界面事件,在一个常规事件触发时执行,而不关注它是如何被触发的(翻译的有点生涩,欢迎提意见) 界面事件的一个比较好的例子是,表单的submit事件,当一个表单被提交他就会触发,而表单submit事件并不关心用户是用什么方式来提交表单的,可以使用户用鼠标点击了提交按钮提交表单,可以是用户输入文本按了回车提交表单,只要是提交了表单,submit事件就会触发。这类事件还有很多,又如onload,onupload,change,focus,blur,对了这里有我们苦苦追寻的focus和blur事件。因为我们希望我们的下拉菜单能够兼容多种设备。
大体来说,界面事件不支持冒泡, 对我们来说这真是一个不好的消息,因为如果我们想让键盘用户也能用我们的下拉菜单,我们就要用到focus和blur。但是focus和blur并不能冒泡上ul元素,我们就只能老老实实的把事件处理绑定在每一个li上面了。当然还有一个不算好消息的好消息,我们可以在事件捕获中得到focus和blur,事件捕获的工作是和事件冒泡相反的,但是它在IE下不被支持。。。不过我们一会儿会讨论IE。
我们说事件冒泡,我们点击了a元素,a的click执行,然后事件冒泡到了li,之后是ul,之后是document。事件捕获则是,在我们点击了a之后,事件从document一级级的下来,经过ul、li、然后才到达a并终止捕获。你会觉得冒泡和捕获这两个东西用哪个都差不多,不过当我向dean Edwards问了这个问题后,他说:“不不不,你应该在大多数情况下去使用事件捕获”。
当你要捕获一个focus事件,被绑定在目标元素的祖先元素上的事件就会被执行,这个可以在所有浏览器下使用,当然除了IE,因为它不支持事件捕获。因此基本来说,如果我们把焦点移上a元素上并同时使用事件冒泡,只有a链接的unfocus事件会被触发。但是我们反过来使用事件捕获,那么这个unfocus事件就会顺着document->ul->li的顺序执行下去。
为什么事件捕获和事件冒泡会有差别?我也说不出。这只是我测试出来的,我开始在opera里面测试,开始我以为他只是opera特有的,但是我在firefox下面也测试,哦?火狐也有这个特性,然后又测试了safari,呵呵,safari也有同样的表现,最后,我发现它几乎是一个跨浏览器的特性。这样让我觉得事件冒泡和事件捕获具有同样的作用,因为在我之前的感觉中,事件是否能被捕获并不最重要,但是能否冒泡就不一样了(能否被冒泡意义重大)。不管怎么说,目前的这种状况(应该是说冒泡和捕获的混乱的支持情况)意义不是很大,但他确实能解决很实际的问题,因为现在我们可以对focus和blur进行事件委派了。
我们要做的很简单,我们给根元素添加上addEventListener,并给这个函数的最后一个参数设为true,使其工作在捕获阶段。
var dropdown = {
init: function (dropdown) {
dropdown.onmouseover = this.mouseOver;
dropdown.onmouseout = this.mouseOut;
dropdown.addEventListener('focus',this.mouseOver,true);
dropdown.addEventListener('blur',this.mouseOut,true);
}
}
这样,一旦下拉菜单有focus事件发生,那么ul上面的事件捕获就会触发,绑定在上面的this.mouseOver函数就会被执行。别问why,他就是这样工作的。
当然,因为IE不支持事件捕获,我们还要添加一点点东西,做一些修改,IE虽不支持事件捕获但是他有自己的解决方案,这是IE所特有的。
var dropdown = {
init: function (dropdown) {
dropdown.onmouseover = this.mouseOver;
dropdown.onmouseout = this.mouseOut;
if (dropdown.addEventListener) {
dropdown.addEventListener('focus',this.mouseOver,true);
dropdown.addEventListener('blur',this.mouseOut,true);
}
dropdown.onfocusin = this.mouseOver;
dropdown.onfocusout = this.mouseOut;
}
IE带有两个类似于focus和blur的事件,但唯一的区别就在于他们支持冒泡,他们是focusin和focusout,我们给原来的代码添加上两行,dropdown.onfocusin, and dropdown.onfocusout。这样我们的事件委派就工作在了所有的浏览器中。
顺便说一声,YUI团队 已经把这种特性纳入了他们的库 之中,不过当你使用其他的一些库的时候,这样的技巧你也可以记一下以便必要时候用得到,这样的技巧很好,但是IE并不是总能提供类似于focusin和focusout这样的东西,所以那种时候你可能会抓狂。 ---------------------------------------------------------- 休息线 ---------------------------------------------------------- ......先翻译这三段吧,第四部分PPK讲的是手机端的js事件,看完之后感觉手机端的事件是相当的混乱,目前本人对此研究也不深入,待更明白一点的时候再做翻译吧。。。,上面翻译的也不是很到位,各位千万要提出意见,这里可以给出ppk的原文 ,欢迎对照指点。
另附:PPK的一些关于事件的文章
作者:kun10
发布时间:March 21, 2010
分类:记生活
每天都会跑到楼下的早饭摊买早饭,我觉得自己是一个有点自作多情的家伙,久而久之了也就觉得自己和早点摊的小伙子熟悉了,因为每天早上我都会差不多在同一个时间,买同一种早餐,花同样的钱说同样的话。 不过,早点小伙的表现倒是让我很诧异: 记得最初第一次去买早点的时候,买完了米饭团,他问我,要不要豆浆,我心想为了健康的生活,买上吧,回来喝了觉得还不错。 第二次,我又去买,同样是买了米饭团,可是小伙子却没有问我要不要豆浆,我自己又一想,算了,今儿就省点钱吧。于是,第二回小伙子的豆浆就没有卖出去。 又一次,我实在是很想喝豆浆的一次,买完了米饭,主动的告诉早饭小伙,我要一袋豆浆,小伙子才貌似反应过来,并和我说:"豆浆凉的,你还要吗?" 我说:"要了。"
--------------时间线,由于学校有事要处理,回校一周---------------
~~~~沙尘飘过~~~~~
-------------------坐火车重回杭州---------------------
早饭还得解决啊。于是又去买米饭团了,又见卖早点的小伙子,这次,我还是没有主动要豆浆,他又问了我要不要豆浆,结果那天我买了豆浆。 今天我又去买,结果,小伙子没有问我:"要豆浆么?",最终我回来喝了咖啡 。
-------------至此,我觉得至少可以说明两件事------------
1、如果早饭小伙是机器人的话,我写的或许是一篇流水账 2、如果早饭小伙不是机器人,他应该是没有做好“用户分析”,不过对于一个早点小伙子来说,这样的要求是不是有点强求了呢? 不过从一个人做事情的角度来说,必要的分析和思考是必须的,从小伙的角度来说,他应该意识到,卖完饭团后多问一句“要豆浆么?”是会带来多余的收益的,至少我是这么想的。 从服务行业来说,我们应该表现的更为热情和主动,有时候客户更为注重的是我们的态度。
作者:kun10
发布时间:March 14, 2010
分类:牛人之整理
JavaScript 可算是世界上最流行的编程语言,它曾被 Web 开发设计师贴上噩梦的标签,虽然真正的噩梦其实是 DOM API,这个被大量的开发与设计师随手拈来增强他们的 Web 前端的脚本语言,如今越来越被重视,虽则如此,JavaScript 仍然拥有很多让人费解的东西。
1. 它以 Java 命名,但并不是 Java 它最初叫 Mocha, 接着改名为 LiveScript,最后才确定命名为 JavaScript,根据历史记录,Java 的命名与 Netscape 和 Sun 之间的合作有关,作为交换条件,Netscape 在他们备受欢迎的浏览器中创建了 Java 运行时。值得一提的是,这个名字的出台几近一个玩笑,要知道,LiveScript 和 Java 在客户端脚本方面存在敌对关系。
不管怎么说,人们后来不得不一再澄清的一件事就是,JavaScript 和 Java 毫无关系。
2. Null 是个对象? 看看这段代码,它返回的是 object。
console.log(typeof null); // object
这实在令人费解,假如 null 表示空值,它怎么可以是对象?简单说,它是 JavaScript 最初版本的错误,这个错误甚至被微软的 JScript 直接借用。
3. NaN !== NaN NaN,表示一个非数字的值,然而问题是,NaN不等于任何东西,甚至不等于它自己。
console.log(NaN === NaN); // false
这显然不对,事实上,如果要判断一个值确实是 NaN,你需要用 isNaN() 函数。
4. 全局变量 对全局变量的依赖一直被视为 JavaScript 最坏的部分(ECMA 的 JavaScript 5 已经去掉了全局变量,请参阅 ECMA 推出 JavaScript 5 - 译者注)。对简单的页面,这无所谓,但复杂的页面,如果包含大量 JavaScript 脚本,你很难知道某个全局变量是在哪里声明的,如果几个全局变量不小心重名,就会引发错误。
“The problem with JavaScript isn’t just that it allows them (global variables), it requires them.” – Crockford 5. 那些统统被探测为 Mozilla User-Agent 的浏览器 必须承认,事实上,这不是 JavaScript 的错,是各个浏览器有意为之。比如,以下是用 JavaScript 探测 Safari 时得到的结果:
console.log(navigator.userAgent);
// Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10
是否注意到其中的第一个单词 Mozilla/5.0,为什么 Safari 会被探测为 Mozilla,尽管 Safari 后来已经纠正这一问题,但仍然不能解释为什么它们要这样误导开发者。事实上,你会发现,绝大多数浏览器把他们的 User Agent 设置为 Mozilla,答案要回到10年前,这更多是一种策略。
User Agent 是一段用来标识当前浏览器身份的字符串,世界上第一个浏览器 Mosaic, 曾这样标志自己:
Mosaic/0.9 // browser name / version number
这很合理,因此当 Netscape 出来的时候,它保留了 Mosaic 这个传统,还在后面添加了一个加密方式部分。
Mozilla/2.02 [en] (Win95; I) // browser name / version / encryption
到目前为止,一切安好,直到 IE3 发布,当 IE3 发布的时候,Netscape 正如日中天,那时,很多服务器和程序已经部署了客户端探测机制,以便认出 Netscape,虽然现在看来,这很值得争议,但当时并没什么。当 IE 初次推出它们的 User Agent 标志的时候,是这个样子:
MSIE/3.0 (Win95; U)
这让 IE 很被动,因为 Netscape 已经能被很多服务器识别,因此,开发者们干脆希望 IE 被误认为 Mozilla,然后,再单独加一个 IE 的标签。
Mozilla/2.0 (compatible; MSIE 3.0; Windows 95)
如今,几乎所有浏览器都步 IE 后尘,将自己标识为 Mozilla,这大概是一种连锁反应。
6. 不一致的函数范围 参看以下代码:
// Create a function that will call a function with the name equal to parameter fn.
function foo(fn) {
if (typeof fn === "function") {
fn();
}
}
// Create an object with a property and a method.
var bar = {
barbar : "Hello, World!",
method : function() {
alert(this.barbar);
}
};
bar.method(); // Alerts Hello, World!
foo(bar.method); // If we call the foo function add pass the "bar.method" method, it somehow alerts "undefined."
foo(function() { bar.method(); }); // alerts Hello, World, after
foo(bar.method) 返回结果不同原因是,method 函数是被当作 windows 对象,而不是 bar 下的对象调用的。要解决这个问题,我们必须从传递的匿名函数中调用 bar.method() 。
7. 位操作符 JavaScript 和 Java 有不少共同之处,如位操作。
- and | - or ^ - xor ~ - not - signed right shift ??? - unsigned right shift - left shift
看看第一个 操作符,使用 应该更有效,因为 JavaScript 和 Java 不一样,JavaScript 没有整数,需要来回转换,因此,转换操作花的时间更长。
8. 太多的空值类型 诸如 null, false, undefined 一类的值几乎表示同样的意思,它们之间的不同又让人很迷惑。
!!(0); // false
!!(false); // false
!!(''); // false
!!(null); // false
!!(undefined); // false
!!(NaN); // false
9. 算术问题 虽然 JavaScript 包含很多算术操作,但你不妨运行一下下面的算式,".2+.4" 应该等于 ".6" 是不是,然而返回的确是 "0.6000000000000001"。JavaScript 在小数计算访问存在一些小问题。
console.log(.2 + .4); // 0.6000000000000001
为什么会这样?简单说,因为 JavaScript 使用 IEEE 标准进行二进制浮点运算,不过,对整数计算是没问题的。
10. 莫名其妙的代码错误 看看以下两段代码:
// braces on the right
return {
foo : bar
};
// braces on their own line
return
{
foo : bar
};
它们应该是一样的,只是 { 位置不同而已,是吧。然而我们再看下面的代码:
如果我们把其中的
var foo = function() {
return {
a : 'b'
};
}();
alert(foo.a); // b
换成
return
{
a : 'b'
};
就会引发错误,这是因为 JavaScript 有一个功能,会纠正它认为错误的代码书写,它会自作聪明地在 return 这个词后面插入一个 ";" ,错误因此而生。
return; // JS incorrectly adds this semicolon.
{
a : 'b'; // It'll add a semicolon here as well, because it doesn't realize that this is an object.
};
本文来源:http://net.tutsplus.com/tutorials/javascript-ajax/top-10-things-that-javascript-got-wrong/
作者:kun10
发布时间:March 9, 2010
分类:牛人之整理
看玉伯的blog 有更新,才看了第一句就引发了疑问了~~~ 于是找了下面的资料 Script中的Defer属性
如果你是一个对系统性能比较关心和在意的人,我想你应该会对Script脚本中的defer属性感兴趣的。 script中的defer属性默认情况下是false的。按照DHTML编程宝典中的描述,对于Defer属性是这样写的:
Using the attribute at design time can improve the download performance of a page because the browser does not need to parse and execute the script and can continue downloading and parsing the page instead. 也就是说:如果是编写脚本的时候加入defer属性,那么浏览器在下载脚本的时候就不必立即对其进行处理,而是继续对页面进行下载和解析,这样会提高下载的性能。 这样的情况有很多种。比如你定义了很多javascript变量,或者在引用文件(.inc)中写了很多的脚本需要处理,那不妨在这些脚本中加入defer属性,对性能的提高肯定有所帮助。 举例如下:
<script language="javascript" defer>
var object = new Object();
....
</script>
因为defer属性默认是为false的,那么在这里
<script language="javascript" defer>
显式声明defer属性后等同于
<script language="javascript" defer=true>
声明了defer属性之后,需要判断是否有别的变量引用了defer脚本块中的变量,否则的话会导致脚本错误的产生。 引用
DEFER是脚本程序强大功能中的一个“无名英雄”。你可能从没有使用过它,但是看完这里的介绍后,相信你就离不开它。它告诉浏览器Script段包含了无需立即执行的代码,并且,与SRC属性联合使用,它还可以使这些脚本在后台被下载,前台的内容则正常显示给用户。
最后请注意两点:
1、不要在defer型的脚本程序段中调用document.write命令,因为document.write将产生直接输出效果。
2、而且,不要在defer型脚本程序段中包括任何立即执行脚本要使用的全局变量或者函数。
加上 defer 等于在页面完全在入后再执行,相当于 window.onload ,但应用上比 window.onload 更灵活!
比较下面的3个例子:
<button id="myButton" onclick="alert('ok')">test</button>
<script>
myButton.click();
</script>
<script defer>
myButton.click();
</script>
<button id="myButton" onclick="alert('ok')">test</button>
<script>
myButton.click();
</script>
<button id="myButton" onclick="alert('ok')">test</button>
---------------- 从w3school 上面看到-------------只有 Internet Explorer 支持 defer 属性。 ---------------- ------------------------------- ---------------- 从《high perfomance javascript》上面看到-------------只有 Internet Explorer4+和firefox 3.5+ 支持 defer 属性。 ---------------- -------------------------------
作者:kun10
发布时间:March 4, 2010
分类:记生活
昨天被面淘宝UED,很牛的团队,不过自己的表现确实有些一般,一方面从技术讲,自己的的确确还有很多要提高的,另一方面,从面试的回答问题和表现讲,自己还不够的自信和稳定。 我觉得淘宝面的收获是很丰富的,我觉得自己对于很多基础的东西理解有很大的偏差,光说一下变量的作用域吧
var a = 2;
function fn(){
alert(a);
var a = 3;
alert(a);
}
fn();
这一段,我没有很弄明白,全局域和函数内部作用域的中变量的查找顺序和查找逻辑,事实上,后来问了money,他告诉我,fn里面已经显式定义了a了,所以函数查找a不会再去外部查找了,因此第一个alert就是undefined。恩,很深刻啊~~~ 另外,面试官也问了我一些其他的技术问题,很多自己曾经使用过,但是因为不常用或是经常的回避使用它们,导致了面试时候思路不广阔,比如apply函数,这个我基本不用的东西。 如下代码:
el.attachEvent("on"+type,function(){
listener.apply(el);
})
原本使用ie的attachEvent,如果事件函数中要用this,this只能指向window对象,apply正好克服了这个问题,listener.apply(el);刚好把listenr函数绑定到了el元素上面,对我来说显得很有创意,而自己过于崇拜一些国外成熟的代码也使得自己无法挖掘更多的东西。 ---------------------------------------有时候自己只会去想这个是不能实现的,那个是要回避的,这样对于提高很不利,也只会写出很保守的代码。 --------------------------------------- 其次就是hr的问题,我觉得昨天的我真的不是很自信,也许是觉得前面的技术题答得不是很好,hr很会问问题,而且很深入,一层层的,有点像实习时部门经理的风格,搞得我这个“不思考的家伙”回答得很仓促,呵呵,也许多思考一下我可以给出好一些的答案。 我觉得最笨的就是回答你有什么优点的那个问题,自己的脑子居然一团乱,或许是很保守的缘故,脑子里面就是不舍得翻出那几个褒义词。回过头和老妈交流才感觉到自己当时真的不是很自信~~~ --------------------------------------不管后面还有没有机会,我还得继续前进,前端还有很大的一块等待自己去发掘,自己的性格也有很大一块需要发掘~~~ -------------------------------------- 感谢你,taobaoUED~~
作者:kun10
发布时间:March 2, 2010
分类:牛人之整理
昨天,我负责了Yahoo!公司组织的一次面试活动,感触颇深的是其中的应聘者提问环节。我得说自己对应聘者们提出的大多数问题都相当失望。我希望听到一些对在Yahoo!工作充满激情的问题。在昨天的应聘者中,只有一个人的问题是我认为最好的,那个人问我:你觉得怎么才能成为优秀的前端工程师?我觉得很有必要把这个问题从面试房间里拿出来讨论一下。首先 ,前端工程师必须得掌握HTML、CSS和JavaScript。只懂其中一个或两个还不行,你必须对这三门语言都很熟悉。也不是说必须对这三门语言都非常精通,但你至少要能够运用它们完成大多数任务,而无需地频繁地寻求别人的帮助。 优秀的前端工程师应该具备快速学习能力。推动Web发展的技术并不是静止不动的,没错吧?我甚至可以说这些技术几乎每天都在变化,如果没有快速学习能力,你就跟不上Web发展的步伐。你必须不断提升自己,不断学习新技术、新模式;仅仅依靠今天的知识无法适应未来。Web的明天与今天必将有天壤之别,而你的工作就是要搞清楚如何通过自己的Web应用程序来体现这种翻天覆地的变化。 计算机科学这个大门类下面的许多分支在人们眼中实际上都不外乎科学。但是,我们所说的前端不是什么科学,而是艺术。艺术家不仅要掌握谋生的技术,还要懂得如何运用。对同一个问题的解决方案在这种情况适用,在另一种情况下可能就不适用。对Web应用程序的前端而言,解决同一问题的方案经常会有很多。没有哪个方案是错的,但其中确实有一些是更合适的。优秀的前端工程师应该知道在什么情况下使用哪种方案更合适,而在什么情况下应该重新选择。 优秀的前端工程师需要具备良好的沟通能力,因为你的工作与很多人的工作息息相关。在任何情况下,前端工程师至少都要满足下列四类客户的需求。产品经理 这些是负责策划应用程序的一群人。他们能够想象出怎样通过应用程序来满足用户需求,以及怎样通过他们设计的模式赚到钱(但愿如此)。一般来说,这些人追求的是丰富的功能。UI设计师 这些人负责应用程序的视觉设计和交互模拟。他们关心的是用户对什么敏感、交互的一贯性以及整体的好用性。他们热衷于流畅靓丽但并不容易实现的用户界面。项目经理 这些人负责实际地运行和维护应用程序。项目管理的主要关注点,无外乎正常运行时间(uptime)应用程序始终正常可用的时间、性能和截止日期。项目经理追求的目标往往是尽量保持事情的简单化,以及不在升级更新时引入新问题。最终用户 当然是应用程序的主要消费者。尽管我们不会经常与最终用户打交道,但他们的反馈意见至关重要;没人想用的应用程序毫无价值。最终用户要求最多的就是对个人有用的功能,以及竞争性产品所具备的功能。 那么,前端工程师应该最关注哪些人的意见呢?答案是所有这四类人 。优秀的前端工程师必须知道如何平衡这四类人的需求和预期,然后在此基础上拿出最佳解决方案。由于前端工程师处于与这四类人沟通的交汇点上,因此其沟通能力的重要性不言而喻。如果一个非常酷的新功能因为会影响前端性能,必须删繁就简,你怎么跟产品经理解释?再比如,假设某个设计如果不改回原方案可能会给应用程序造成负面影响,你怎么才能说服UI设计师?作为前端工程师,你必须了解每一类人的想法从何而来,必须能拿出所有各方都能接受的解决方案。从某种意义上说,优秀的前端工程师就像是一位大使,需要时刻抱着外交官的心态来应对每一天的工作。 我告诫新来的前端工程师最多的一句话,就是不要在没有作出评估之前就随便接受某项任务。你必须始终记住,一定先搞清楚别人到底想让你干什么,不能简单地接受这个功能有问题之类的大概其的说法。而且,你还要确切地知道这个功能或设计的真正意图何在。加一个按钮之类的任务并不总意味着你最后会加一个按钮。还可能意味着你会找产品经理,问一问这个按钮有什么用处,然后再找UI设计师一块探讨按钮是不是最佳的交互手段。要成为优秀的前端工程师,这种沟通至关重要。 无论从哪个方面讲,我都觉得前端工程师是计算机科学职业领域中最复杂的一个工种。绝大多数传统的编程思想已经不适用了,为了在多种平台中使用,多种技术都借鉴了大量软科学的知识和理念。成为优秀前端工程师所要具备的专业技术,涉及到广阔而复杂的领域,这些领域又会因为你最终必须服务的各方的介入而变得更加复杂。专业技术可能会引领你进入成为前端工程师的大门,但只有运用该技术创造的应用程序以及你跟他人并肩协同的能力,才会真正让你变得优秀。 英文原文:What makes a good front end engineer? 本文转自phpchina
1