JavaScript的9个陷阱及评点

http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/

来自Nine Javascript Gotchas, 以下是JavaScript容易犯错的九个陷阱。虽然不是什么很高深的技术问题,但注意一下,会使您的编程轻松些,即所谓make life easier. 笔者对某些陷阱会混杂一些评点。

  1. 最后一个逗号

    如这段代码,注意最后一个逗号,按语言学角度来说应该是不错的(python的类似数据类型辞典dictionary就允许如此)。IE会报语法错误,但语焉不详,你只能用人眼从几千行代码中扫描。

    <script>
      var theObj = {
            city : "Boston",
            state : "MA",
      }
    </script> 
  2. 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作用域的问题。如果你看过,你会发现解决方案不止一种。

  3. 标识盗贼

    在JavaScript中不要使用跟HTML的id一样的变量名。如下代码:

    <input type="button" id="TheButton">
    <script>
        TheButton = get("TheButton");
    </script>

    IE会报对象未定义的错误。我只能说:IE sucks.

  4. 字符串只替换第一个匹配

    如下代码:

    <script>
        var fileName = "This is a title".replace(" ","_");
    </script>

    而实际上,结果是”This_is a title“. 在JavaScript中,String.replace的第一个参数应该是正则表达式。所以,正确的做法是这样:

    var fileName = "This is a title".replace(/ /g,"_");
  5. mouseout意味着mousein

    事实上,这是由于事件冒泡导致的。IE中有mouseentermouseleave,但不是标准的。作者在此建议大家使用库比如YUI来解决问题。

  6. parseInt是基于进制体系的

    这个是常识,可是很多人给忽略了parseInt还有第二个参数,用以指明进制。比如,parseInt("09"),如果你认为答案是9,那就错了。因为,在此,字符串以0开头,parseInt以八进制来处理它,在八进制中,09是非法,返回false,布尔值false转化成数值就是0. 因此,正确的做法是parseInt("09", 10).

  7. for...in...会遍历所有的东西

    有一段这样的代码:

    var arr = [5,10,15]
    var total = 1;
    for ( var x in arr) {
        total = total * arr[x];
    }

    运行得好好的,不是吗?但是有一天它不干了,给我返回的值变成了NaN, 晕。我只不过引入了一个库而已啊。原来是这个库改写了Arrayprototype,这样,我们的arr平白无过多出了一个属性(方法),而for...in...会把它给遍历出来。所以这样做才是比较安全的:

    for ( var x = 0; x < arr.length; x++) {
        total = total * arr[x];
    }

    其实,这也是污染基本类的prototype会带来危害的一个例证。

  8. 事件处理器的陷阱

    这其实只会存在使用作为对象属性的事件处理器才会存在的问题。比如window.onclick = MyOnClickMethod这样的代码,这会复写掉之前的window.onclick事件,还可能导致IE的内容泄露(sucks again)。在IE还没有支持DOM 2的事件注册之前,作者建议使用库来解决问题,比如使用YUI:

    YAHOO.util.Event.addListener(window, "click", MyOnClickMethod);

    这应该也属于常识问题,但新手可能容易犯错。

  9. 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中找到答案。

21 Responses to “JavaScript的9个陷阱及评点”

  1. Cloudream Says:

    那个亲爱的IE……

    -_,-

    当然Firefox也有JS处理问题……OPERA同样也不完美……

    (偶承认,偶记不知他们仨HTML解析内核的名字……除了gecko……)

    (○ ̄ ~  ̄○)

  2. jaceju Says:

    譯得好!

    不過為什麼標題是 “Scrip” ?是不是少了個 t ?

  3. 子乌 Says:

    嗯,其实这些也并不算是陷阱,只能算是js初学者容易犯的几个错误:D

  4. ÀÖÀÖ˶ Says:

    JavaScripµÄ9¸ö……

    À´×ÔNine Javascript Gotchas, ÒÔÏÂÊÇJavaScriptÈÝÒ×·¸´íµÄ¾Å¸öÏÝÚå¡£ËäÈ»²»ÊÇʲôºÜ¸ßÉîµÄ¼¼ÊõÎÊÌ⣬µ«×¢Òâһϣ¬»áʹÄúµÄ±à³ÌÇáËÉЩ£¬¼´Ëùνmake life easier. ±…

  5. cute Says:

    都是常犯错误。

  6. 沈蚊 Says:

    亚黑的英文真不是一般难看。

  7. 魏中华 Says:

    大致看了下 YUI,惊叹于它庞大的规模,几十个文件夹,动辄数千行,莫非是传说中的 Javascript 版本的 MFC ?

    像我这种对复杂事物特别敏感的人士,似乎很难感兴趣,看来要抱憾终生了。

  8. kakawar Says:

    我觉得jQuery也挺好,因为目前只会用这个……

  9. hax Says:

    你的译文与原文有点不一样。有些你的评点应该说明一下,不是原文的。

    “理由可能是当你执行fouce()的时候,元素还不存在。”
    这里你写错了。一个是笔误,另外一个,元素当然已经存在了。原文说的是not available,不可用而已。

  10. hax Says:

    To Cloudream:
    ie的引擎叫做Trident,三叉戟。
    opera似乎没有专门的名字。
    safari是WebCore。

    它们的js引擎分别是:
    JScript (IE)
    SpiderMonkey(FF)
    JavaScriptCore(Safari)
    linear_b(Opera)

  11. yason Says:

    确实非常不错的内容

  12. superwunc Says:

    关于第三个陷阱

    如果对变量使用var定义了就不会有问题

    var TheButton ;
    TheButton = get(“TheButton”);

  13. fyting Says:

    用了好几个suck,我刚开始以为原文如此,结果发现是你翻译时把自己的个人喜好也加进去了。
    This will work fine in Firefox but cause and object undefined error in Internet Explorer
    IE会报对象未定义的错误。我只能说:IE sucks.

  14. aw Says:

    关于Prototype确实很恶心。用ActionScript2就很爽 ^_^
    话说我当年刚开始写AS的时候,满眼望去都是Prototype……一个个都是地雷啊!

  15. popper Says:

    正在学习 中 数于初学着感觉还是很有帮助的 。

  16. Akira Says:

    我也来评一下^^

    最后一个逗号
    如这段代码,注意最后一个逗号,按语言学角度来说应该是不错的(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出来吧
    那样也可以快一些

  17. 猫鱼 Says:

    请问为何 第一个例子里面的
    MyObject.ClickHandler
    ie总会报错: MyObject.ClickHandler为空或不是对象?

  18. weiye Says:

    关于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对象。

  19. 飞天大神猪 Says:

    确实是遇到过里面的一些问题。但不赞成遇到问题随便使用类库来解决。因为你永远不知道类库会带来什么后果。

  20. JavaScript的9个陷阱 - Elric’s Blog - 关注前端技术,关注生活. Says:

    [...] 译文:http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/ 日志分类:Javascript 标签:Javascript [...]

  21. Physure.com » [转]JavaScript的陷阱 Says:

    [...]   这本来是翻译Estelle Weyl的《15 JavaScript Gotchas》,里面介绍的都是在JavaScript编程实践中平时容易出错或需要注意的地方,并提供避开这些陷阱的方法,总体上讲,就是在认清事物本质的基础样要坚持好的编程习惯,其实这就是Douglas Crockford很久以前提出的JavaScript风格要素问题了,有些内容直接是相同的,具体请看《Javascript风格要素(1)》和《Javascript风格要素(2)》。在翻译的过程中,我又看到了贤安去年翻译的《JavaScript的9个陷阱及评点》,其内容又有些交叉在一起,所以我就在现有翻译的基础上做了一个简单的拼合,并依据自己的理解增加了一些注释和解释。 [...]


你可能感兴趣的:(JavaScript的9个陷阱及评点)