来自Nine Javascript Gotchas, 以下是JavaScript容易犯错的九个陷阱。虽然不是什么很高深的技术问题,但注意一下,会使您的编程轻松些,即所谓make life easier. 笔者对某些陷阱会混杂一些评点。
-
最后一个逗号
如这段代码,注意最后一个逗号,按语言学角度来说应该是不错的(python的类似数据类型辞典dictionary就允许如此)。IE会报语法错误,但语焉不详,你只能用人眼从几千行代码中扫描。
<script> var theObj = { city : "Boston", state : "MA", } </script>
-
this
的引用会改变如这段代码:
<input type="button" value="Gotcha!" id="MyButton" > <script> var MyObject = function () { this.alertMessage = "Javascript rules"; this.ClickHandler = function() { alert(this.alertMessage ); } }(); document.getElementById("theText").onclick = MyObject.ClickHandler </script>
并不如你所愿,答案并不是”JavaScript rules”。在执行
MyObject.ClickHandler
时,代码中红色这行,this
的引用实际上指向的是document.getElementById("theText")
的引用。可以这么解决:<input type="button" value="Gotcha!" id="theText" > <script> var MyObject = function () { var self = this;
this.alertMessage = "Javascript rules"; this.OnClick = function() { alert(self.value); } }(); document.getElementById("theText").onclick = MyObject.OnClick </script>实质上,这就是JavaScript作用域的问题。如果你看过,你会发现解决方案不止一种。
-
标识盗贼
在JavaScript中不要使用跟HTML的id一样的变量名。如下代码:
<input type="button" id="TheButton"> <script> TheButton = get("TheButton"); </script>
IE会报对象未定义的错误。我只能说:IE sucks.
-
字符串只替换第一个匹配
如下代码:
<script> var fileName = "This is a title".replace(" ","_"); </script>
而实际上,结果是”
This_is a title
“. 在JavaScript中,String.replace
的第一个参数应该是正则表达式。所以,正确的做法是这样:var fileName = "This is a title".replace(/ /g,"_");
-
mouseout意味着mousein
事实上,这是由于事件冒泡导致的。IE中有
mouseenter
和mouseleave
,但不是标准的。作者在此建议大家使用库比如YUI来解决问题。 -
parseInt
是基于进制体系的这个是常识,可是很多人给忽略了
parseInt
还有第二个参数,用以指明进制。比如,parseInt("09")
,如果你认为答案是9,那就错了。因为,在此,字符串以0开头,parseInt
以八进制来处理它,在八进制中,09
是非法,返回false
,布尔值false
转化成数值就是0. 因此,正确的做法是parseInt("09", 10)
. -
for...in...
会遍历所有的东西有一段这样的代码:
var arr = [5,10,15] var total = 1; for ( var x in arr) { total = total * arr[x]; }
运行得好好的,不是吗?但是有一天它不干了,给我返回的值变成了
NaN
, 晕。我只不过引入了一个库而已啊。原来是这个库改写了Array
的prototype
,这样,我们的arr
平白无过多出了一个属性(方法),而for...in...
会把它给遍历出来。所以这样做才是比较安全的:for ( var x = 0; x < arr.length; x++) { total = total * arr[x]; }
其实,这也是污染基本类的
prototype
会带来危害的一个例证。 -
事件处理器的陷阱
这其实只会存在使用作为对象属性的事件处理器才会存在的问题。比如
window.onclick = MyOnClickMethod
这样的代码,这会复写掉之前的
window.onclick
事件,还可能导致IE的内容泄露(sucks again)。在IE还没有支持DOM 2的事件注册之前,作者建议使用库来解决问题,比如使用YUI:YAHOO.util.Event.addListener(window, "click", MyOnClickMethod);
这应该也属于常识问题,但新手可能容易犯错。
-
Focus Pocus
新建一个
input
文本元素,然后把焦点挪到它上面,按理说,这样的代码应该很自然:var newInput = document.createElement("input"); document.body.appendChild(newInput); newInput.focus(); newInput.select();
但是IE会报错(sucks again and again)。理由可能是当你执行
fouce()
的时候,元素尚未可用。因此,我们可以延迟执行:var newInput = document.createElement("input"); newInput.id = "TheNewInput"; document.body.appendChild(newInput); setTimeout(function(){ //这里我使用闭包改写过,若有兴趣可以对比原文 document.getElementById('TheNewInput').focus(); document.getElementById('TheNewInput').select();}, 10);
在实践中,JavaScript的陷阱还有很多很多,大多是由于解析器的实现不到位而引起。这些东西一般都不会在教科书中出现,只能靠开发者之间的经验分享。谢天谢地,我们生活在网络时代,很多碰到的问题,一般都可以在Google中找到答案。
August 20th, 2007 at 03:32
那个亲爱的IE……
-_,-
当然Firefox也有JS处理问题……OPERA同样也不完美……
(偶承认,偶记不知他们仨HTML解析内核的名字……除了gecko……)
(○ ̄ ~  ̄○)
August 20th, 2007 at 09:56
譯得好!
不過為什麼標題是 “Scrip” ?是不是少了個 t ?
August 20th, 2007 at 10:53
嗯,其实这些也并不算是陷阱,只能算是js初学者容易犯的几个错误:D
August 20th, 2007 at 11:32
JavaScripµÄ9¸ö……
À´×ÔNine Javascript Gotchas, ÒÔÏÂÊÇJavaScriptÈÝÒ×·¸´íµÄ¾Å¸öÏÝÚå¡£ËäÈ»²»ÊÇʲôºÜ¸ßÉîµÄ¼¼ÊõÎÊÌ⣬µ«×¢Òâһϣ¬»áʹÄúµÄ±à³ÌÇáËÉЩ£¬¼´Ëùνmake life easier. ±…
August 20th, 2007 at 14:26
都是常犯错误。
August 21st, 2007 at 00:03
亚黑的英文真不是一般难看。
August 21st, 2007 at 11:12
大致看了下 YUI,惊叹于它庞大的规模,几十个文件夹,动辄数千行,莫非是传说中的 Javascript 版本的 MFC ?
像我这种对复杂事物特别敏感的人士,似乎很难感兴趣,看来要抱憾终生了。
August 21st, 2007 at 13:27
我觉得jQuery也挺好,因为目前只会用这个……
August 21st, 2007 at 18:04
你的译文与原文有点不一样。有些你的评点应该说明一下,不是原文的。
“理由可能是当你执行fouce()的时候,元素还不存在。”
这里你写错了。一个是笔误,另外一个,元素当然已经存在了。原文说的是not available,不可用而已。
August 21st, 2007 at 18:10
To Cloudream:
ie的引擎叫做Trident,三叉戟。
opera似乎没有专门的名字。
safari是WebCore。
它们的js引擎分别是:
JScript (IE)
SpiderMonkey(FF)
JavaScriptCore(Safari)
linear_b(Opera)
August 27th, 2007 at 18:00
确实非常不错的内容
September 3rd, 2007 at 09:54
关于第三个陷阱
如果对变量使用var定义了就不会有问题
var TheButton ;
TheButton = get(“TheButton”);
September 8th, 2007 at 15:42
用了好几个suck,我刚开始以为原文如此,结果发现是你翻译时把自己的个人喜好也加进去了。
This will work fine in Firefox but cause and object undefined error in Internet Explorer
IE会报对象未定义的错误。我只能说:IE sucks.
October 1st, 2007 at 21:30
关于Prototype确实很恶心。用ActionScript2就很爽 ^_^
话说我当年刚开始写AS的时候,满眼望去都是Prototype……一个个都是地雷啊!
October 8th, 2007 at 08:58
正在学习 中 数于初学着感觉还是很有帮助的 。
November 3rd, 2007 at 11:18
我也来评一下^^
最后一个逗号
如这段代码,注意最后一个逗号,按语言学角度来说应该是不错的(python的类似数据类型辞典dictionary就允许如此)。IE会报语法错误,但语焉不详,你只能用人眼从几千行代码中扫描。
————————————————————————————————————————-
这是JS解析器的问题,符合ECMA v3语法规范
这不算一个毛病,追求这个未免有点太……
允许最后一个逗号或许有好处,但是这样的话,不利于判断对象的结束,不认真的话也会产生问题
(举一个可能不是十分恰当的例子:应该没有人指责C语言字符串中的最后一个”)
this的引用会改变
————————————————————————————————————————-
对于习惯了Class-based OOP的人来说这是一个大问题
this指针怎么应该改变呢,我也认为不应该
但是JavaScript不是Class-based OOP的语言,而且,更重要的是
它的this是在执行域生效,而不是在语法域生效
JS的函数是可以作为数据来对待的,所以this只表示执行域上的对象所有者
这很让人困扰,但是也有好处,好处之一是泛型,这里我不过多作解释,需要理解一些高级的概念
标识盗贼
在JavaScript中不要使用跟HTML的id一样的变量名。如下代码:
—————————————————————————————————————–
这个完全不是问题,W3C的规范中DOM对象通过document.getElementById来获得
它不应该和JS的变量冲突,如果冲突了是浏览器的问题
例子中的问题加上var就可以避免
字符串只替换第一个匹配
—————————————————————————————————————-
想不出这个为什么也算问题,或许应该把replace函数分成replaceFirst和replaceAll(笑)
mouseout意味着mousein
事实上,这是由于事件冒泡导致的。IE中有mouseenter和mouseleave,但不是标准的。作者在此建议大家使用库比如YUI来解决问题。
—————————————————————————————————————-
IE的事件模型,讨厌的兼容性,交给基础库去处理
parseInt是基于进制体系的
这个是常识,可是很多人给忽略了parseInt还有第二个参数,用以指明进制。比如,parseInt(“09″),如果你认为答案是9,那就错了。因为,在此,字符串以0开头,parseInt以八进制来处理它,在八进制中,09是非法,返回false,布尔值false转化成数值就是0. 因此,正确的做法是parseInt(“09″, 10).
————————————————————————————————–
嗯,是啊……C语言的atoi会不会这样?(笑)
for…in…会遍历所有的东西
————————————————————————————————-
应该是会遍历所有propertyIsEnumerable的东西
所以强烈BS直接修改Object原型的做法
但是数组也不应该用for…in…来遍历,那不符合语义
事件处理器的陷阱
这其实只会存在使用作为对象属性的事件处理器才会存在的问题。比如window.onclick = MyOnClickMethod这样的代码,这会复写掉之前的window.onclick事件,还可能导致IE的内容泄露(sucks again)。在IE还没有支持DOM 2的事件注册之前,作者建议使用库来解决问题,比如使用YUI:
—————————————————————————————————–
嗯,事件模型很令人头疼……
但是IE用attachEvent可以避免这个问题
Focus Pocus
新建一个input文本元素,然后把焦点挪到它上面,按理说,这样的代码应该很自然:
—————————————————————————————————-
这个……没办法……
还是事先做好一个hidden的input然后show出来吧
那样也可以快一些
November 29th, 2007 at 17:53
请问为何 第一个例子里面的
MyObject.ClickHandler
ie总会报错: MyObject.ClickHandler为空或不是对象?
December 20th, 2007 at 23:49
关于this的问题,楼主的例子是有问题的,
var MyObject = function () {
var self = this;
this.alertMessage = “Javascript rules”;
this.OnClick = function() {
alert(self.value);
}
}();
document.getElementById(”theText”).onclick = MyObject.OnClick
第一个匿名函数的实际调用对象是window,self=this=window。匿名函数调用的结果返回给MyObjct。它并不具有方法OnClick,OnClick实际是赋给了window。
可以改成这样
function MyObject () {
this.alertMessage = “Javascript rules”;
this.OnClick = function() {
alert(self.value);
}
};
MyObject.call(MyObject);
document.getElementById(”theText”).onclick = MyObject.OnClick
————————————————————————————————————
第三个在JavaScript中不要使用跟HTML的id一样的变量名。这根本不是问题。
IE会把id当作dom对象,当然不可以随意赋值,使用的时候应该重新定义 TheButton = get(“TheButton”);就像不能直接给self赋值一样,self本身指向window对象。
January 8th, 2008 at 09:19
确实是遇到过里面的一些问题。但不赞成遇到问题随便使用类库来解决。因为你永远不知道类库会带来什么后果。
June 17th, 2009 at 09:17
[...] 译文:http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/ 日志分类:Javascript 标签:Javascript [...]
February 6th, 2010 at 00:16
[...] 这本来是翻译Estelle Weyl的《15 JavaScript Gotchas》,里面介绍的都是在JavaScript编程实践中平时容易出错或需要注意的地方,并提供避开这些陷阱的方法,总体上讲,就是在认清事物本质的基础样要坚持好的编程习惯,其实这就是Douglas Crockford很久以前提出的JavaScript风格要素问题了,有些内容直接是相同的,具体请看《Javascript风格要素(1)》和《Javascript风格要素(2)》。在翻译的过程中,我又看到了贤安去年翻译的《JavaScript的9个陷阱及评点》,其内容又有些交叉在一起,所以我就在现有翻译的基础上做了一个简单的拼合,并依据自己的理解增加了一些注释和解释。 [...]