1) Comma Caused Coruption
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.
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":
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:
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:
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:
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:
and get the height.
However, the default call to parseInt has a problem.
Guess what the value of monthInt will be:
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:
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:
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:
That worked perfectly.
8) Event handlers Pitfalls
Never set event handlers like the following:
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:
9) Focus Pocus
Often when I want to add inline editing to my app, I create a text field and then focus on it:
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 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);