JavaScript Tricks You May Not Know

August 29th, 2012 Leave a comment 15 comments
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!

15 comments

  1. melanke says:

    Very Nice ;)

  2. Praven says:

    The “Concatenating Strings vs. Array.join” tip, does not seem to be relevant anymore. See
    the “String Concatenation” section here:
    http://oreilly.com/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html
    As it says, “Firefox was the first browser to optimize string concatenation. Beginning with version 1.0, the array technique is actually slower than using the plus operator in all cases. Other browsers have also optimized string concatenation, so Safari, Opera, Chrome, and Internet Explorer 8 also show better performance using the plus operator”

  3. alex says:

    string concatenation faster
    proof: http://jsperf.com/joint-vs-concat

  4. Andrew says:

    Great reference for some of those handy JS techniques that we should all use more often/

  5. Hans PUFAL says:

    For static local variables the following works on the Chrome browser :

    function count () {
    count = function () {return ++count.i);
    return count.i = 1;
    }

    This eliminates the test for count.i on each call on count in exchange for the redefining of the function count on the first call only.

  6. Hans PUFAL says:

    In ‘Custom comparison and sorting’ the array contents should all be strings :

    var list = ["5", "10", "2", "1"];

    Or at least the “10” to make your results consistent.

    • Frederick Polgardy says:

      No — the point of this exercise was to show that a list of *numbers* will be sorted by their string values by default, unless you provide a comparison function.

  7. Matt says:

    Whether to use string concatenation, string.concat or Array.join really depends on the browser. The book High Performance JavaScript goes into this scenario in nice detail. Many modern browsers will concat strings faster than they will join() arrays of strings.

  8. Tim says:

    Thanks for making everyone smarter :)

    One thing – looks like there’s a typo in “Tying Methods to Objects”

    ‘varobj’ should probably read ‘var obj’

    My as-yet-uncaffeinated brain took several cycles to parse that!

  9. Nirav says:

    Thank you! Basic concepts but very clearly explained.

  10. Adam Bankin says:

    The code snippet in Null vs. Undefined returns undefined for both due to variable hoisting.

    Regardless of where you put var in the flow of your code it will be hoisted to before your other code.

    So:
    alert(typeof myVariable);
    var myVariable;
    alert(typeof myVariable);

    is actually parsed as:
    var myVariable;
    alert(typeof myVariable);
    alert(typeof myVariable);

  11. ZER0 says:

    For Static Local Variables, there is a trick with bitwise operator specifically for counters, that could be work to be mentioned (well, we’re talking about tricks here after all):

    function count() {
    return count.i = -~count.i;
    }

    Just notice that it will start from `1` instead of `0`, but usually for counting it’s fine.

  12. Patrick Berkeley says:

    String concat is faster than array push + join. Please fix. http://jsperf.com/string-concat-vs-array-push-then-join-per-symbol

Comment