Three JavaScript Quirks That Java/C Developers Should Know

JavaScript can be a deceiving language and it can be a real pain because it isn’t 100% consistent. As it’s well known it does have bad parts, confusing or redundant features that should be avoided: the infamous with statement, implicit global variables and comparison erratic behavior are probably the best known.

JavaScript is one of the most successful flames generator in history! Besides the flaws it has (which are, in part, addressed in the new ECMAScript specifications), most programmers hate JavaScript for 2 reasons:

  • The DOM, which they erroneously think is equivalent to the JavaScript language, which has quite a terrible API.
  • They come to JavaScript from languages like C and Java. They are fooled by JavaScript’s syntax into believing that it works the same way as those imperative languages do. This misconception will lead to confusion, frustration, and bugs.

That’s why, generally, JavaScript has a worse reputation than it deserves.

--ADVERTISEMENT--

During my career, I noticed a few patterns: language features most developers with a Java or C/C++ background assume to be identical in JavaScript, while they are completely different.

This article gathers the most troublesome ones, comparing the Java-way to the JavaScript-way to shown differences and highlight best practices in JavaScript.

Scoping

Most developers start working on JavaScript because they are forced, and almost every of them start writing code before taking a moment to learn the language. Every such developer has been tricked by JavaScript scope at least once.

Because JavaScript’s syntax closely resembles (on purpose) C-family languages, with curly braces delimiting function‘s, if‘s and for‘s bodies, one would reasonably expect lexical block-level scope. Unfortunately, this is not the case.

First, in JavaScript variable scope is determined by functions, not by brackets. In other words, if and for bodies don’t create a new scope, and a variable declared inside their bodies is actually hoisted, i.e. created at the beginning of the innermost function in which it is declared, or of the global scope otherwise.

Second, the presence of the with statement forces JavaScript scoping to be dynamic, impossible to determine until runtime. You might not be surprised to hear that the use of the with statement is deprecated: JavaScript stripped of with would actually be a lexically scoped language, i.e. the scope could be completely determined by looking at the code.

Formally, in JavaScript there are four ways for a name to enter a scope:

  • Language-defined: by default all scopes contains the names this and arguments.
  • Formal parameters: any (formal) parameters declared for a function is scoped to the body of that function.
  • Function declarations.
  • Variable declarations.

One further complication is caused by the implicit global scoping assigned to variables declared (implicitly) without the var keyword. This madness pairs with the implicit assignment of the global scope to this reference when functions are called without an explicit bind (more on this in next sections).

Before delving into the details, let’s clearly state the good pattern that can be used to avoid confusion:

Use strict mode ('use strict';), and move all variables and functions declaration at the top of each function; avoid variables declaration inside for and if blocks, as well as function declarations inside those blocks (for different reasons, that goes beyond the scope of this article).

Hoisting

Hoisting is a simplification that is used to explain the actual behavior of declarations. Hoisted variables are declared at the very beginning of the function containing them, and initialized to undefined. Then assignment takes place in the actual line where the original declaration was.

Take a look at the following example:

function myFunction() {
  console.log(i);
  var i = 0;
  console.log(i);
  if (true) {
    var i = 5;
    console.log(i);
  }
  console.log(i);
}

What values do you expect to be printed to the console? Would you be surprised to the following output?

undefined
0
5
5

Inside the if block, the var statement doesn’t declare a local copy of the variable i, but rather overwrites the one declared before. Notice that the first console.log statement prints the actual value of variable i, which is initialized to undefined. You can test it by using the "use strict"; directive as the first line in the function. In strict mode variables must be declared before being used, but you can check that JavaScript engine won’t complain for the declaration. On a side note, be aware that you will get no complain for redeclaring a var: if you want to catch such bugs, you should better process your code with a linter such JSHint or JSLint.

Let’s now see one more example to highlight another error-prone use of variable declarations:

var notNull = 1;
function test() {
  if (!notNull) {
    console.log("Null-ish, so far", notNull);
    for(var notNull = 10; notNull <= 0; notNull++){
      //..
    }
    console.log("Now it's not null", notNull);
  }
  console.log(notNull);
}

Despite you might expect differently, the if body is executed because a local copy of a variable named notNull is declared inside the test() function, and it is hoisted. Type coercion also plays a role here.

Function Declarations vs Function Expressions

Hoisting doesn’t apply to variables only, function expressions, which are variables to all intents and purposes, and function declarations are hoisted as well. This topic needs to be treated with way more care than I’ll do here, but in short function declarations behaves mostly as function expressions, except that their declarations are moved to the beginning of their scope.

Consider the following example showing the behavior of a function declaration:

function foo() {
    // A function declaration
    function bar() {
        return 3;
    }
    return bar();

    // This function declaration will be hoisted and overwrite the previous one
    function bar() {
        return 8;
    }
}

Now, compare it with this example that shows the behavior of a function expression:

function foo() {
    // A function expression
    var bar = function() {
        return 3;
    };
    return bar();

    // The variable bar already exists, and this code will never be reached
    var bar = function() {
        return 8;
    };
}

See the references section for further insight on these concepts.

With

The following example shows a situation where scoping can only be determined at runtime:

function foo(y) {
  var x = 123;
  with(y) {
    return x;
  }
}

If y has a field named x, then function foo() will return y.x, otherwise it will return 123. This coding practice is a possible source of runtime errors, hence it’s highly recommended that you avoid using the with statement.

Looking at the Future: ECMAScript 6

ECMAScript 6 specifications will add a fifth way to add block-level scoping: the let statement. Consider the code below:

function myFunction() {
  console.log(i);
  var i = 0;
  console.log(i);
  if (false) {
    let i = 5;
    console.log(i);
  }
  console.log(i);
}

In ECMAScript 6, declaring i with let inside the body of the if will create a new variable local to the if block. As a non-standard alternative, it’s possible to declare let blocks as follows:

var i = 6;
let (i = 0, j = 2) {
  /* Other code here */
}
// prints 6
console.log(i);

In the code above, the variables i and j will exist only inside the block. At the time of writing, the support for let is limited, even for Chrome.

Scope in a Nutshell

The next table summarizes the scope in different languages:

Feature Java Python JavaScript Warnings
Scope Lexical (block) Lexical (function, class or module) Yes It works very differently from Java or C
Block scope Yes No `let` keyword (ES6) Again, warning: this is not Java!
Hoisting No way! No Yes For variables and function expressions, only declaration is hoisted. For function declarations, the definition is hoisted as well

Functions

Another very misunderstood feature of JavaScript are functions, especially because in imperative programming languages like Java there is no such a concept as a function.

As a matter of facts, JavaScript is a functional programming language. Well, not a pure functional programming language as Haskell – after all it still has an imperative style, and mutability is encouraged rather than simply allowed, as for Scala. Nevertheless JavaScript could be used as a purely functional programming language, with function calls deprived of any side effect.

First-Class Citizens

Functions in JavaScript can be treated like any other type, for example String and Number: they can be stored in variables, passed as arguments to functions, returned by functions, and stored in arrays. Functions can also have properties and can be changed dynamically and that’s because…

Objects

One very surprising fact, for most JavaScript newbies, is that functions are actually objects. In JavaScript every function is actually a Function object. The Function constructor creates a new Function object:

var func = new Function(['a', 'b', 'c'], '');

This is (almost) equivalent to:

function func(a, b, c) { }

I said they are almost equivalent because using the Function constructor is less efficient, produces an anonymous function, and do not create a closure to its creation context. Function objects are always created in the global scope.

Function, the type of functions, is built upon Object. This can be easily seen by inspecting any function you declare:

function test() {}
//  prints  "object"
console.log(typeof test.prototype);
//  prints  function Function() { [native code] }
console.log(test.constructor);

This means that functions may and do have properties. Some of them are assigned to the functions on creation like name or length. These properties return the name and number of arguments in the function definition respectively.

Consider the following example:

function func(a, b, c) { }
//  prints "func"
console.log(func.name);
//  prints 3
console.log(func.length);

But you can even set new properties for any function by yourself:

function test() {
  console.log(test.custom);
}
test.custom = 123;
//  prints 123
test();

Functions in a Nutshell

The following table describes functions in Java, Python, and JavaScript:

Feature Java Python JavaScript Warnings
Functions as built-in types Lambdas, Java 8 Yes Yes
Callbacks / Command Pattern Objects (or lambdas for Java 8) Yes Yes Functions (callbacks) have properties that can be modified by the “client”
Dynamic creation No No `eval` – `Function` object `eval` has security concerns and `Function` objects might work unexpectedly
Properties No No Can have properties Access to function’s properties can’t be restricted

Closures

If I had to choose my favorite JavaScript feature, I’d go for closures, no doubt. JavaScript was the first mainstream programming language to introduce closures. As you might know, Java and Python have had a weakened version of closures for a long time, where you could only read (some) values from enclosing scopes.

In Java, for instance, anonymous inner class provides closure-like functionality with some restrictions. For example, only final local variables can be used in their scope – better said, their values can be read.

JavaScript allows full access to the outer scope variables and functions. They can be read, written, and if needed even hidden by local definitions: you can see examples of all these situations in the “Scoping” section.

Even more interesting, a function created in a closure remembers the environment in which it was created. By combining closures and function nesting, you can have outer functions returning inner functions without executing them. Besides, you can have local variables of the outer function surviving in the closure of the inner one long after the execution of the function in which they are declared has ended. This is a very powerful feature but it has also its drawback as it’s a common cause of memory leaks in JavaScript applications.

A few examples will clarify these concepts:

function makeCounter () {
  var i = 0;

  return function displayCounter () {
    console.log(++i);
  };
}
var counter = makeCounter();
//  prints 1
counter();
//  prints 2
counter();

The makeCounter() function above creates and returns another function that keeps track of the environment in which it’s created. Although the execution of makeCounter() is over when the variable counter is assigned, the local variable i is kept in displayCounter‘s closure, and can be therefore accessed inside its body.

If we were to run makeCounter again, it would create a new closure, with a different entry for i:

var counterBis = makeCounter();
//  prints 1
counterBis();
//  prints 3
counter();
//  prints 2
counterBis();

To make it a bit more interesting, we could update the makeCounter() function so that it takes an argument:

function makeCounter(i) {
  return function displayCounter () {
    console.log(++i);
  };
}
var counter = makeCounter(10);
//  prints 11
counter();
//  prints 12
counter();

Outer function arguments are kept in the closure as well, so we don’t need to declare a local variable this time. Every call to makeCounter() will remember the initial value we set, and count on.

Closures are paramount for many fundamental JavaScript patterns: namespacing, module, private vars, memoization are just the best known.

As an example, let’s see how we can simulate a private variable for an object:

function Person(name) {
  return {
    setName: function(newName) {
      if (typeof newName === 'string' && newName.length > 0) {
        name = newName;
      } else {
        throw new TypeError("Not a valid name");
      }
    },
    getName: function () {
      return name;
    }
  };
}

var p = Person("Marcello");

// prints "Marcello"
a.getName();

// Uncaught TypeError: Not a valid name
a.setName();

// Uncaught TypeError: Not a valid name
a.setName(2);
a.setName("2");

// prints "2"
a.getName();

With this pattern, exploiting closures, we can create a wrapper for a property name, with our own setter and getter. ES5 made this a lot easier, since you can create objects with getters and setters for their properties, and control access to the properties themselves at the finest grain.

Closures in a Nutshell

The following table describes closure in Java, Python, and JavaScript:

Feature Java Python JavaScript Warnings
Closure Weakened, read-only, in anonymous inner classes Weakened, read-only, in nested def Yes Memory leaks
Memoization Pattern Must use shared objects Possible using lists or dictionaries Yes Better use lazy evaluation
Namespace/Module Pattern Not needed Not needed Yes
Private Attributes Pattern Not needed Not possible Yes Might get confusing

Conclusion

In this article I covered three features of JavaScript that are often misunderstood by developers coming from different languages, especially Java and C. In particular, we’ve discussed concepts as scoping, hosting, functions, and closures. In case you want to study in deep these topics, here is a list of articles you can read:


Replies

  1. Just another JS article

    Congratulations, You have just added another article to the interwebz that shows how mis-understood JavaScript is. Not because you showcase any knowledge at all ofcourse. Your examples are wrong (did you even bother checking them?) and I think you didn't even take the time to look up anything at all about the language.

    A bad start:

    Your first example is wrong. It does not output 'undefined, 0 5 5'. It does however output ' undefined 0 0'. This because thx to hoisting the proper equivalent is this:

    function myFunction() { 
      var i = undefined; //the compiler is smart enough to know we don't need to define i twice
      console.log(i);  //undefined
      i = 0; //simple assignment
      console.log(i); // 0
      if (false) { //the following if block is never executed
        i = 5;
        console.log(i);
      } 
      console.log(i); //0 since id did not change
    }

    Prototype, functional, potatoe, potato, whatever

    You state that JavaScript is a functional language, kind of. Not really, it looks like one. So lets call it one. Or whatever.. Why force it to be anything else than what is really is? Why even try. It's a prototype based language, and that is really powerful!

    You also state a few lines later that function is a primitive. But it's also an object. These two statements do not go well together. A quick fact checking on mdn would give us the following primitives:

    • string
    • number
    • Boolean
    • null
    • undefined

    The mdn article also talks about primitive Wrappers. Objects that wrap around a primitive. This explains the behavior:

    typeof new Number(5); //Object
    typeof 5; //number

    Strange use of language

    Normally, in computer science, we use words like 'is a'. You don't, you say

    Function, the type of functions, is built upon Object

    Not sure what you mean here, simply put. A Function is an Object. This because it is not a primitive. You then go on to 'prove' this by doing a typeof function.prototype . Not sure what your point here is. You have proven that the prototype is an object. Wow.

    You also state that functions (can) have properties. Not sure if this is such a special thing, it's an object...

    And to explain closures, the following sentence does that really well: (taken from crockfords website)

    An inner function always has access to the vars and parameters
    of its outer function, even after the outer function has returned.

    Examples should explain

    You end the article with some examples, not sure what they should prove. Your Person function is a factory-like function that returns an object that has access to a passed in variable 'thanks to' scope, closure, whatever. This doesn't make the variable private, It just makes the variable a memory-leak. The variable also has nothing to do with the object. The object consists simply of 2 functions that have access to a non-local variable. Your point? Personally, if you want to show how to create an object with private vars, use privileged functions:

    function Person(name) {
      var privateName = name; //don't touch me
      
      //define privileged functions:
      this.getName = function() {
        return privateName;
      }
    
      this.setName = function(name) {
        privateName = name;
      } 
    }
    
    var myPerson = new Person('foo'); //using new is so much cooler
    myPerson.getName(); //foo
    myPerson.privateName; //undefined

    For people who would like to have a good read on scope and stuff: crockford

    EDIT: I just can't resist. You talk about JS being the first 'mainstream' language to implement closures. this shows that you or, have no idea what closures are, or with mainstream, you mean: 'that I know'. The fist language implementing closures was somewhere around 1970 (if I remember correct). I wasn't even born then...

    Kind regards,
    A sad reader

  2. I did not understand this one as well. I can't get the same output even when using "use strict";

  3. Unfortunately there is a typo,
    if (false) was supposed to be if (true)
    Apologies!

  4. Hi,
    thanks for your valuable and polite feedback.

    You are right about the first example, there is a typo: if (false) was supposed to be if (true) on line 6.
    Although you are also right it is not acceptable, unfortunately typos and errors happens.
    Thanks for catching it and adding a walkthrough through the function, that I'm sure will help readers.

    About your last example, using that syntax (creating an object with a constructor) is a perfectly valid alternative.
    Your example, however, is error prone, because if Person is called without new in front of it, undefined will be returned - which is the main turn off for constructors.
    This is easily solved, though:

    function Person(name) {
      if (!(this instanceof Person)) {
        return new Person(name);
      }
      
      //define privileged functions:
      this.getName = function() {
        return name;
      }
    
      this.setName = function(newName) {
        name = newName;
      } 
    }
    
    var myPerson = Person('foo'); //now works even without new

    By the way, you don't really need to declare another privateName var, since you can just use the argument to the constructor, which will as well captured in the get and set functions' closures.

    I think you are making a bit of confused about the term "mainstream".
    I never claimed that JavaScript invented closures, but you can hardly say that Scheme was ever a mainstream language, while JavaScript is the first language having closures that is widely adopted.
    But you don't have to take my word on that, you seems to have enough confidence in Douglas Crockford to take his (browse a bit through his videos, will you?, and you'll find those exact same words).

    Speaking of Crockford, thanks for the extra pointers, they will certainly be a wonderful reading/listening that I strongly suggest to every one.

    Have a very nice day

  5. My example is not error-prone. You just don't understand functions.

    this is not personal, if you feel it is a personal rant, it is not. It is just a frustrated dude who thinks he is the next #worldDominator vomiting words into a textbox.

    I should advice everyone to look up your blog (I think it is yours) and read up on the really strong articles you have (I really mean this. I really like the topics you are addressing there and they are really well explained).

    I think it is also safe to say that the examples you are using in this article are bad.. They do to much, using type-coercion in an example of hoisting simply adds to the confusion. That same example in fact demonstrates that hoisting really is: moving a var statement to the top of the function block. You should emphasize that.

    I am also not at all convinced of your JS-knowledge, but it is hard to say something about that from one article - or comment.

    Default return values

    Functions always return a value. Always. If no return; is used, then the default value returned is undefined. If you use the new keyword, the default value returned is this.

    Writing:

    function Person() {};
    var p = new Person();

    Is the same as:

    function Person() { return this; }
    var p = Person();

    Using your approach doesn't really fix anything, unless developer laziness counts as a problem that should be solved with code. Even worse, it helps writing hard-to-read code. We have a keyword to help us, so let's use it.

    And no, I don't need to declare my privateName in my example. But think of code-readability. Think of variables that are not passed in in the constructor. Think of creating a clean example that shows one thing and one thing only. My example is used to illustrate how to create private variables with public getters and setters.

    Hoisting, var, function and var function

    You kind of make a point, but kind of miss the point as well when you talk about hoisting and stuff. In JavaScript all variables and function declarations are hoisted, simply put (as you correctly state) they are moved to the top of the current function block.

    function foo() {
      console.log(a); //undefined
      var a = 5;
    }
    foo();

    Is actually parsed as:

    function foo() {
      var a;
      console.log(a); //undefined
      a = 5;
    }
    foo();//after the function exits, a is garbage collected since we no longer reference it
    
    

    But what happens if we forget to declare our variable all together?

    function foo() {
      console.log(a); //undefined
      a = 5;
    }
    foo();

    This roughly translates to:

    var a;
    function foo() {
      console.log(a); //undefined
      a = 5;
    }
    foo();

    Our variable a is declared globally, not because it is hoisted, but simply because we forgot to declare it, and so JavaScript declares it globally for us, the true friend he is.
    And we now can no longer garbage collect our variable because it is global.

    Then there is the difference between function declaration and function expression/statement. The first is hoisted, the latter not. But why is it hoisted? this has to with execution time. The JS-engine first parses our codezz and creates the execution context. This means declaring variables (and thus hosting them), parsing function declarations, ... The next phase is execution. He simple walks over line by line and executes it.

    //this is evaluated on execution-time
    foo();
    
    //the named function is created on parse-time, and thus hoisted
    function foo() {
      console.log('foobar');
    }

    The following however will not work:

    foo();
    var foo = function foo() {console.log('foobar');}

    This because it translates to:

    var foo; //the declaration of our variable is hoisted
    foo(); //but it is still undefined here
    foo = function foo() {console.log('foobar');} //here we assign a function expression to the variable.

    Our function expression is only parsed on execution-time instead of parse time. #confusion <- this hashtag exists purely for JavaScript

11 more replies