代码改变世界

【javascript基础】 Nine Javascript Gotchas 【翻译】JavaScript的9个陷阱及评点

2012-11-12 19:08  sniper007  阅读(305)  评论(0编辑  收藏  举报

原文

 

1) Comma Caused Coruption

 

  var theObj = {
        city : "Boston",
        state : "MA",
  }

 

 

Notice the comma after "MA"?  It will be the source of many woes.  Firefox will pay it no heed, but it will create a syntax error in IE.  Worst of all, IE will not tell you where the actual bug is.  The only soution is to scan through your entire 2,500 line javascript file trying to find that extra comma.

2)  "this" can change which object it's pointing at

Take a look at this code sample.

 

<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>

 

The function MyObject.ClickHandler will actually give a different alert, depending on how it's being called.

If you call MyObject.OnClick(); you will get a popup saying "Javascript rules".  

However, if you click on the button "MyButton", the popup will say "undefined"

When you assign MyObject.OnClick to the even handler, the special variable "this" now referes to the button, not to MyObject.

There are several ways to refer to MyObject.  My favorite is to introduce the "self" variable as a replacement for "this":

 

<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>

 

 

Now the alert will say "Javascript rules" no matter what you call. The variable "self" will always refer to MyObject.

Note there is one more gotcha with the above code.  Do not forget the "var" in "var self" or IE will throw a mysterious exception.


3) Identity Theft

Never name a variable the same as an HTML ID:

 

<input type="button" id="TheButton">

<script>
    TheButton 
= get("TheButton");
</script>

 

 

This will work fine in Firefox but cause and object undefined error in InternetExplorer


4)  String replace only replaces the first occurrence

You might have a code to turn a title into a URL slug:

 

 

var fileName = "This is a title".replace(" ","_");

 

 

 

 

To your chagrin, fileName is actually equal to:
    "This_is a title"

Unlike replace in other languages such as C# or Python, only the first occurence is replaced.  That's because the first argument to replace is actually a regular expression.

To replace all occurences, you need to set the global modifier. Use:

 

 

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

 

5)  MouseOut sometimes means MouseIn

When you have nested div's, the onmouseout event will fire for an outer box when you move inside the inner box.  For context menu's or hover overs, this is not the desired behavior.  My solution is to test for the mouse's location, and only take action if the mouse is actually positioned outside the outer box.

6)  ParseInt scoffs at your base ten numbering system

ParseInt is really nice, because it works with strings that are not pure digits.  I always find myself doing the following:

 

 

 

var height = parseInt("200px")

 

and get the height.

However, the default call to parseInt has a problem.

Guess what the value of monthInt will be:

 

  month = "09"
  var monthInt = parseInt(month )

 

If you guessed 9, then gotcha!  The answer is 0.

When the string begins with a zero, parseInt interprets the value in base 8.  To fix this problem, do the following:

 

 

 

var monthInt = parseInt(month , 10);

 

 

Now monthInt will be equal to 9.  The second argument forces parseInt to use a base ten numbering system.


7)  for loops over the kitchen sink

I once had an array as such:

 

 

var arr = [5,10,15]
var total = 1;
I iterated over the array:
for ( var x in arr) {
    total = total * arr[x];

}

 

This piece of code worked fine, until one day, I was getting error.  The error said, "Cannot object  by a number.  This flummuxed me since there were no strings in the array.  But, lo, when I iterated over the array and logged each value, there was an indeed a function object called "find".  

The cause was a javascript library that we had recently installed.  This library added a "find" method to the javascript array object.  Nice to have, but I the "for" loop in javascript will iterate it over all object attributes, including functions.  

But fortunately, the object was not included in the "length" attribute.  Thus to fix the problem, I used another kind of for loop:

 

 

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

}

 

 

 

That worked perfectly.



8)  Event handlers Pitfalls
Never set event handlers like the following:

 

 

window.onclick = MyOnClickMethod

 

 

 

1)  This will overwrite existing events.  It opens up the possibility of overwriting by some other javascript
2)  This can introduce memory leaks in Internet Explorer in certain circumstances.  

Instead, use a library that abstracts around the event handler, like YUI:

 

 

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

 

9)  Focus Pocus

Often when I want to add inline editing to my app, I create a text field and then focus on it:

 

 

var newInput = document.createElement("input");
document.body.appendChild("newInput");
newInput.focus();
newInput.select();

 

However, the above code will create an error in IE.  The reason the even though you have added the element, it is not really available yet.  Fortunately, a split second delay is all we need:

 

 

var newInput = document.createElement("input");
newInput.id = "TheNewInput";
document.body.appendChild("newInput");

setTimeout("document.getElementById('TheNewInput').focus(); document.getElementById('TheNewInput').select();", 10);

 

 

 译文如下:

 

以下是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中有mouseenter和mouseleave,但不是标准的。作者在此建议大家使用库比如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, 晕。我只不过引入了一个库而已啊。原来是这个库改写了Array的prototype,这样,我们的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中找到答案。