Javascript vs Java

JS vs Java

Good article with JS vs Java

Objects only - no Classes

JS is OOO, but there are no classes (although new Ecmascript 6 will add it).

// create an empty object - no class was needed !!
var superhero = {};
 
superhero.name = 'Superman';  
superhero.strength = 100;

Javascript objects are just like a Java HashMap of related properties, where the keys are Strings only. The following would be the 'equivalent' Java code:

Map<String,Object> superhero = new HashMap<>();
 
superhero.put("name","Superman");  
superhero.put("strength", 100);

This means that a Javascript object is just a multi-level 'hash map' of key/value pairs, with no class definition needed.

Functions Are Just Values

Functions in Javascript are just values of type Function, it's a simple as that!

var flyFunction = function() {  
    console.log('Flying like a bird!');
};
 
superhero.fly = flyFunction;

// prints 'Flying like a bird!' to the console
superhero.fly();

Somehow it may be represented in Java as:

public interface Power {  
    void use();
}
 
public class SuperHero {
 
    private Power flyPower;
 
    public void setFly(Power flyPower) {
        this.flyPower = flyPower;
    }
 
    public void fly() {
        flyPower.use();
    }
}

// Java 8 equivalent 
superman.setFly(  
    ()->System.out.println("Flying like a bird ..."));
 
superman.fly();

The 'this' Keyword Usage

What Javascript allows to do with this is quite surprising compared to the Java world.

var superman = {
 
  heroName: 'Superman',  
 
  sayHello: function() {
      console.log("Hello, I'm " + this.heroName );
  }  
};
 
superman.sayHello();  

This program creates an object superman with two properties: a String heroName and a Function named sayHello. Running this program outputs as expected Hello, I'm Superman.

What if we pass the function around?

By passing around sayHello, we can easily end up in a context where there is no heroName property:

var failThis = superman.sayHello;
 
failThis();

Running this snippet would give as output: Hello, I'm undefined.

Why does 'this' not work anymore?

This is because the variable failThis belongs to the global scope, which contains no member variable named heroName. To solve this:

In Javascript the value of the this keyword is completely overridable to be anything that we want!

// overrides 'this' with superman. (I do not get this example)
hello.call(superman);  

The snippet above would print again Hello, I'm Superman. This means that the value of this depends on both the context on which the function is called, and on how the function is called.

Classic vs Prototypal Inheritance

In Javascript, there is no class inheritance, instead objects can inherit directly from other objects. The way this works is that each object has an implicit property that points to a 'parent' object.

That property is called __proto__, and the parent object is called the object's prototype, hence the name Prototypal Inheritance.

How does prototype work?

When looking up a property, Javascript will try to find the property in the object itself. If it does not find it then it tries in it's prototype, and so on.

var avengersHero = {  
    editor: 'Marvel'
};
 
var ironMan = {};
 
ironMan.__proto__ = avengersHero;
 
console.log('Iron Man is copyrighted by ' + ironMan.editor);

This snippet will output Iron Man is copyrighted by Marvel.

As we can see, although the ironMan object is empty, it's prototype does contain the property editor, which get's found.

How does this compare with Java inheritance?

Let's now say that the rights for the Avengers where bought by DC Comics:

avengersHero.editor = 'DC Comics';

If we call ironMan.editor again, we now get Iron Man is copyrighted by DC Comics. All the existing object instances with the avengersHero prototype now see DC Comics without having to be recreated.

This mechanism is very simple and very powerful. Anything that can be done with class inheritance can be done with prototypal inheritance. But what about constructors?

Constructors vs Constructor Functions

In Javascript an attempt was made to make object creation similar to languages like Java.

function SuperHero(name, strength) {  
    this.name = name;
    this.strength = strength;
}

Notice the capitalized name, indicating that it's a constructor function. Let's see how it can be used:

var superman = new SuperHero('Superman', 100);
 
console.log('Hello, my name is ' + superman.name); 

This code snippet outputs Hello, my name is Superman.

You might think that this looks just like Java, and that is exactly the point! What this new syntax really does is to it creates a new empty object, and then calls the constructor function by forcing this to be the newly created object.

Why is this syntax not recommended then?

Let's say that we want to specify that all super heroes have a sayHello method. This could be done by putting the sayHello function in a common prototype object:

function SuperHero(name, strength) {  
    this.name = name;
    this.strength = strength;
}
 
SuperHero.prototype.sayHello = function() {  
    console.log('Hello, my name is ' + this.name);
}
 
var superman = new SuperHero('Superman', 100);  
superman.sayHello(); 

This would output Hello, my name is Superman.

But the syntax SuperHero.prototype.sayHello looks anything but Java like! The new operator mechanism sort of half looks like Java but at the same time is completely different.

Is there a recommended alternative to new?

The recommended way to go is to ignore the Javascript new operator altogether and use Object.create:

var superHeroPrototype = {  
   sayHello: function() {
        console.log('Hello, my name is ' + this.name);
    } 
};
 
var superman = Object.create(superHeroPrototype);  
superman.name = 'Superman';

Unlike the new operator, one thing that Javascript absolutely got right were Closures.

Closures vs Lambdas

Javascript Closures are not that different from Java anonymous inner classes used in a certain way.

public interface FlyCommand {  
    public void fly();
}
 
public class FlyingHero {
 
    private String name;
 
    public FlyingHero(String name) {
        this.name = name;
    }
 
    public void fly(FlyCommand flyCommand) {
        flyCommand.fly();
    }
}

// usage
String destination = "Mars";  
superMan.fly(() -> System.out.println("Flying to " + destination ));

The output of this snippet is Flying to Mars. Notice that the FlyCommand lambda had to 'remember' the variable destination, because it needs it for executing the fly method later.

This notion of a function that remembers about variables outside it's block scope for later use is called a Closure in Javascript.

What is the main difference between Lambdas and Closures?

In Javascript a closure looks like this:

var destination = 'Mars';
 
var fly = function() {  
    console.log('Fly to ' + destination);
}
 
fly();

The Javascript closure, unlike the Java Lambda does not have the constraint that the destination variable must be immutable (or effectively immutable since Java 8).

This difference is actually a 'killer' feature of Javascript closures, because it allows them to be used for creating encapsulated modules.

Modules and Encapsulation

There are no classes in Javascript and no public/ private modifiers, but then again take a look at this:

function createHero(heroName) {
 
    var name = heroName;
 
    return  {
              fly: function(destination) {
                   console.log(name + ' flying to ' + destination);
           }
    }; 
}

Here a function createHero is being defined, which returns an object which has a function fly. The fly function 'remembers' name when needed.

How do Closures relate to Encapsulation?

When the createHero function returns, noone else will ever be able to directly access name, except via fly.

var superman = createHero('SuperMan');
 
superman.fly('The Moon');

The output of this snippet is SuperMan flying to The Moon. But what happens if we try to access name directly ?

console.log('Hero name = ' + superman.name);  

The result is Hero name = undefined. The function createHero is said to a be a Javascript encapsulated module, with closed 'private' member variables and a 'public' interface returned as an object with functions.

Block Scope and Hoisting

Understanding block scope in Javascript is simple: there is no block scope! Take a look at this example

function counterLoop() {
 
    console.log('counter before declaration = ' + i); 
 
    for (var i = 0; i < 3 ; i++) {
        console.log('counter = ' + i); 
    }
 
    console.log('counter after loop = ' + i); 
}
 
counterLoop(); 

By looking at this coming from Java, you might expect:

  • error at line 3: 'variable i does not exist'

  • values 0, 1, 2 are printed

  • error at line 9: 'variable i does not exist'

It turns out that only one of these three things is true, and the output is actually this:

counter before declaration = undefined  
counter = 0 
counter = 1 
counter = 2 
counter after loop = 3 

Because there is no block scope, the loop variable i is visible for the whole function. This means:

  • line 3 sees the variable declared but not initialised

  • line 9 sees i after the loop has terminated

What might be the most puzzling is that line 3 actually sees the variable declared but undefined, instead of throwing i is not defined.

This is because the Javascript interpreter first scans the function for a list of variables, and then goes back to interpret the function code lines one by one.

The end result is that it's like the variable i was hoisted to the top, and this is what the Javascript runtime actually 'sees':

function counterLoop() {
 
    var i; // i is 'seen' as if declared here! 
 
    console.log('counter before declaration = ' + i); 
 
    for (i = 0; i < 3 ; i++) {
        console.log('counter = ' + i); 
    }
 
    console.log('counter after loop:  ' + i); 
}

To prevent surprises caused by hoisting and lack of block scoping, it's a recommended practice to declare variables always at the top of functions.

This makes hoisting explicit and visible by the developer, and helps to avoid bugs. The next version of Javascript (Ecmascript 6) will include a new keyword 'let' to allow block scoping.

Last updated