Javascript vs Java
JS vs Java
Objects only - no Classes
JS is OOO, but there are no classes (although new Ecmascript 6 will add it).
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:
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!
Somehow it may be represented in Java as:
The 'this' Keyword Usage
What Javascript allows to do with this
is quite surprising compared to the Java world.
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:
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!
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.
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:
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.
Notice the capitalized name, indicating that it's a constructor function. Let's see how it can be used:
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:
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
:
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.
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:
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:
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
.
The output of this snippet is SuperMan flying to The Moon
. But what happens if we try to access name
directly ?
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
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:
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':
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