javascript garden

Intro

JavaScript Garden is a growing collection of documentation about the most

quirky parts of the JavaScript programming language. It gives advice to avoid common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert JavaScript programmers may encounter on their endeavors into the depths of the language.

JavaScript Garden does not aim to teach you JavaScript. Former knowledge of the language is strongly recommended in order to understand the topics covered in this guide. In order to learn the basics of the language, please head over to the excellent guide on the Mozilla Developer Network.

Objects

Object Usage and Properties

Everything in JavaScript acts like an object, with the only two exceptions being

null and undefined.

false.toString(); // 'false'

[1, 2, 3].toString(); // '1,2,3'



function Foo(){}

Foo.bar = 1;

Foo.bar; // 1

A common misconception is that number literals cannot be used as

objects. That is because a flaw in JavaScript's parser tries to parse the dot

notation on a number as a floating point literal.

2.toString(); // raises SyntaxError

There are a couple of workarounds that can be used to make number literals act

as objects too.

2..toString(); // the second point is correctly recognized

2 .toString(); // note the space left to the dot

(2).toString(); // 2 is evaluated first

Objects as a Data Type

Objects in JavaScript can also be used as Hashmaps; they mainly consist

of named properties mapping to values.

Using an object literal - {} notation - it is possible to create a

plain object. This new object inherits from Object.prototype and

does not have own properties defined.

var foo = {}; // a new empty object



// a new object with a 'test' property with value 12

var bar = {test: 12}; 

Accessing Properties

The properties of an object can be accessed in two ways, via either the dot

notation or the square bracket notation.

var foo = {name: 'kitten'}

foo.name; // kitten

foo['name']; // kitten



var get = 'name';

foo[get]; // kitten



foo.1234; // SyntaxError

foo['1234']; // works

The notations work almost identically, with the only difference being that the

square bracket notation allows for dynamic setting of properties and

the use of property names that would otherwise lead to a syntax error.

Deleting Properties

The only way to remove a property from an object is to use the delete

operator; setting the property to undefined or null only removes the

value associated with the property, but not the key.

var obj = {

    bar: 1,

    foo: 2,

    baz: 3

};

obj.bar = undefined;

obj.foo = null;

delete obj.baz;



for(var i in obj) {

    if (obj.hasOwnProperty(i)) {

        console.log(i, '' + obj[i]);

    }

}

The above outputs both bar undefined and foo null - only baz was

removed and is therefore missing from the output.

Notation of Keys

var test = {

    'case': 'I am a keyword, so I must be notated as a string',

    delete: 'I am a keyword, so me too' // raises SyntaxError

};

Object properties can be both notated as plain characters and as strings. Due to

another mis-design in JavaScript's parser, the above will throw

a SyntaxError prior to ECMAScript 5.

This error arises from the fact that delete is a keyword; therefore, it must be

notated as a string literal to ensure that it will be correctly interpreted by

older JavaScript engines.

The Prototype

JavaScript does not feature a classical inheritance model; instead, it uses a

prototypal one.

While this is often considered to be one of JavaScript's weaknesses, the

prototypal inheritance model is in fact more powerful than the classic model.

It is, for example, fairly trivial to build a classic model on top of a

prototypal model, while the other way around is a far more difficult task.

JavaScript is the only widely used language that features prototypal

inheritance, so it can take time to adjust to the differences between the two

models.

The first major difference is that inheritance in JavaScript uses prototype

chains.

function Foo() {

    this.value = 42;

}

Foo.prototype = {

    method: function() {}

};



function Bar() {}



// Set Bar's prototype to a new instance of Foo

Bar.prototype = new Foo();

Bar.prototype.foo = 'Hello World';



// Make sure to list Bar as the actual constructor

Bar.prototype.constructor = Bar;



var test = new Bar(); // create a new bar instance



// The resulting prototype chain

test [instance of Bar]

    Bar.prototype [instance of Foo]

        { foo: 'Hello World' }

        Foo.prototype

            { method: ... }

            Object.prototype

                { toString: ... /* etc. */ }

In the code above, the object test will inherit from both Bar.prototype and

Foo.prototype; hence, it will have access to the function method that was

defined on Foo. It will also have access to the property value of the

one Foo instance that is its prototype. It is important to note that new

Bar() does not create a new Foo instance, but reuses the one assigned to

its prototype; thus, all Bar instances will share the same value property.

Property Lookup

When accessing the properties of an object, JavaScript will traverse the

prototype chain upwards until it finds a property with the requested name.

If it reaches the top of the chain - namely Object.prototype - and still

hasn't found the specified property, it will return the value

undefined instead.

The Prototype Property

While the prototype property is used by the language to build the prototype

chains, it is still possible to assign any given value to it. However,

primitives will simply get ignored when assigned as a prototype.

function Foo() {}

Foo.prototype = 1; // no effect

Assigning objects, as shown in the example above, will work, and allows for dynamic

creation of prototype chains.

Performance

The lookup time for properties that are high up on the prototype chain can have

a negative impact on performance, and this may be significant in code where

performance is critical. Additionally, trying to access non-existent properties

will always traverse the full prototype chain.

Also, when iterating over the properties of an object

every property that is on the prototype chain will be enumerated.

Extension of Native Prototypes

One mis-feature that is often used is to extend Object.prototype or one of the

other built in prototypes.

This technique is called monkey patching and breaks encapsulation. While

used by popular frameworks such as Prototype, there is still no good

reason for cluttering built-in types with additional non-standard functionality.

The only good reason for extending a built-in prototype is to backport

the features of newer JavaScript engines; for example,

Array.forEach.

In Conclusion

It is essential to understand the prototypal inheritance model before

writing complex code that makes use of it. Also, be aware of the length of the

prototype chains in your code and break them up if necessary to avoid possible

performance problems. Further, the native prototypes should never be

extended unless it is for the sake of compatibility with newer JavaScript

features.

hasOwnProperty

To check whether an object has a property defined on itself and not somewhere

on its prototype chain, it is necessary to use the

hasOwnProperty method which all objects inherit from Object.prototype.

hasOwnProperty is the only thing in JavaScript which deals with properties and

does not traverse the prototype chain.

// Poisoning Object.prototype

Object.prototype.bar = 1;

var foo = {goo: undefined};



foo.bar; // 1

'bar' in foo; // true



foo.hasOwnProperty('bar'); // false

foo.hasOwnProperty('goo'); // true

Only hasOwnProperty will give the correct and expected result; this is

essential when iterating over the properties of any object. There is no other

way to exclude properties that are not defined on the object itself, but

somewhere on its prototype chain.

hasOwnProperty as a Property

JavaScript does not protect the property name hasOwnProperty; thus, if the

possibility exists that an object might have a property with this name, it is

necessary to use an external hasOwnProperty to get correct results.

var foo = {

    hasOwnProperty: function() {

        return false;

    },

    bar: 'Here be dragons'

};



foo.hasOwnProperty('bar'); // always returns false



// Use another Object's hasOwnProperty and call it with 'this' set to foo

({}).hasOwnProperty.call(foo, 'bar'); // true



// It's also possible to use the hasOwnProperty property from the Object property for this purpose

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true

In Conclusion

Using hasOwnProperty is the only reliable method to check for the

existence of a property on an object. It is recommended that hasOwnProperty

is used in every for in loop to avoid errors from

extended native prototypes.

The for in Loop

Just like the in operator, the for in loop traverses the prototype

chain when iterating over the properties of an object.

// Poisoning Object.prototype

Object.prototype.bar = 1;



var foo = {moo: 2};

for(var i in foo) {

    console.log(i); // prints both bar and moo

}

Since it is not possible to change the behavior of the for in loop itself, it

is necessary to filter out the unwanted properties inside the loop body;

this is done using the hasOwnProperty method of

Object.prototype.

Using hasOwnProperty for Filtering

// still the foo from above

for(var i in foo) {

    if (foo.hasOwnProperty(i)) {

        console.log(i);

    }

}

This version is the only correct one to use. Due to the use of hasOwnProperty, it

will only print out moo. When hasOwnProperty is left out, the code is

prone to errors in cases where the native prototypes - e.g. Object.prototype -

have been extended.

One widely used framework that extends Object.prototype is Prototype.

When this framework is included, for in loops that do not use

hasOwnProperty are guaranteed to break.

In Conclusion

It is recommended to always use hasOwnProperty. Assumptions should never

be made about the environment the code is running in, or whether the native

prototypes have been extended or not.

Functions

Function Declarations and Expressions

Functions in JavaScript are first class objects. That means they can be

passed around like any other value. One common use of this feature is to pass

an anonymous function as a callback to another, possibly an asynchronous function.

The function Declaration

function foo() {}

The above function gets hoisted before the execution of the

program starts; thus, it is available everywhere in the scope it was

defined, even if called before the actual definition in the source.

foo(); // Works because foo was created before this code runs

function foo() {}

The function Expression

var foo = function() {};

This example assigns the unnamed and anonymous function to the variable foo.

foo; // 'undefined'

foo(); // this raises a TypeError

var foo = function() {};

Due to the fact that var is a declaration that hoists the variable name foo

before the actual execution of the code starts, foo is already defined when

the script gets executed.

But since assignments only happen at runtime, the value of foo will default

to undefined before the corresponding code is executed.

Named Function Expression

Another special case is the assignment of named functions.

var foo = function bar() {

    bar(); // Works

}

bar(); // ReferenceError

Here, bar is not available in the outer scope, since the function only gets

assigned to foo; however, inside of bar, it is available. This is due to

how name resolution in JavaScript works, the name of the

function is always made available in the local scope of the function itself.

How this Works

JavaScript has a different concept of what the special name this refers to

than most other programming languages. There are exactly five different

ways in which the value of this can be bound in the language.

The Global Scope

this;

When using this in global scope, it will simply refer to the global object.

Calling a Function

foo();

Here, this will again refer to the global object.

Calling a Method

test.foo(); 

In this example, this will refer to test.

Calling a Constructor

new foo(); 

A function call that is preceded by the new keyword acts as

a constructor. Inside the function, this will refer

to a newly created Object.

Explicit Setting of this

function foo(a, b, c) {}



var bar = {};

foo.apply(bar, [1, 2, 3]); // array will expand to the below

foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3

When using the call or apply methods of Function.prototype, the value of

this inside the called function gets explicitly set to the first argument

of the corresponding function call.

As a result, in the above example the method case does not apply, and this

inside of foo will be set to bar.

Common Pitfalls

While most of these cases make sense, the first can be considered another

mis-design of the language because it never has any practical use.

Foo.method = function() {

    function test() {

        // this is set to the global object

    }

    test();

}

A common misconception is that this inside of test refers to Foo; while in

fact, it does not.

In order to gain access to Foo from within test, it is necessary to create a

local variable inside of method that refers to Foo.

Foo.method = function() {

    var that = this;

    function test() {

        // Use that instead of this here

    }

    test();

}

that is just a normal variable name, but it is commonly used for the reference to an

outer this. In combination with closures, it can also

be used to pass this values around.

Assigning Methods

Another thing that does not work in JavaScript is function aliasing, which is

assigning a method to a variable.

var test = someObject.methodTest;

test();

Due to the first case, test now acts like a plain function call; therefore,

this inside it will no longer refer to someObject.

While the late binding of this might seem like a bad idea at first, in

fact, it is what makes prototypal inheritance work.

function Foo() {}

Foo.prototype.method = function() {};



function Bar() {}

Bar.prototype = Foo.prototype;



new Bar().method();

When method gets called on an instance of Bar, this will now refer to that

very instance.

Closures and References

One of JavaScript's most powerful features is the availability of closures.

With closures, scopes always keep access to the outer scope, in which they

were defined. Since the only scoping that JavaScript has is

function scope, all functions, by default, act as closures.

Emulating private variables

function Counter(start) {

    var count = start;

    return {

        increment: function() {

            count++;

        },



        get: function() {

            return count;

        }

    }

}



var foo = Counter(4);

foo.increment();

foo.get(); // 5

Here, Counter returns two closures: the function increment as well as

the function get. Both of these functions keep a reference to the scope of

Counter and, therefore, always keep access to the count variable that was

defined in that scope.

Why Private Variables Work

Since it is not possible to reference or assign scopes in JavaScript, there is

no way of accessing the variable count from the outside. The only way to

interact with it is via the two closures.

var foo = new Counter(4);

foo.hack = function() {

    count = 1337;

};

The above code will not change the variable count in the scope of Counter,

since foo.hack was not defined in that scope. It will instead create - or

override - the global variable count.

Closures Inside Loops

One often made mistake is to use closures inside of loops, as if they were

copying the value of the loop's index variable.

for(var i = 0; i < 10; i++) {

    setTimeout(function() {

        console.log(i);  

    }, 1000);

}

The above will not output the numbers 0 through 9, but will simply print

the number 10 ten times.

The anonymous function keeps a reference to i. At the time

console.log gets called, the for loop has already finished, and the value of

i as been set to 10.

In order to get the desired behavior, it is necessary to create a copy of

the value of i.

Avoiding the Reference Problem

In order to copy the value of the loop's index variable, it is best to use an

anonymous wrapper.

for(var i = 0; i < 10; i++) {

    (function(e) {

        setTimeout(function() {

            console.log(e);  

        }, 1000);

    })(i);

}

The anonymous outer function gets called immediately with i as its first

argument and will receive a copy of the value of i as its parameter e.

The anonymous function that gets passed to setTimeout now has a reference to

e, whose value does not get changed by the loop.

There is another possible way of achieving this, which is to return a function

from the anonymous wrapper that will then have the same behavior as the code

above.

for(var i = 0; i < 10; i++) {

    setTimeout((function(e) {

        return function() {

            console.log(e);

        }

    })(i), 1000)

}

The arguments Object

Every function scope in JavaScript can access the special variable arguments.

This variable holds a list of all the arguments that were passed to the function.

The arguments object is not an Array. While it has some of the

semantics of an array - namely the length property - it does not inherit from

Array.prototype and is in fact an Object.

Due to this, it is not possible to use standard array methods like push,

pop or slice on arguments. While iteration with a plain for loop works

just fine, it is necessary to convert it to a real Array in order to use the

standard Array methods on it.

Converting to an Array

The code below will return a new Array containing all the elements of the

arguments object.

Array.prototype.slice.call(arguments);

Because this conversion is slow, it is not recommended to use it in

performance-critical sections of code.

Passing Arguments

The following is the recommended way of passing arguments from one function to

another.

function foo() {

    bar.apply(null, arguments);

}

function bar(a, b, c) {

    // do stuff here

}

Another trick is to use both call and apply together to create fast, unbound

wrappers.

function Foo() {}



Foo.prototype.method = function(a, b, c) {

    console.log(this, a, b, c);

};



// Create an unbound version of "method" 

// It takes the parameters: this, arg1, arg2...argN

Foo.method = function() {



    // Result: Foo.prototype.method.call(this, arg1, arg2... argN)

    Function.call.apply(Foo.prototype.method, arguments);

};

Formal Parameters and Arguments Indices

The arguments object creates getter and setter functions for both its

properties, as well as the function's formal parameters.

As a result, changing the value of a formal parameter will also change the value

of the corresponding property on the arguments object, and the other way around.

function foo(a, b, c) {

    arguments[0] = 2;

    a; // 2



    b = 4;

    arguments[1]; // 4



    var d = c;

    d = 9;

    c; // 3

}

foo(1, 2, 3);

Performance Myths and Truths

The only time the arguments object is not created is where it is declared as

a name inside of a function or one of its formal parameters. It does not matter

whether it is used or not.

Both getters and setters are always created; thus, using it has nearly

no performance impact at all, especially not in real world code where there is

more than a simple access to the arguments object's properties.

However, there is one case which will drastically reduce the performance in

modern JavaScript engines. That case is the use of arguments.callee.

function foo() {

    arguments.callee; // do something with this function object

    arguments.callee.caller; // and the calling function object

}



function bigLoop() {

    for(var i = 0; i < 100000; i++) {

        foo(); // Would normally be inlined...

    }

}

In the above code, foo can no longer be a subject to inlining since it

needs to know about both itself and its caller. This not only defeats possible

performance gains that would arise from inlining, but it also breaks encapsulation

because the function may now be dependent on a specific calling context.

Making use of arguments.callee or any of its properties is highly discouraged.

Constructors

Constructors in JavaScript are yet again different from many other languages. Any

function call that is preceded by the new keyword acts as a constructor.

Inside the constructor - the called function - the value of this refers to a

newly created object. The prototype of this new

object is set to the prototype of the function object that was invoked as the

constructor.

If the function that was called has no explicit return statement, then it

implicitly returns the value of this - the new object.

function Foo() {

    this.bla = 1;

}



Foo.prototype.test = function() {

    console.log(this.bla);

};



var test = new Foo();

The above calls Foo as constructor and sets the prototype of the newly

created object to Foo.prototype.

In case of an explicit return statement, the function returns the value

specified by that statement, but only if the return value is an Object.

function Bar() {

    return 2;

}

new Bar(); // a new object



function Test() {

    this.value = 2;



    return {

        foo: 1

    };

}

new Test(); // the returned object

When the new keyword is omitted, the function will not return a new object.

function Foo() {

    this.bla = 1; // gets set on the global object

}

Foo(); // undefined

While the above example might still appear to work in some cases, due to the

workings of this in JavaScript, it will use the

global object as the value of this.

Factories

In order to be able to omit the new keyword, the constructor function has to

explicitly return a value.

function Bar() {

    var value = 1;

    return {

        method: function() {

            return value;

        }

    }

}

Bar.prototype = {

    foo: function() {}

};



new Bar();

Bar();

Both calls to Bar return the same thing, a newly create object that

has a property called method, which is a

Closure.

It should also be noted that the call new Bar() does not affect the

prototype of the returned object. While the prototype will be set on the newly

created object, Bar never returns that new object.

In the above example, there is no functional difference between using and

not using the new keyword.

Creating New Objects via Factories

It is often recommended to not use new because forgetting its use may

lead to bugs.

In order to create a new object, one should rather use a factory and construct a

new object inside of that factory.

function Foo() {

    var obj = {};

    obj.value = 'blub';



    var private = 2;

    obj.someMethod = function(value) {

        this.value = value;

    }



    obj.getPrivate = function() {

        return private;

    }

    return obj;

}

While the above is robust against a missing new keyword and certainly makes

the use of private variables easier, it comes with some

downsides.

  1. It uses more memory since the created objects do not share the methods

    on a prototype.

  2. In order to inherit, the factory needs to copy all the methods from another

    object or put that object on the prototype of the new object.

  3. Dropping the prototype chain just because of a left out new keyword

    is contrary to the spirit of the language.

In Conclusion

While omitting the new keyword might lead to bugs, it is certainly not a

reason to drop the use of prototypes altogether. In the end it comes down to

which solution is better suited for the needs of the application. It is

especially important to choose a specific style of object creation and use it

consistently.

Scopes and Namespaces

Although JavaScript deals fine with the syntax of two matching curly

braces for blocks, it does not support block scope; hence, all that is left

in the language is function scope.

function test() { // a scope

    for(var i = 0; i < 10; i++) { // not a scope

        // count

    }

    console.log(i); // 10

}

There are also no distinct namespaces in JavaScript, which means that everything

gets defined in one globally shared namespace.

Each time a variable is referenced, JavaScript will traverse upwards through all

the scopes until it finds it. In the case that it reaches the global scope and

still has not found the requested name, it will raise a ReferenceError.

The Bane of Global Variables

// script A

foo = '42';



// script B

var foo = '42'

The above two scripts do not have the same effect. Script A defines a

variable called foo in the global scope, and script B defines a foo in the

current scope.

Again, that is not at all the same effect: not using var can have major

implications.

// global scope

var foo = 42;

function test() {

    // local scope

    foo = 21;

}

test();

foo; // 21

Leaving out the var statement inside the function test will override the

value of foo. While this might not seem like a big deal at first, having

thousands of lines of JavaScript and not using var will introduce horrible,

hard-to-track-down bugs.

// global scope

var items = [/* some list */];

for(var i = 0; i < 10; i++) {

    subLoop();

}



function subLoop() {

    // scope of subLoop

    for(i = 0; i < 10; i++) { // missing var statement

        // do amazing stuff!

    }

}

The outer loop will terminate after the first call to subLoop, since subLoop

overwrites the global value of i. Using a var for the second for loop would

have easily avoided this error. The var statement should never be left out

unless the desired effect is to affect the outer scope.

Local Variables

The only source for local variables in JavaScript are

function parameters and variables declared via the

var statement.

// global scope

var foo = 1;

var bar = 2;

var i = 2;



function test(i) {

    // local scope of the function test

    i = 5;



    var foo = 3;

    bar = 4;

}

test(10);

While foo and i are local variables inside the scope of the function test,

the assignment of bar will override the global variable with the same name.

Hoisting

JavaScript hoists declarations. This means that both var statements and

function declarations will be moved to the top of their enclosing scope.

bar();

var bar = function() {};

var someValue = 42;



test();

function test(data) {

    if (false) {

        goo = 1;



    } else {

        var goo = 2;

    }

    for(var i = 0; i < 100; i++) {

        var e = data[i];

    }

}

The above code gets transformed before execution starts. JavaScript moves

the var statements, as well as function declarations, to the top of the

nearest surrounding scope.

// var statements got moved here

var bar, someValue; // default to 'undefined'



// the function declaration got moved up too

function test(data) {

    var goo, i, e; // missing block scope moves these here

    if (false) {

        goo = 1;



    } else {

        goo = 2;

    }

    for(i = 0; i < 100; i++) {

        e = data[i];

    }

}



bar(); // fails with a TypeError since bar is still 'undefined'

someValue = 42; // assignments are not affected by hoisting

bar = function() {};



test();

Missing block scoping will not only move var statements out of loops and

their bodies, it will also make the results of certain if constructs

non-intuitive.

In the original code, although the if statement seemed to modify the global

variable goo, it actually modifies the local variable - after hoisting

has been applied.

Without knowledge of hoisting, one might suspect the code below would raise a

ReferenceError.

// check whether SomeImportantThing has been initialized

if (!SomeImportantThing) {

    var SomeImportantThing = {};

}

But of course, this works due to the fact that the var statement is being

moved to the top of the global scope.

var SomeImportantThing;



// other code might initialize SomeImportantThing here, or not



// make sure it's there

if (!SomeImportantThing) {

    SomeImportantThing = {};

}

Name Resolution Order

All scopes in JavaScript, including the global scope, have the special name

this, defined in them, which refers to the current object.

Function scopes also have the name arguments, defined in

them, which contains the arguments that were passed to the function.

For example, when trying to access a variable named foo inside the scope of a

function, JavaScript will look up the name in the following order:

  1. In case there is a var foo statement in the current scope, use that.
  2. If one of the function parameters is named foo, use that.
  3. If the function itself is called foo, use that.
  4. Go to the next outer scope, and start with #1 again.

Namespaces

A common problem associated with having only one global namespace is the

likelihood of running into problems where variable names clash. In JavaScript,

this problem can easily be avoided with the help of anonymous wrappers.

(function() {

    // a self contained "namespace"



    window.foo = function() {

        // an exposed closure

    };



})(); // execute the function immediately

Unnamed functions are considered expressions; so in order to

being callable, they must first be evaluated.

( // evaluate the function inside the parentheses

function() {}

) // and return the function object

() // call the result of the evaluation

There are other ways to evaluate and directly call the function expression

which, while different in syntax, behave the same way.

// A few other styles for directly invoking the 

!function(){}()

+function(){}()

(function(){}());

// and so on...

In Conclusion

It is recommended to always use an anonymous wrapper to encapsulate code in

its own namespace. This does not only protect code against name clashes, but it

also allows for better modularization of programs.

Additionally, the use of global variables is considered bad practice. Any

use of them indicates badly written code that is prone to errors and hard to maintain.

Arrays

Array Iteration and Properties

Although arrays in JavaScript are objects, there are no good reasons to use

the for in loop. In fact, there

are a number of good reasons against the use of for in on arrays.

Because the for in loop enumerates all the properties that are on the prototype

chain and because the only way to exclude those properties is to use

hasOwnProperty, it is already up to twenty times

slower than a normal for loop.

Iteration

In order to achieve the best performance when iterating over arrays, it is best

to use the classic for loop.

var list = [1, 2, 3, 4, 5, ...... 100000000];

for(var i = 0, l = list.length; i < l; i++) {

    console.log(list[i]);

}

There is one extra catch in the above example, which is the caching of the

length of the array via l = list.length.

Although the length property is defined on the array itself, there is still an

overhead for doing the lookup on each iteration of the loop. And while recent

JavaScript engines may apply optimization in this case, there is no way of

telling whether the code will run on one of these newer engines or not.

In fact, leaving out the caching may result in the loop being only half as

fast as with the cached length.

The length Property

While the getter of the length property simply returns the number of

elements that are contained in the array, the setter can be used to

truncate the array.

var foo = [1, 2, 3, 4, 5, 6];

foo.length = 3;

foo; // [1, 2, 3]



foo.length = 6;

foo.push(4);

foo; // [1, 2, 3, undefined, undefined, undefined, 4]

Assigning a smaller length truncates the array. Increasing it creates a sparse array.

In Conclusion

For the best performance, it is recommended to always use the plain for loop

and cache the length property. The use of for in on an array is a sign of

badly written code that is prone to bugs and bad performance.

The Array Constructor

Since the Array constructor is ambiguous in how it deals with its parameters,

it is highly recommended to always use the array literals - [] notation -

when creating new arrays.

[1, 2, 3]; // Result: [1, 2, 3]

new Array(1, 2, 3); // Result: [1, 2, 3]



[3]; // Result: [3]

new Array(3); // Result: []

new Array('3') // Result: ['3']

In cases when there is only one argument passed to the Array constructor

and when that argument is a Number, the constructor will return a new sparse

array with the length property set to the value of the argument. It should be

noted that only the length property of the new array will be set this way;

the actual indexes of the array will not be initialized.

var arr = new Array(3);

arr[1]; // undefined

1 in arr; // false, the index was not set

Being able to set the length of the array in advance is only useful in a few

cases, like repeating a string, in which it avoids the use of a for loop

code.

new Array(count + 1).join(stringToRepeat);

In Conclusion

The use of the Array constructor should be avoided. Literals are definitely

preferred. They are shorter, have a clearer syntax, and increase code

readability.

Types

Equality and Comparisons

JavaScript has two different ways of comparing the values of objects for equality.

The Equality Operator

The equality operator consists of two equal signs: ==

JavaScript features weak typing. This means that the equality operator

coerces types in order to compare them.

""           ==   "0"           // false

0            ==   ""            // true

0            ==   "0"           // true

false        ==   "false"       // false

false        ==   "0"           // true

false        ==   undefined     // false

false        ==   null          // false

null         ==   undefined     // true

" \t\r\n"    ==   0             // true

The above table shows the results of the type coercion, and it is the main reason

why the use of == is widely regarded as bad practice. It introduces

hard-to-track-down bugs due to its complicated conversion rules.

Additionally, there is also a performance impact when type coercion is in play;

for example, a string has to be converted to a number before it can be compared

to another number.

The Strict Equality Operator

The strict equality operator consists of three equal signs: ===.

It works like the normal equality operator, except that strict equality

operator does not perform type coercion between its operands.

""           ===   "0"           // false

0            ===   ""            // false

0            ===   "0"           // false

false        ===   "false"       // false

false        ===   "0"           // false

false        ===   undefined     // false

false        ===   null          // false

null         ===   undefined     // false

" \t\r\n"    ===   0             // false

The above results are a lot clearer and allow for early breakage of code. This

hardens code to a certain degree and also gives performance improvements in case

the operands are of different types.

Comparing Objects

While both == and === are called equality operators, they behave

differently when at least one of their operands is an Object.

{} === {};                   // false

new String('foo') === 'foo'; // false

new Number(10) === 10;       // false

var foo = {};

foo === foo;                 // true

Here, both operators compare for identity and not equality; that is, they

will compare for the same instance of the object, much like is in Python

and pointer comparison in C.

In Conclusion

It is highly recommended to only use the strict equality operator. In cases

where types need to be coerced, it should be done explicitly

and not left to the language's complicated coercion rules.

The typeof Operator

The typeof operator (together with

instanceof) is probably the biggest

design flaw of JavaScript, as it is almost completely broken.

Although instanceof still has limited uses, typeof really has only one

practical use case, which does not happen to be checking the type of an

object.

The JavaScript Type Table

Value               Class      Type

-------------------------------------

"foo"               String     string

new String("foo")   String     object

1.2                 Number     number

new Number(1.2)     Number     object

true                Boolean    boolean

new Boolean(true)   Boolean    object

new Date()          Date       object

new Error()         Error      object

[1,2,3]             Array      object

new Array(1, 2, 3)  Array      object

new Function("")    Function   function

/abc/g              RegExp     object (function in Nitro/V8)

new RegExp("meow")  RegExp     object (function in Nitro/V8)

{}                  Object     object

new Object()        Object     object

In the above table, Type refers to the value that the typeof operator returns.

As can be clearly seen, this value is anything but consistent.

The Class refers to the value of the internal [[Class]] property of an object.

In order to retrieve the value of [[Class]], one has to make use of the

toString method of Object.prototype.

The Class of an Object

The specification gives exactly one way of accessing the [[Class]] value,

with the use of Object.prototype.toString.

function is(type, obj) {

    var clas = Object.prototype.toString.call(obj).slice(8, -1);

    return obj !== undefined && obj !== null && clas === type;

}



is('String', 'test'); // true

is('String', new String('test')); // true

In the above example, Object.prototype.toString gets called with the value of

this being set to the object whose [[Class]] value should be

retrieved.

Testing for Undefined Variables

typeof foo !== 'undefined'

The above will check whether foo was actually declared or not; just

referencing it would result in a ReferenceError. This is the only thing

typeof is actually useful for.

In Conclusion

In order to check the type of an object, it is highly recommended to use

Object.prototype.toString because this is the only reliable way of doing so.

As shown in the above type table, some return values of typeof are not defined

in the specification; thus, they can differ between implementations.

Unless checking whether a variable is defined, typeof should be avoided.

The instanceof Operator

The instanceof operator compares the constructors of its two operands. It is

only useful when comparing custom made objects. Used on built-in types, it is

nearly as useless as the typeof operator.

Comparing Custom Objects

function Foo() {}

function Bar() {}

Bar.prototype = new Foo();



new Bar() instanceof Bar; // true

new Bar() instanceof Foo; // true



// This just sets Bar.prototype to the function object Foo,

// but not to an actual instance of Foo

Bar.prototype = Foo;

new Bar() instanceof Foo; // false

Using instanceof with Native Types

new String('foo') instanceof String; // true

new String('foo') instanceof Object; // true



'foo' instanceof String; // false

'foo' instanceof Object; // false

One important thing to note here is that instanceof does not work on objects

that originate from different JavaScript contexts (e.g. different documents

in a web browser), since their constructors will not be the exact same object.

In Conclusion

The instanceof operator should only be used when dealing with custom made

objects that originate from the same JavaScript context. Just like the

typeof operator, every other use of it should be avoided.

Type Casting

JavaScript is a weakly typed language, so it will apply type coercion

wherever possible.

// These are true

new Number(10) == 10; // Number.toString() is converted

                      // back to a number



10 == '10';           // Strings gets converted to Number

10 == '+10 ';         // More string madness

10 == '010';          // And more 

isNaN(null) == false; // null converts to 0

                      // which of course is not NaN



// These are false

10 == 010;

10 == '-10';

To avoid the issues above, use of the strict equal operator

is highly recommended. Although this avoids a lot of common pitfalls, there

are still many further issues that arise from JavaScript's weak typing system.

Constructors of Built-In Types

The constructors of the built in types like Number and String behave

differently when being used with the new keyword and without it.

new Number(10) === 10;     // False, Object and Number

Number(10) === 10;         // True, Number and Number

new Number(10) + 0 === 10; // True, due to implicit conversion

Using a built-in type like Number as a constructor will create a new Number

object, but leaving out the new keyword will make the Number function behave

like a converter.

In addition, passing literals or non-object values will result in even more

type coercion.

The best option is to cast to one of the three possible types explicitly.

Casting to a String

'' + 10 === '10'; // true

By prepending an empty string, a value can easily be cast to a string.

Casting to a Number

+'10' === 10; // true

Using the unary plus operator, it is possible to cast to a number.

Casting to a Boolean

By using the not operator twice, a value can be converted a boolean.

!!'foo';   // true

!!'';      // false

!!'0';     // true

!!'1';     // true

!!'-1'     // true

!!{};      // true

!!true;    // true

Core

Why Not to Use eval

The eval function will execute a string of JavaScript code in the local scope.

var foo = 1;

function test() {

    var foo = 2;

    eval('foo = 3');

    return foo;

}

test(); // 3

foo; // 1

However, eval only executes in the local scope when it is being called

directly and when the name of the called function is actually eval.

var foo = 1;

function test() {

    var foo = 2;

    var bar = eval;

    bar('foo = 3');

    return foo;

}

test(); // 2

foo; // 3

The use of eval should be avoided. 99.9% of its "uses" can be achieved

without it.

eval in Disguise

The timeout functions setTimeout and setInterval can both

take a string as their first argument. This string will always get executed

in the global scope since eval is not being called directly in that case.

Security Issues

eval also is a security problem, because it executes any code given to it.

It should never be used with strings of unknown or untrusted origins.

In Conclusion

eval should never be used. Any code that makes use of it should be questioned

in its workings, performance and security. If something requires eval in

order to work, it should not be used in the first place. A better design

should be used, that does not require the use of eval.

undefined and null

JavaScript has two distinct values for nothing, null and undefined, with

the latter being more useful.

The Value undefined

undefined is a type with exactly one value: undefined.

The language also defines a global variable that has the value of undefined;

this variable is also called undefined. However, this variable is neither a constant

nor a keyword of the language. This means that its value can be easily

overwritten.

Here are some examples of when the value undefined is returned:

  • Accessing the (unmodified) global variable undefined.
  • Accessing a declared but not yet initialized variable.
  • Implicit returns of functions due to missing return statements.
  • return statements that do not explicitly return anything.
  • Lookups of non-existent properties.
  • Function parameters that do not have any explicit value passed.
  • Anything that has been set to the value of undefined.
  • Any expression in the form of void(expression)

Handling Changes to the Value of undefined

Since the global variable undefined only holds a copy of the actual value of

undefined, assigning a new value to it does not change the value of the

type undefined.

Still, in order to compare something against the value of undefined, it is

necessary to retrieve the value of undefined first.

To protect code against a possible overwritten undefined variable, a common

technique used is to add an additional parameter to an anonymous

wrapper that gets no argument passed to it.

var undefined = 123;

(function(something, foo, undefined) {

    // undefined in the local scope does 

    // now again refer to the value `undefined`



})('Hello World', 42);

Another way to achieve the same effect would be to use a declaration inside the

wrapper.

var undefined = 123;

(function(something, foo) {

    var undefined;

    ...



})('Hello World', 42);

The only difference here is that this version results in 4 more bytes being

used in case it is minified, and there is no other var statement inside the

anonymous wrapper.

Uses of null

While undefined in the context of the JavaScript language is mostly used in

the sense of a traditional null, the actual null (both a literal and a type)

is more or less just another data type.

It is used in some JavaScript internals (like declaring the end of the

prototype chain by setting Foo.prototype = null), but in almost all cases, it

can be replaced by undefined.

Automatic Semicolon Insertion

Although JavaScript has C style syntax, it does not enforce the use of

semicolons in the source code, so it is possible to omit them.

JavaScript is not a semicolon-less language. In fact, it needs the

semicolons in order to understand the source code. Therefore, the JavaScript

parser automatically inserts them whenever it encounters a parse

error due to a missing semicolon.

var foo = function() {

} // parse error, semicolon expected

test()

Insertion happens, and the parser tries again.

var foo = function() {

}; // no error, parser continues

test()

The automatic insertion of semicolon is considered to be one of biggest

design flaws in the language because it can change the behavior of code.

How it Works

The code below has no semicolons in it, so it is up to the parser to decide where

to insert them.

(function(window, undefined) {

    function test(options) {

        log('testing!')



        (options.list || []).forEach(function(i) {



        })



        options.value.test(

            'long string to pass here',

            'and another long string to pass'

        )



        return

        {

            foo: function() {}

        }

    }

    window.test = test



})(window)



(function(window) {

    window.someLibrary = {}



})(window)

Below is the result of the parser's "guessing" game.

(function(window, undefined) {

    function test(options) {



        // Not inserted, lines got merged

        log('testing!')(options.list || []).forEach(function(i) {



        }); // <- inserted



        options.value.test(

            'long string to pass here',

            'and another long string to pass'

        ); // <- inserted



        return; // <- inserted, breaks the return statement

        { // treated as a block



            // a label and a single expression statement

            foo: function() {} 

        }; // <- inserted

    }

    window.test = test; // <- inserted



// The lines got merged again

})(window)(function(window) {

    window.someLibrary = {}; // <- inserted



})(window); //<- inserted

The parser drastically changed the behavior of the code above. In certain cases,

it does the wrong thing.

Leading Parenthesis

In case of a leading parenthesis, the parser will not insert a semicolon.

log('testing!')

(options.list || []).forEach(function(i) {})

This code gets transformed into one line.

log('testing!')(options.list || []).forEach(function(i) {})

Chances are very high that log does not return a function; therefore,

the above will yield a TypeError stating that undefined is not a function.

In Conclusion

It is highly recommended to never omit semicolons. It is also recommended

that braces be kept on the same line as their corresponding statements and to

never omit them for single-line if / else statements. These measures will

not only improve the consistency of the code, but they will also prevent the

JavaScript parser from changing code behavior.

The delete Operator

In short, it's impossible to delete global variables, functions and some other

stuff in JavaScript which have a DontDelete attribute set.

Global code and Function code

When a variable or a function is defined in a global or a function

scope it is a property of either the Activation object or

the Global object. Such properties have a set of attributes, one of which is

DontDelete. Variable and function declarations in global and function code

always create properties with DontDelete, and therefore cannot be deleted.

// global variable:

var a = 1; // DontDelete is set

delete a; // false

a; // 1



// normal function:

function f() {} // DontDelete is set

delete f; // false

typeof f; // "function"



// reassigning doesn't help:

f = 1;

delete f; // false

f; // 1

Explicit properties

Explicitly set properties can be deleted normally.

// explicitly set property:

var obj = {x: 1};

obj.y = 2;

delete obj.x; // true

delete obj.y; // true

obj.x; // undefined

obj.y; // undefined

In the example above, obj.x and obj.y can be deleted because they have no

DontDelete atribute. That's why the example below works too.

// this works fine, except for IE:

var GLOBAL_OBJECT = this;

GLOBAL_OBJECT.a = 1;

a === GLOBAL_OBJECT.a; // true - just a global var

delete GLOBAL_OBJECT.a; // true

GLOBAL_OBJECT.a; // undefined

Here we use a trick to delete a. this here refers

to the Global object and we explicitly declare variable a as its property

which allows us to delete it.

IE (at least 6-8) has some bugs, so the code above doesn't work.

Function arguments and built-ins

Functions' normal arguments, arguments objects

and built-in properties also have DontDelete set.

// function arguments and properties:

(function (x) {



  delete arguments; // false

  typeof arguments; // "object"



  delete x; // false

  x; // 1



  function f(){}

  delete f.length; // false

  typeof f.length; // "number"



})(1);

Host objects

The behaviour of delete operator can be unpredictable for hosted objects. Due

to the specification, host objects are allowed to implement any kind of behavior.

In conclusion

The delete operator often has unexpected behaviour and can only be safely

used to delete explicitly set properties on normal objects.

Other

setTimeout and setInterval

Since JavaScript is asynchronous, it is possible to schedule the execution of a

function using the setTimeout and setInterval functions.

function foo() {}

var id = setTimeout(foo, 1000); // returns a Number > 0

When setTimeout is called, it returns the ID of the timeout and schedule

foo to run approximately one thousand milliseconds in the future.

foo will then be executed once.

Depending on the timer resolution of the JavaScript engine running the code, as

well as the fact that JavaScript is single threaded and other code that gets

executed might block the thread, it is by no means a safe bet that one will

get the exact delay specified in the setTimeout call.

The function that was passed as the first parameter will get called by the

global object, which means that this inside the called function

refers to the global object.

function Foo() {

    this.value = 42;

    this.method = function() {

        // this refers to the global object

        console.log(this.value); // will log undefined

    };

    setTimeout(this.method, 500);

}

new Foo();

Stacking Calls with setInterval

While setTimeout only runs the function once, setInterval - as the name

suggests - will execute the function every X milliseconds, but its use is

discouraged.

When code that is being executed blocks the timeout call, setInterval will

still issue more calls to the specified function. This can, especially with small

intervals, result in function calls stacking up.

function foo(){

    // something that blocks for 1 second

}

setInterval(foo, 1000);

In the above code, foo will get called once and will then block for one second.

While foo blocks the code, setInterval will still schedule further calls to

it. Now, when foo has finished, there will already be ten further calls to

it waiting for execution.

Dealing with Possible Blocking Code

The easiest solution, as well as most controllable solution, is to use setTimeout within

the function itself.

function foo(){

    // something that blocks for 1 second

    setTimeout(foo, 1000);

}

foo();

Not only does this encapsulate the setTimeout call, but it also prevents the

stacking of calls and gives additional control. foo itself can now decide

whether it wants to run again or not.

Manually Clearing Timeouts

Clearing timeouts and intervals works by passing the respective ID to

clearTimeout or clearInterval, depending on which set function was used

in the first place.

var id = setTimeout(foo, 1000);

clearTimeout(id);

Clearing All Timeouts

As there is no built-in method for clearing all timeouts and/or intervals,

it is necessary to use brute force in order to achieve this functionality.

// clear "all" timeouts

for(var i = 1; i < 1000; i++) {

    clearTimeout(i);

}

But there might still be timeouts that are unaffected by this arbitrary number.

Another way of doing this is to consider that the ID given to a timeout is

incremented by one every time you call setTimeout.

// clear "all" timeouts

var biggestTimeoutId = window.setTimeout(function(){}, 1),

i;

for(i = 1; i <= biggestTimeoutId; i++) {

    clearTimeout(i);

}

Even though this works on all major browsers today, it isn't specified that

the IDs should be ordered that way and it may change. Therefore, it is instead

recommended to keep track of all the timeout IDs, so they can be cleared

specifically.

Hidden Use of eval

setTimeout and setInterval can also take a string as their first parameter.

This feature should never be used because it internally makes use of eval.

function foo() {

    // will get called

}



function bar() {

    function foo() {

        // never gets called

    }

    setTimeout('foo()', 1000);

}

bar();

Since eval is not getting called directly in this case, the string

passed to setTimeout will be executed in the global scope; thus, it will

not use the local variable foo from the scope of bar.

It is further recommended to not use a string to pass arguments to the

function that will get called by either of the timeout functions.

function foo(a, b, c) {}



// NEVER use this

setTimeout('foo(1, 2, 3)', 1000)



// Instead use an anonymous function

setTimeout(function() {

    foo(a, b, c);

}, 1000)

In Conclusion

A string should never be used as the parameter of setTimeout or

setInterval. It is a clear sign of really bad code, when arguments need

to be supplied to the function that gets called. An anonymous function should

be passed that then takes care of the actual call.

Furthermore, the use of setInterval should be avoided because its scheduler is not

blocked by executing JavaScript.

Leave a Comment