Javascript tips

I am reading Secrete of Javascript Ninja these days. This book introduced many js tips/patterns, and I wish to summarize what I find useful in this post.

Force the “new” operator

JS is not that object oriented. In JS, all functions is a constructor when it is called with a “new” operator, and “this” variable in the function is bounded to the newly constructed object automatically. This was considered a harmful pattern, because if I forgot to add “new”, then the function will not be considered a constructor, and “this” variable refers to global variable. However, this situation can be avoided by adding the “new” operator automatically if we forgot. Following code does this:

[sourcecode language=”javascript”]
function User(first, last){
if ( !(this instanceof arguments.callee) )
return new User(first, last);
….
}
[/sourcecode]

In this case, “User” cannot be used as a normal function.

Get function it self inside function execution

JS allows you to write code in functional programming style. In other functional programming languages like Scheme, it is not easy to do recursion using a lambda function, because you don’t know how to call the function it self: it got no name. In JS, you can always call current function through arguments.callee.

[sourcecode language=”javascript”]
var factorial=function(n){return n==0?1:n*arguments.callee(n-1);}
[/sourcecode]

Use setTimtout to help break time consuming script

If a script is running when page is loaded, then the page will only be displayed after the script finishes running. However, we can use setTimeout to break long script into small pieces. When the script is constructing page, page view update is not done immediately. Instead, it is pushed into a queue, and everything in the queue will be handled after script block finish running. setTimeout function will break the current script block, and let those tasks in the queue have a chance to be handled.
[sourcecode language=”javascript”]
bd=document.getElementsByTagName("body")[0];
tb=document.createElement("table");
bd.appendChild(tb);
for(var i=0;i<10000;i++){
var tr=document.createElement("tr");
var td=document.createElement("td")
td.appendChild(document.createTextNode(i));
tr.appendChild(td);
td=document.createElement("td")
td.appendChild(document.createTextNode(i*i));
tr.appendChild(td);
tb.appendChild(tr);
}
[/sourcecode]
[sourcecode language=”javascript”]
bd=document.getElementsByTagName("body")[0];
tb=document.createElement("table");
bd.appendChild(tb);
var j=10;
(function(){
for(var i=0;i<1000;i++){
var tr=document.createElement("tr");
var td=document.createElement("td")
td.appendChild(document.createTextNode(i));
tr.appendChild(td);
td=document.createElement("td")
td.appendChild(document.createTextNode(i*i));
tr.appendChild(td);
tb.appendChild(tr);
}
if(j–)setTimeout(arguments.callee,0);
})();
[/sourcecode]

Refer to group in regular expression

Like regular expressions in many other languages, JS use “\1” to refer to first matching group, “\2” for the second…However, this only works inside regular expression itself. One application is primality testing in my earlier post.

JS string also has “replace” method, which support regular expression replacement. To refer to matching group in the second argument of replace method, we need to use “$1”, “$2” instead of “\1”, “\2”.

[sourcecode language=”javascript”]
"hello world".replace(/(\w+)\s+(\w+)/,"$2 $1");
[/sourcecode]

Remove empty text node from HTML

When using DOM to get html node, text nodes containing white space only is very annoying. Following code removes white space text nodes using DFS.

[sourcecode language=”javascript”]
function cleanWhitespace( element ) {
// If no element is provided, do the whole HTML document
element = element || document;
// Use the first child as a starting point
var cur = element.firstChild;
// Go until there are no more child nodes
while ( cur != null ) {
// If the node is a text node, and it contains nothing but whitespace
if ( cur.nodeType == 3 && ! /\S/.test(cur.nodeValue) ) {
// Remove the text node
element.removeChild( cur );
// Otherwise, if it’s an element
} else if ( cur.nodeType == 1 ) {
// Recurse down through the document
cleanWhitespace( cur );
}
cur = cur.nextSibling; // Move through the child nodes
}
}
[/sourcecode]

Get element by class name

[sourcecode language=”javascript”]
function hasClass(name,type) {
var r = [];
var e = document.getElementsByTagName(type || "*");
for ( var j = 0; j < e.length; j++ )
if ( e[j].classList.contains(name) )
r.push( e[j] );
return r;
}
[/sourcecode]

Leave a Reply

Your email address will not be published.