JavaScript has five primitive data types: string, number, boolean, null and undefined. And operators like, +
, -
, typeof
, instanceof
etc. Other than these, everything else are objects. Even functions are objects, can be created by invoking by Function
constructor and typeof
on a function returns function
.
// new Function([arg1[, arg2[, ...argN]],] functionBody) |
JavaScript interpreter does not enforce it, but it’s a common convention, the name of the functions, which are not intended to be used as class
es, starts with a small letter and follows the conventions of camelCase.
Functions in JavaScript either used as a block of codes, to be executed upon call or create objects with properties assigned to the function or to its prototype.
Though operators seems to work like function, but by nature they are special kind of entity, which can’t be assigned and always needs operand(s) to operate on. That means, we can’t write var o = +;
.
Objects can be created by two ways.
// by object literal |
JavaScript objects are basically representations of data-structure of key-value pair. And they can be iterated. And in modern browsers we don’t need to check with .hasOwnProperty
as with the old browsers. Now we can simply do by for...in
loop.
// create the object |
We can add properties to objects by two methods. Either declare properties at the time of creating the objects as the previous example or later assign by value-of
notation.
// use the string literals directly |
To delete a property from an object we can use delete
keyword.
// directly delete the property if known |
By default type of any object, created programmatically is object
and parent is undefined
.
var obj = {}; |
Prior to ES-2015, there was no notion of classes in JavaScript, though class
was a reserved keyword. So, until ES-2015, generally classes were reprsented as functions. And with functions, we can even derive one class into another, using the prototypal inheritance of JavaScript. There are several versions of deriving one class into another, and we can use one of these ways, as per the requirement and choice.
// declare class - 'Animal' |
Unlike other programming languages, in JavaScript inheritance assigned after creation of class, through prototype. Here we will discuss various methods of deriving classes.
// assign a new object to the prototype of 'Tiger' |
All things are fine and all the properties present in the prototype along with the properties declared in direct closure
of the super class has been derived to child class Tiger
. Programmatically and in using this type of construct don’t cause any problems.
However, using new
with a prototypal language like JavaScript, seems like going against the tide. And in this historic document, Crockford agrees to the fact, that JavaScript lacks the mechanism to inherit directly from another object. Instead it uses function
along with new
keyword.
This indirection was intended to make the language seem more familiar to classically trained programmers, but failed to do that, as we can see from the very low opinion Java programmers have of JavaScript. JavaScript’s constructor pattern did not appeal to the classical crowd. It also obscured JavaScript’s true prototypal nature. As a result, there are very few programmers who know how to use the language effectively.
Using new
keyword, actually causes a little deviation from being a pure Prototypal Language
. In modern browsers, there is a method called create
in the Object
prototype. This tries to fulfill the promise of a pure prototypal language.
So, our previous example can be formatted as,
// declare Animal class |
So, it didn’t call the constructor
of the Animal
class. We need to do that explicitly inside the Tiger
constructor
.
function Tiger () { |
And if we are more into writing prototypically pure code, we should not even use functions as classes. Observe how the properties are created here. We can also control accesses of the properties. More details.
// create Animal class object creator |
One benefit of using prototypal language is, it’s possible to use delegation instead of inheriting another class in order to re-use code.
What is delegation
? Let’s understand that by an example.
Suppose we have two classes Mammal
and Reptile
. By the genetic inheritance, we know that, there are almost no similarity between these two species. As designing classes means abstraction of real behavior, suppose for the sake of the program we have identified that, the movement of both of the classes are same. And some super enthusiastic developer has already implemented the move
function for the mammals.
What can we do now. Derive the Mammal
into Reptile
, how odd it may look or sound. Or repeat the same method in Reptile
. But that will introduce redundant code. Or move out the function out of Mammal
and put in some Utility
object and use from both the classes as method call.
As a prototypal language JavaScript gives another possibility. Delegation
.
We can directly use the move
function with an object of Reptile
class by the use of call
or apply
available in Function
prototype.
// create one object of reptile |
Only constraint would be, Reptile
class should contain all the properties, required by the move
method in Mammal
class.
But how this can be done?
Here comes the concept of closure
. In JavaScript, there is no block-scope
as in other programming languages like Java, C++, C.
{ |
Instead it defines closure
as the state of a function along with the scope of it. Let’s understand it by some examples.
var outside = 'Outside'; |
Let’s modify the code a little bit. We will declare the variable outside
again inside the function a
.
var outside = 'Outside'; |
Why it printed undefined
? Because inside the function the re-declaration of outside
hoisted and it overrided the prior declaration of the variable outside
. But, outside the function it remains same.
Now, let’s take an interesting example of closure
.
for (var i = 1; i < 4; i++) { |
It will print 4
three times. But we expected that, it should print 1
, 2
then 3
. Why it did that? Because, the closure, in which the expression console.log(i);
was executed, had 4
as the value of i
at the time of execution.
How can we correct this? simply by creating new closure
for each of the functions passed to setTimeout
.
for (var i = 1; i < 4; i++) { |
It’ll correctly print 1
, 2
then 3
.
Is this the only way-out? No. We can also use partial
functions here. What are partial functions.
In Function
prototype, there is one method, called bind
, which returns a function binding with the passed context and arguments. This blog contains a previous post regarding usefulness of this function for a specific usecase. Here we can use bind
for this purpose.
for (var i = 1; i < 4; i++) { |
It’ll print 1
, 2
and 3
in correct manner.
Thank you for reading this. Be happy. :-)