JavaScript Tricks You May Not Know

August 29th, 2012 Leave a comment
Like the article?
JavaScript Tricks You May Not Know

JavaScript has been around for a long time now and on the surface it shares some similarities with Java and C and is a fully-functional Object-Oriented language. However, at the core, JavaScript is more like a functional programming language with some obscure twists. In this article I will show you some tips and techniques you may not be aware of that simulate C-like features and help you write more powerful JavaScript.

Deeply Nested Objects

JavaScript can do operations on a deeply nested object but if you need to do this, it is better to store it as a reference in a temp variable instead of having to de-reference it each time. Let’s assume you want to do a series of operations on a textfield, accessible like this:

document.forms[0].elements[0]

Since each period (.) results in an operation to retrieve a property in a loop, the operations can add up quickly. It is recommended that you store this reference to the textfield in a variable, like this:

var field = document.forms[0].elements[0];

This allows you to retrieve the object once and re-use it as necessary without all of the necessary re-getting.

Null vs. Undefined

JavaScript is one of the few languages that has a difference between undefined and null values, which sometimes causes confusion in those new to the language. null is a special value meaning “no value” where null is often thought of as a special type since typeof null returns “object”.However, undefined typically means that the variable has not yet been declared or given a value, which can cause more confusion. For example, both of these snippets of code will return “undefined”:

alert(typeof myVariable);

var myVariable;
alert(typeof myVariable);

In both of these cases, the variable fulfills one of the conditions listed above for undefined, which is most likely the expected behavior. However, with the equality operator (==), null and undefined are equal, despite the fact they are two different types. This is the purpose for the identity operator (===), which doesn’t view them as equal.

The Delete Operator

JavaScript has a delete operator that removes data and “undefines” a property, which can be handy when you want to make sure there is no data currently there. You can apply the delete operator to object properties and array members but not to variables declared with var. However, if you have implicitly declared variables you can still delete them. Here is an example:

var someObj = { val: "My string": }
alert (someObj.val); //should display "My string"

delete someObj.val; //remove the value
alert (someObj.val); //should display "undefined"

Static Local Variables

Many high-level programming languages support the idea of static local variables. These are variables that retain their values between function calls. JavaScript does not have a static keyword to be able to support this technique. However, it is possible to mimic this functionality with functions that are also objects. Storing the static variable as a property of the function creates the same functionality as using the static keyword in other languages. Here is an example:

function count() {
  if (typeof count.i == 'undefined') {
    count.i = 0;
  }
  return count.i++;
}

As you can see, when count is called for the first time, count.i is undefined, so our “if” condition is true, count.i is then set to zero. Since we are storing the variable as a property of the count function, it will be able to retain its value between function calls, mimicking the abilities of a static variable.

Assertion

Assertion is a commonly used debug technique that ensures an expression evaluates to true during execution. If the expression is evaluated as false, this indicates a bug in the code. JavaScript does not have a built-in assertion function like other object-oriented languages, but it is easy to put one together that will create this functionality. Here is an example:

function AssertException(message) {
  this.message = message;
}

AssertException.prototype.toString = function() {
  return 'AssertException: ' + this.message;
}

function assert(exp, message) {
  if (!exp) {
    throw new AssertException(message);
  }
}

The above code creates a function that throws an exception of type AssertException if the passed expression is evaluated as “false”. Throwing this exception on its own isn’t really that useful but when you add in an error message it would be easier to detect problematic assertions. Usage of this function would be similar to languages such as C or Java:

try {
  assert(obj != null, 'Object is null');
} catch (e) {
  if (e instanceof AssertException) {
     // error handling
  }
}

This way, if the object happens to be null, the error message will be printed in the JavaScript console for you to read at runtime: uncaught exception: AssertException: Object is null

Custom Comparison and Sorting

Sorting is a fairly common task and JavaScript provides a sorting method for arrays to make this easy. However, strange behavior comes in when non-string elements are converted to strings before sorting, which can lead to odd results when working with numbers. For example:

var list = [5, 10, 2, 1];
list.sort();
// list is now: [1, 10, 2, 5]

The explanation is simple, but probably unexpected. The numbers are converted to strings before they are sorted, so 10 becomes “10” and 5 becomes “5”, etc…When the JavaScript interpreter compares the two strings by comparing the first two characters of each, the first string is considered “less” than the second string. In this case, 1 comes before 2, which is why 10 comes before 2.

You can override this behavior by supplying your own custom comparison function. This will tell the function how elements are to be sorted. It takes two compared elements a and b as parameters and should return the following:

  • A value lesson than zero if a < b
  • Zero if a == b
  • A value greater than zero if a > b

It is very easy to program a function to do the comparison:

function compare(a, b) {
  return a - b;
}

Sorting our original array with this function fixes the numerical sort problem:

var list = [5, 10, 2, 1];
list.sort(compare);
// list is now: [1, 2, 5, 10]

Tying Methods to Objects

If you have worked with JavaScript enough you have probably come upon the situation where you need to assign an object’s method to an event handler. The problem with this is that event handlers are called in context of the HTML element. To get around this, you can create a function that binds a method to an object. Here is an example function:

function bind(obj, method) {
  return function() { 
    return method.apply(obj, arguments); 
  }
}

The function takes a method and an object and returns a function that will always call the method in the context of that object. Here is an example of how to use the function:

var obj = {
  msg: 'Name is',
  buildMessage: function (name) {
    return this.msg + ' ' + name;
  }
}

alert(obj.buildMessage('Mike')); // displays: Name is Mike

f = obj.buildMessage;
alert(f('Johnson')); // displays: undefined Johnson

g = bind(obj, obj.buildMessage);
alert(g('Johnson')); // displays: Name is Johnson

Concatenating Strings vs. Array.join

In JavaScript, concatenating strings can be a big hit on performance so it should be avoided in most situations. However, what if you wanted to build a string out of many pieces? The bad way would be to use the concatenation “+” operation, like so:

str = '';
for (/* each piece */) {
  str += piece; // don't do this!
}
return str;

Overall, this is going to perform poorly due to all of the concatenation operations that you are performing. A better way to approach this problem would be to use the Array.join() method that joins all array elements into one string:

var tmpArray = [];
for (/* each piece */) {
  tmpArray.push(piece);
}
str = tmpArray.join(''); 
return str;

Using this method will create a much faster operation that produces the same result.

NOTE: Some commenters here indicated that concat is actually faster than the combination of array push and join. Here is a page that runs a test against the two operations: http://jsperf.com/joint-vs-concat. I won’t dispute this. Just use whatever operation you prefer. The difference in performance does not appear to be significant.

Conclusion

I hope you have enjoyed reading about these quirks in JavaScript. Although you may not always been able to approach a problem the same way, JavaScript is a great client-side scripting language with many powerful features for you to learn about. As you find more tricks like these, you will be able to become more proficient at your JavaScript and write better and more efficient code.

Help us spread the word!
  • Twitter
  • Facebook
  • LinkedIn
  • Pinterest
  • Delicious
  • DZone
  • Reddit
  • Sphinn
  • StumbleUpon
  • Google Plus
  • RSS
  • Email
  • Print
Don't miss another post! Receive updates via email!

Comment