- Prototypical Inheritance in JS
- Scope in JS
- Function Declaration and Function Expression
- Try Catch in JS
- Scope model in JS
- IIFE Pattern
- Hoisting
- This keyword
- Closure
- Classic Module Pattern
- Modified Module Pattern
- Modern Module Pattern
- Object Orientation
- Async Pattern
- Event Loop
In JavaScript when one object inherits from another prototypically, you are able to access all the properties and methods from the parent object.
var obj1 = {
someProp: 'obj1 property!',
someMethod: function () {
alert('obj1 method!');
}
};
var obj2 = Object.create(obj1);
obj2.someProp = 'obj2 property!';
You might think from the above code that someProp
was
changed from obj1 property!
to obj2 property!
when obj2
was instantiated. However, you can not change properties on an
object's prototype
like that. All that code did was create a property
called someProp
on obj2
that masks
the value
of the underlying someProp on obj1
. If you run delete obj2.someProp
then someProp won't be gone
, it will
revert to showing
the value of obj1.someProp
. This is the
way nested scopes work. Setting a property on a child scope
does not change the property
with the same name on the
parent scope
; it merely hides it.
There are only two scopes:
- Function scope
- Global scope
Function are the atomic unit of the scope
.
When we define something like below:
Compilation phase:
var foo = "bar"; /* declaration */
/*
While compiling this one statement gets broken into two
1. the declaration part using var
2. the assignment part
*/
function bar() { /* declaration */
var foo = "bar"; /* declaration */
}
function baz(foo) { /* declaration of function as well as foo */
foo = "bam";
bam = "yay";
}
Things to note about the above code is:
- JS do JIT(Just in time) compilation, which means function are not compiled when they are defined but they gets compiled and called at the time of call.
- Everything is scoped.
So, the very first line has a scope of global
,
while foo
inside the bar
function has the scope of bar
.
When the js compiles the baz
function, it treats the
argument as a declaration
.
So foo
in the argument will be treated as a local variable.
And the scope
will be of baz
.
Execution phase:
Now we have to note that there will be no var
in the execution
phase. So the first line will be:
foo = "bar" without any
var
.
So even if we define var foo
100 times, while execution it
will be ignored. So defining var foo
in somewhere in our
program has no impact on the rest as that will be ignored.
Compiler terminologies:
lhs
: left hand side
rhs
: right hand side of an assignment.
In our language its the =
sign.
So in first line:
foo
will be ourlhs
referencebar
will be our rhs reference
But lhs
and rhs
can occur without assignment operator.
So to need to understand them in some other way which is:
lhs
: the target
rhs
: the source
So in case of function argument
there is an implicit assignment.
When we execute the function bar
we will ask the scope of bar
that whether it knows about the foo
which happens to be the
lhs
.
When we execute the baz, we will ask scope of baz
, whether it
knows about an identifier
named foo
which happens to be
the lhs
.
So it will say that: yes, its in my declaration
.
But when we execute the line:
bam =
yay
We will ask baz
that whether it heard about an lhs
identifier
named bam
. It will say: no.
Now where do we go?
We go outer one level
. so it will be ourglobal
scope in this case.
So we will ask our global
scope, whether it knows any
identifier named bam
which happens to be the lhs
.
And it will say: yes
, i have just created it for you.
The global
scope will create bam
for us because we have an
lhs
reference.
Note: This thing is in
non strict
mode.
So this assignment will create aglobal variable
.
And that is why we should not declare a variable withoutvar
.
And that's why we get the idea of leakage of global variables
.
But when we will be in strict mode
the global scope will say
it does not
know.
While passing foo
in the function baz
, even if we try to
redeclare foo
using var foo
, the compiler will ignore it as
it has foo
already.
Note:
In JS
undeclared
andundefined
are two different words.
 Âundeclared
: when we do not declare the identifier.
 Âundefined
: when we declare but it contains empty value.
undefined
is more likeuninitialised
.
undefined
is an actual value.
Example:
var foo = "bar";
function bar() {
var foo = "baz";
function baz(foo) {
foo = "bam";
bam = "yay";
}
baz();
}
bar();
foo;
bam;
baz();
While compiling we will say:
hey
global scope
I have a declaration for variable calledfoo
.
For compiling the baz
function it will ask
the scope of bar
to register the function baz
.
While executing when we will go to the bar()
.
We will ask: hey global scope do you have a rhs
reference bar
.
Note:
bar() will be an
rhs
notlhs
because there is no assignment going on at this point of time.
So it will say yes
and it will return the function object bar
.
We have ()
after the bar
, so bar will have function object
and ()
will be used for calling the function.
Note:
In case we ask some
rhs
value which is not declared in the scope, the behavior is different.
The global scope does not create one for us if its arhs
. And it will throw a reference error.
This is common torestrict
andunrestrict
mode.
var foo = function bar() {
var foo = "baz";
function baz(foo) {
foo = bar;
foo;
}
baz();
};
foo();
bar();
If the
function
keyword is the first word in the statement then its afunction declaration
. Otherwise it will be afunction expressions
.
In our case it is function expression
rather than declaration
.
Most of the time function expressions
are anonymous function
,
but in our case it is named anonymous
function.
As the first line in our code is function expression
, bar
will
not get defined in the outer scope
.
In case of function expression
, the name of the function is
enclosed in its own scope
.
So the name bar
exists throughout the function.
So calling foo = bar
is fine. But bar
does not
exists in the global scope. So calling bar()
at the last line
will raise reference error
.
Why we should use named anonymous function expression
:
When we use anonymous function expression there are three downside:
- When we don't use named anonymous function expression we
dont have any way to refer
to ourselves. This property is required when we do recursion, or when we bind some event to our function. (name is necessary) (many people think thatthis
keyword is a reference to itself but it is not.)Anonymous function expression
pose problem while debugging. So giving a name is always helpful.- We don't need to look outside to know what is being done by the function. ex:
when we give name ashandler
it is evident that this function is handling something.
In Es3, try
catch
was added, and according to the
specification, catch
has block
scope.
Meaning, the variable which you will declare in the
catch
clause will only be accessible in the catch
clause
and not outside
.
var foo;
try {
foo.length;
}
catch (err) {
console.log(err);
}
console.log(err); // ReferenceError.
So here err
cant be accessed from outside.
## Scope Models in JS: There are two:
- Lexical scope which we were talking till now. (lex refers to
the
lexing
that occurs in the compiler) (lexical scope meanscompile time scope
) - Dynamic scope (not present in js)(
run time scope
).
var foo = "foo";
(function() {
var foo = "foo2";
console.log(foo); // `foo2`
})();
console.log(foo); // `foo`
When we want to keep some statements in segregated scope
, we use
this pattern. In this pattern an anonymous function expression
has been used and is executed right away.
We can have named function expression
rather than anonymous
function expression. But that thing will give out the name
.
And we wanted to hide our code in some other scope which will
not gets accessed from outside.
## Hoisting: Its not a proper word in the specs, its only being used to define the js behaviors. Consider the below code:
a;
b;
var a = b;
var b = 2;
b;
a;
What will happen if we execute this code?
Before executing there will be compilation. During which the
compiler will find the declaration first, so the above code will
transform into:
var a;
var b;
a;
b;
a = b;
b = 2;
b;
a;
In the above code the compiler moves the declaration
of a
and b
to the top. They were treated first.
This movement of declaration to the top
is called hoisting
.
So the compile phase will be line 1 and 2.
All the function and variable declaration will get
hoisted.
Note:
the
function expression
doesnot
gethoisted
.
So the below code
var a = b();
var c = d();
a;
c;
function b() {
return c;
}
var d = function() {
return b();
};
Will be converted to
function b() {
return c;
}
var a;
var c;
var d;
a = b();
c = d();
a;
c;
d = function() {
return b();
};
Note:
Functions are
hoisted
before variables.
Consider the below code:
foo();
var foo = 2;
function foo() {
console.log("bar");
}
function foo() {
console.log("foo");
}
In this case first function foo
containing bar
will be
hoisted
. Then the function foo
containing foo
will be
hoisted which will override the previous hoisted value.
Then the variable foo
gets hoisted and it will be ignored as
there is already a variable called foo
and it holds the last
function.
Note:
Mutual recursion: Two function calling each other till a terminating condition is reached is called
Mutually recursive
function.
And mutual recursion is not possible in a language where there is nothoisting
.
header files in c language
are manual hoisting. we are putting the declaration part on the top of everything.
Js automatically do hoisting.
##The this
keyword:
Every function, while executing, has a reference to its current
execution context, called this
.
Execution context include far more than this
keyword,
but we are only interested in this
.
Execution context
means where the function has been called and how the function has been called
.
There are four rules for how the this
keyword is bound.
And it all depends on call sight
(It is the place in code where the function is executed
).
Four rules:
-
Default binding rule
(4th according to preference)
ex:function foo() { console.log(this.bar); } var bar = "bar1"; var o2 = {bar: "bar2", foo: foo}; var o3 = {bar: "bar3", foo: foo}; foo(); // here there is only reference to the function // and nothing else. // In these situation, the default binding rule // applies. // This is also true with the IIFIs. o2.foo(); o3.foo();
Default rule says:
- If you are in strict mode, default to
this
keyword isundefined
value. - If not, default to
this
keyword is global object.
Note:
In js everything is a reference to an object. In the above code we have two reference to the
foo
.- Our
global
variable is referencing thefoo
. - o2.foo is also referencing the
foo
.
- If you are in strict mode, default to
-
Implicit binding rule
: ( 3rd according to preference ) Consider the above code:we have o2 and o3 which have same function
foo
. So we have animplicit reference
forfoo
.
If o2 will not have thebar
property,this.bar
will not refer to theglobal bar
.Note:
Binding confusion:
function foo() { var bar = "bar1"; baz(); } function baz() { console.log(this.bar) } var bar = "bar2"; foo();
This code is fake but the concept is real. Here the function
baz
is somethird party
function on which the user does not have any control but user knows that this function is usingthis.bar
somewhere in the code, on the other hand user have another functionfoo
on which user have control. Now user have definedbar
locally and is trying to callbar()
in a hope of referencing thelocal variable bar
.Note:
It is impossible to create a crossover between the lexical environment and the this mechanism
. They are just two fundamentally different mechanism and they don't crossover.The above code was not doing what was expected from it.
The incorrect solution:function foo() { var bar = "bar1"; this.baz = baz; this.baz(); } function baz() { console.log(this.bar); } var bar = "bar2"; foo();
How the above code is wrong:
this
reference gets set by thesight of call
. In our code we need to find what is being referenced by thethis
keyword.As we can see that the function
foo
is being called from the global scope, sothis
will point to the global object as we are in not strict mode. So when we are saying:this.baz = baz in function
foo
.
We are actually saying global.baz = baz butglobal.baz
is already there.when we are calling the
baz
function in ourfoo
function, this.baz(): here theimplicit rule
applies as we are callingobject.function()
but theobject
is stillglobal
object, so it will beglobal.baz()
. -
Explicit scope
:function foo() { console.log(this.bar); } var bar = "bar1"; var obj = {bar: "bar2"}; foo(); // bar1 foo.call(obj); // bar2
Explicit binding say that:
If we use
.call()
or.apply()
at the call sight, both of these utilities take theirfirst parameter
asthis
binding.Problem with
this
keyword generality:In case of a controller, when we have
this
pointing to the controller object, we can do all our work by just usingcontroller.method
.But when we do an ajax call, the things get a bit different. We say in the callback I want to call my controller method :
we pass an reference to the controller method. But when it gets called thethis
binding getswrong
, it willfall back
to theglobal
.Or say we have attached it to an event handler like a
click handler
on a button. When I click the button, I want my controller method to invoked but we will get frustrated becausethis
binding becomes thebutton
itself rather than mycontroller object
.solution:
hard binding
: It is used to fixate thethis
keyword reference.
ex:function foo() { console.log(this.bar); } var obj = {bar: "bar"}; var obj2 = {bar: "bar2"}; var orig = foo; foo = function() {orig.call(obj);}; foo(); // `bar` foo.call(obj2); // ???
In the above code, everything is same apart from declaration of
orig
variable and assigning it 'foo'. Now in the next line, we are overriding the foo with afunction expression
, andforcing
the call tofoo
to the originalfoo
but fixing thethis
reference to theobj
.So both the function call will print
bar
.Making an binding utility:
function bind(fn, o) { return function() { fn.call(o); }; } function foo() { console.log(this.bar); } var obj = {bar: "bar"}; var obj2 = {bar: "bar2"}; foo = bind(foo, obj); foo(); // `bar` foo.call(obj2);
This code is same as the above one. But it does not have any variable in
global scope
whose reference can be over written. But in this code too we are creating oneglobal utility
.Also the utility in this code does not have return statement(we cant return anything from the func) And we can not pass arguments too.
solution:
putting the utility on the prototype of function itself.// we are calling our utility `bind2` temporarily. if (!Function.prototype.bind2) { Function.prototype.bind2 = function(o) { var fn = this; // the function! // when we will look at the call sight // we will find that the utility is // a function, so 'this' will apply to it. // also we are calling it using 'implicit' // binding of 'foo'. So 'this' will point to // 'foo'. return function() { return fn.apply(o, arguments); }; }; } function foo(baz) { console.log(this.bar + " " + baz); } var obj = {bar: "bar"}; foo = foo.bind2(obj); foo("baz") // `bar baz`
In this code the utility has a return statement so it is capable of returning some values, also we will be able to pass arguments in this utility.
It is so common that the JavaScript has a
bind()
function on the functionprototype
. So we don't need ourbind2
utility. Its built-in. (In ECMAScript 5)When we go to the MDN page for binding, they have a
polyfills
(they are to provide support for older browser). So we can use thebind
utility in older browser too. -
new keyword
:Please set aside any conception about the 'new' keyword In other language
new
keyword is used for instantiating the classes but- JavaScript does not have
classes
new
keyword has nothing to do with theinstantiation
function foo() { this.baz = 'baz'; console.log(this.bar + ' ' + baz); // undefined undefined } var bar = 'bar'; var baz = new foo();
When we put the
new
keyword in front of any function call, it magically turns thatfunction call
into aconstructor
call.When we put the
new
keyword in front of any function call, it's going to do4 things
:- A
brand new
emptyobject
will be created. - The new empty
object
getslinked
to a different object. - The
brand new
empty object getbound
as thethis
keyword for the purposes of that function call. - If that function does not otherwise return anything.
Then it will implicitily insert, between
line 3
andhalf of the above code
, areturn this
. That is thebrand new
object get returned for the purposes of the call.
So in the above code, when we call
foo
function with thenew
keyword, an object as thethis
reference will get returned.So we can have one variable on
this
asba
, but when we try to accessthis.bar
, as there is nothing calledbar
onthis
, therefore,undefined
will gets printed.And at the moment,
baz
variable exists but it does not have any value so we will printundefined
again.But final thing is that, there is a implicit
return this
, so the newly created object gets assigned to ourbaz
variable. So if we trybaz.baz
we will get the string value 'baz'.How
this
binding works:Ask these questions:
- Was the function called with 'new' keyword ?
If so, use that object.
Which means the
new
keyword is able to override any of the other rules as it is mostprecedent
of the rules. - Was the function called with
call
orapply
specifying an explicitthis
? If so, use that object. - Was the function called via a containing/ owning object(context) ?
- Default: global object (except strict mode)
hard bound
functions are a variation of explicit binding rule.So, what will be the precedence of
hard binding
?Ans: At no 2, which means the
new
keyword is able to override thehard binding
. - JavaScript does not have
Closure is when a function
remembers
itslexical scope
even when the function is executedoutside that lexical
scope.
Ex:
function foo() {
var bar = "bar";
function baz() {
console.log(bar);
}
bam(baz);
}
function bam(baz) {
baz(); // `bar`
}
foo();
Note:
If we keep a reference to an object, that does not get
garbage
collected. Similarly until we have at-least one function referencing thescope
object, throughclosure
,scope
does not gets garbage collected.
Prob:
consider the below code:
for (var i = 1; i <= 5; i++) {
setTimeout(function() {
console.log("i: " + i);
}, 1 * 1000);
}
By running this example we will get the below result:
i: 6
i: 6
i: 6
i: 6
i: 6
i: 6
But why?
Because through
closure
the function insidesetTimeout
is using the the global variablei
. and as we have live copy of thei
variable in each function call, everyi
value will get updated with the last value.
How to solve it ?
-
Using
IIFI
pattern: we need to use theIIFE
pattern.
Ex:for (var i=1; i<= 5; i++) { (function(i){ setTimeout(function(){ console.log('i: ' + i); }, i * 1000); })(i); }
so now each of the
setTimeout
function will have iteration scope rather thanglobal
scope. -
Using
let
keyword:for (let i=1; i<5; i++) { setTimeout(function(){ console.log("i: " + i); },i*1000); }
what
let
keyword does is, it rebindsi
for eachiteration
offor
loop.
It has two characteristics:
- There must be an outer wrapping function that gets executed(Does not have to be a IIFE, but it does have to an outer function that gets executed).
- There must be one or more functions that get returned from that function call. So one or more inner functions that have the
closure
over the inner private scope.
Ex:
var foo = (function() {
var o = {bar: 'bar'};
return {
bar: function() { //these stuffs are like
// private members of a
// module.
// And the obj `bar` is like
// an public API.
// There are one or more methods
// on the API, that have the
// special privilleged 'closure'
// capability that access the
// 'internal' state, and that
// makes a module.
console.log(o.bar);
}
};
})();
foo.bar();
So all the function is hidden
from the outside world
and we get choose what we return on our public API
.
This pattern is useful in implementing
encapsulation
. This is the idea of hiding private implementation details
var foo = (function() {
var publicAPI = {
bar: function() {
publicAPI.baz();
},
baz: function() {
console.log('baz');
}
};
return publicAPI;
})();
foo.bar(); // `baz`
define('foo', function() {
var o = {bar: 'bar'};
return {
bar: function() {
console.log(o.bar);
}
};
});
we have a named module foo
and we are doing stuff on
that.
This pattern when used using IIFE
pattern, can only
provide one instance, meaning its only for one time use
.
On the other hand if we use this pattern by using common function and then assign the return value to different variable, we will have different instance of the same module.
Ex:
var foo = function() {
var publicAPI = {
bar: function() {
publicAPI.baz();
},
baz: function() {
console.log('baz');
}
};
return publicAPI;
};
var myFoo = foo();
var yourFoo = foo();
-
function Foo(who) { this.me = who; } Foo.prototype.identify = function() { return 'I am ' + this.me; }; var a1 = new Foo('a1'); var a2 = new Foo('a2'); a2.speak = function() { alert('Hello, ' + this.identify() + '.'); }; a1.constructor === Foo; a1.constructor === a2.constructor; a1.__proto__ === Foo.prototype; a1.__proto__ === a2.__proto__;
Every single
object
is built by a constructor function. Each time a constructor is called, a new object is created.Note:
It's important to understand that there is a distinction between an object's
prototype
(which is available viaObject.getPrototypeOf(obj)
, or via the deprecated__proto__
property) and theprototype
property onconstructor functions
. The former is the property oneach instance
, and the latter is the property on theconstructor
. That is,Object.getPrototypeOf(new Foobar())
refers to the same object asFoobar.prototype
.A constructor makes an object
based on
its own prototype.based on
is not completely true in case of JavaScript.based on
implies that we take the prototype and we stamp out a copy of it.This is true in
class
oriented languages. sobased on
give us the wrong idea.A more appropriate way of saying the above thing is:
A constructor makes an object
linked to
its own prototype.Note:
While discussing the
new
keyword we said in thesecond
step that it linked to an object.Note:
Before anything gets executed in the above code we already have somethings, which are:
- A function called
Object
(capitalO
) - An object which does not have any name, but a
label named
Object.prototype
.
Object func ----
.prototype
------> unnamed objectThe
Object
function has been linked to the object which does not have any name.
On the unnamed object, we have functions liketoString
and several values which are built in the language.When the first line of above code gets executed:
-
We will have a function called
Foo
, -
Its also going to create an
object
that we are linked to, and it will have the same arbitrary name:.prototype
.Foo func -------
.prototype
-------> unnamed objectAlso the unnamed object is linked to the unnamed object of the 'Object' function and this linkage is labeled as
[[p]]
. ([[p]]
is explained later in this notes) -
In addition to the above connection, there is also a connection in the opposite direction. The unnamed object has a property on the
function
called.constructor
.
Foo function <------
.constructor
---- unnamed objectMost people think the '.constructor' means is constructed by. In other words the unnamed object is constructed by the
function
.But its not true
.The word
constructor
is an arbitrary word it could have been any other random word.So there is a
two-way
linkage. Now when we execute theFoo.prototype.identify = function()
line, we put theidentify
property directly on theunnamed
object.Now coming on the code
var a1 = new Foo('a1')
Here we have encountered thenew
keyword. So four things will happen:- brand new object will gets created.
- object gets linked to another object.
(so the newly created object will get linked
to the
unnamed object.
) - The context gets set to the
this
. So the newly created object will have a property calledme
, which will have the valuea1
. - We return
this
, which gets assigned to the variablea1
in the code. So now the name of the newly created object will bea1
.
Now executing
a2.speak = function()
This will put thespeak
property on the object which isa2
.So at this point of time, if we try to execute
a1.speak()
, it wont get executed as there is no property calledspeak
on thea1
object.Coming on to the code
a1.constructor === Foo
. There is no direct property calledconstructor
on thea
object. Some people think that there is a hidden property calledconstructor
on thea1
object, but in reality its not there.So when we execute the above code, as there is no property called
constructor
on thea1
object it will go up in thePrototypical
chain. And the unnamed object has a linkage of.constructor
so the call will end of beingFoo
. Soa1.constructor is Foo
.The linkage of newly created object, such as
a1
, with the unnamed object, which is linked with the function such asFoo
using.prototype
label, is calledPrototypical linkage
. In the specs this linkage is denoted by[[Prototype]]
But in this notes we will say it[[P]]
instead.They are internal linkage, they are not visible to public.
Now when we execute
a1.__proto__ === Foo.prototype
The name for__proto__
isdunder
. The pronunciation of the above property isdunder proto property
. So when the above code will get executed it will check whethera1
have adunder proto
property.As it does not have, it will go up in the Prototypical chain and check the same thing on the unnamed object. As that object also does not have the
dunder proto
property, so we will go up in the Prototypical chain, which happens to be the unnamed object of theObject
function.Now on this object there is a property named
__proto__
. It turns out that it is not a property, rather its agetter
function. So the above code is afunction call
.This function returns the
internal prototype
linkage of whatever thethis
binding is.So when we have called the
__proto__
function, thethis
keyword isa1
.So this function
returns the internal prototype
linkage ofa1
.So the
[[P]]
was the internal linkage and__proto__
is the public linkage ofa1
with the unnamed object of theFoo
function.So
__proto__
is the public property that references the internal characteristics.The problem with
dunder proto
is, it never been standardised.But its a de-facto standard for every other browser except the
IE
.So we can see that
a1.__proto__
is same asFoo.prototype
. The same goes fora2
.As of
ES5
, there is an standard utilitya1.__proto__ === Object.getPrototypeOf(a1);
So this utility extract the internal
Prototypical linkage
for us.So this utility is there for
IE > 8
But what we will do for browsers < 8.Sol:
a2.__proto__ == a2.constructor.prototype; // for IE < 8
But the problem is,
both the property
the constructor property
andthe prototype
property arewritable
property. They happen to default to pointing where we discussed above. But when they gets over written, the above code forIE < 8
is unreliable.function foo(who) { this.me = who; } Foo.prototype.identify = function() { return 'I am ' + this.me; }; function Bar(who) { Foo.call(this, who); } // Bar.prototype = new Foo(); // or... Bar.prototype = Object.create(Foo.prototype); // NOTE: .constructor is broken here, need to fix Bar.prototype.speak = function() { alert('Hello, ' + this.identify() + '.'); }; var b1 = new Bar('b1'); var b2 = new Bar('b2'); b1.speak(); // alerts: `Hello, I am b1.` b2.speak(); // alerts: `Hello, I am b2.`
In the above code we wanted the class
Bar
to be the child of theFoo
class. As we have written the function names in CAPS, they refer to the class.We can achieve this by assigning what is there in the comment in the code
// Bar.prototype = new Foo();
But by this way we will un-wantedlycall Foo every
time.Soln is use the
Object.create
. TheObject.create
does the first two things of whatnew
keyword does.In this code, when we call
var b1 = new Bar('b1')
.this
will point tob1
So when we callb1.speak();
it will check whetherb1
is having aspeak
property. No it does not have.Then it will go Prototypically up, and check whether
Bar.prototype
havespeak
property, and it is there on theBar
, so it will call it.Now in the speak property, we have
this.identify
, herethis
points tob1
, so we check whetherb1
has aidentify
property, as it does not have, we will go Prototypically up, and check ifBar.prototype
has a identify property.No, so we traverse further up, and check whether
Foo.prototype
has a 'identify' property, as it has it gets called.But there is a drawback in this approach. We have lost the
.constructor
linkage. But how? As of line 6 in the above code we have the.constructor
property but when we execute the code on line 12, we change the reference of the prototype object, and the newly created one does not have a.constructor
property.So we will delegate up to check
does the foo
prototype has a.constructor
, yes it does and it is pointing to theFoo
, so we getFoo
instead ofBar
.So this bizzare result proves that
.constructor
does not meanis constructed by
, it is simply an arbitrary property.Now we can use the class pattern rather than the
module pattern
. For this all the methods which were private in the module pattern will now come to theprototype of the class
.It is necessary to write the prototype like:
ClassName.prototype.someMethod
Because when we write like:ClassName.prototype = { someMethod: 'hello' }
We are actually overriding the prototype and thus we will loose the
.constructor
property.Generally we should always use the dynamic binding provided to us using 'this' but there is one instance where we have to fallback to the lexical way of doing things.
consider the below example:
NotesManager.prototype.showHelp = function() { this.$help.show(); // $help is just a convention // for saying that this variable // belongs to JQuery. document.addEventListener('click', function __handler__(evt){ evt.preventDefault(); evt.stopPropagation(); evt.stopImmediatePropagation(); document.removeEventListener('click', __handler__, true); this.hideHelp(); //}, true) }.bind(this),true) };
Now when we call this function, the
this
in the last line of codewill not point
to the reference we want, rather it will be thebutton
on which the listener is being called.To solve this problem we can use
.bind
function. So we do like the uncommented last line.But in the event listener function we are
removing the event listener
using thenamed
method. But due thehard binding
thenamed function
isnot
there.So only in this case we do like below:
NotesManager.prototype.showHelp = function() { var self = this; self.$help.show(); // $help is just a convention // for saying that this variable // belongs to JQuery. document.addEventListener(`click`, function __handler__(evt){ evt.preventDefault(); evt.stopPropagation(); evt.stopImmediatePropagation(); document.removeEventListener(`click`, __handler__, true); self.hideHelp(); }, true);
But in general this is not a good practice.
- A function called
-
Inheritance means that the child is having the copy of what the parent have.
So its not wise to call
prototypal inheritance
for JavaScript as we are not using the word inheritance for itscorrect meaning
.In JavaScript when we have the object arbitrarily called
Foo.prototype
and when we havea1
anda2
object, they are linked in the opposite way to what inheritance does. In inheritance we have the below structure:parent -----------> child
meaning child is a copy of the parent. But in JS:
Foo.prototype <----------- child
meaning the child is behaviorally linked to the prototype.
This delegation in JS is a
design pattern
and it is calledBehavior Delegation
. -
OLOO: (Objects Linked to Other Objects)
function Foo(who) { this.me = who; } Foo.prototype.identify = function() { return 'I am ' + this.me; }; function Bar(who) { Foo.call(this, who); } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.speak = function() { alert('Hello, ' + this.identify() + '.'); }; var b1 = new Bar('b1'); b1.speak();
In this code we only need to care about the three objects which are prototypically linked.
b1
is linked toBar.prototype
.Bar.prototype
is linked toFoo.prototype
.Now the same thing can be achieved by using only the
objects
rather than theconstructor
.As a first step towards refinement we will remove the
new
keyword. The refined code will look like the below:function Foo(who) { this.me = who; } Foo.prototype.identify = function() { return 'I am ' + this.me; }; function Bar(who) { Foo.call(this, who); } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.speak = function() { alert('Hello, ' + this.identify() + '.'); }; var b1 = Object.create(Bar.prototype); Bar.call(b1, 'b1'); b1.speak();
[js]
In this refinement remove the
new
keyword and instead use theObject.create
utility to create abrand new object
andlink
the object to theprototype
.Then we explicitly bind the
Bar
this
tob1
.Consider the second refinement below:
function Foo(who) { this.me = who; } Foo.prototype.identify = function() { return 'I am ' + this.me; }; //changed var Bar = Object.create(Foo.prototype); Bar.init = function(who) { Foo.call(this, who); }; // changed Bar.speak = function() { alert('Hello, ' + this.identify() + '.'); }; var b1 = Object.create(Bar); // changed b1.init('b1'); // changed b1.speak();
In this refinement, we have ditched the function
Bar
and madeBar
an object instead.Consider the third refinement:
var Foo = { init: function(who) { this.me = who; }, identify: function() { return 'I am ' + this.me; } }; var Bar = Object.create(Foo); Bar.speak = function() { alert('Hello, ' + this.identify() + '.'); }; var b1 = Object.create(Bar); b1.init('b1'); b1.speak();
Now these are peer objects that can delegate to each other.
-
if (!Object.create) { Object.create = function(o) { function F() {} F.prototype = o; return new F(); }; }
- Callbacks
- Generators / Co-routines
- Promises
-
callback hell
:setTimeout(function(){ console.log('one'); setTimeout(function(){ console.log('two'); setTimeout(function(){ console.log('three'); }, 1000); }, 1000); }, 1000);
Note:
callback hell does not have anything to do with nesting.
Consider the below code:
function one(cb) { console.log('one'); setTimeout(cb, 1000); } function two(cb) { console.log('two'); setTimeout(cb, 1000); } function three() { console.log('three'); } one(function(){ two(three) });
-
Inversion of control
:When we loose control over a program to let it execute by some third party library.
-
Solving callback problems
:- separate callbacks:
function trySomething(ok, err) { setTimeout(function(){ var num = Math.random(); if (num > 0.5) ok(num); else err(num); }, 1000); } trySomething( function(num){ console.log('Success: ' + num); }, function(num){ console.log('Sorry: ' + num); } );
In this we expect the third party library to call one method when there is
success
and the other when there isfailure
. But this is moreimplicit trust
, because we are trusting on them that they will callonly one method
. But what will happen when they call both the methods:Our code will break
.- error-first style:
function trySomething(cb) { setTimeout(function(){ var num = Math.random(); if (num > 0.5) cb(null, num); else cb('Too low!'); }, 1000); } trySomething(function(err, num){ if (err) { console.log(err); } else{ console.log('Number: ' + num); } });
In this code we have only one function. So we are only checking for the `error` object. But consider a scenario when they return an `error` object and then a `success` value. In this situation we will `reject` the `success` value as we are only checking for the `error` object.
function* gen() {
console.log('hello');
yield null;
console.log('World');
}
var it = gen();
it.next(); // prints `Hello`
it.next(); // prints `World`
So calling the gen
function, creates an iterator
.
so when we call it.next()
it will start from the
line 2 and execute till it encounters a yield
statement.
The second it.next()
will also run till it encounters
a yield
statement or till end of the program.
yield
is used for two way message passing
.
meaning we can pass value to yield
from outside
and yield
can also return value to the calling function.
Consider the below code:
var run = coroutine(function* (){
var x = 1 + (yield null);
var y = 1 + (yield null);
yield(x + y);
});
run();
run(10);
console.log('something: ' + run(30).value);
So when first run()
will be called, the yield
will
return null
to the function.
When we call run(10)
, the value of the previous yield
expression will be 10.
So the value of x = 11
.
and it encounters the next yield
and null
will get
returned to run(10)
now when run(30)
will get executed, 30 will get
substituted for the yield
expression and
y = 31
.
Then it encounters the next yield
and (x + y) will
be returned which is 42
.
Till now everything was looking synchronous
in
generators.
Consider the below code:
function getData(d) {
setTimeout(function() {run(d);}, 1000);
}
var run = coroutine(function* (){
var x = 1 + (yield getData(10));
var y = 1 + (yield getData(30));
var answer = (yield getData('something: ' + (x + y)));
console.log(answer);
});
run();
JQuery style Promises:
var wait = jQuery.Deferred();
var p = wait.promise();
// this happens when we listen for an event
// continuation event
p.done(function(value) {
console.log(value);
});
// when we call resolve on Deferred, it will
// automatically fires the 'done' event for
// any promises that are listening to it.
setTimeout(function(){
wait.resolve(Math.random());
}, 1000);
Ex:
function waitForN(n) {
var d = $.Deferred();
setTimeout(d.resolve, n);
return d.promise();
}
// promise gets returned from the
// waitForN function, and when we call
// '.then' we are listening for the
// continuation event on that returned promise.
waitForN(1000).then(function() {
console.log('hello world');
return waitForN(2000);
})
.then(function(){
console.log('finally!');
});
Promises un-invert the inversion of control
Prob: Make three request to fetch some data from files asynchronously, but display them in the given order.
Sol:
For this problem we need to track the internal
state of the call, if we are using callbacks
.
Our browser have following things:
- call stack (js runtime)
- WebAPIs (ex: setTimeout, DOM(document), ajax(XMLHttpRequest))
- event loop
Actually JS is single threaded
.
So when we execute some things such as the below code:
console.log('hiii there');
function foo() {
console.log('hello');
}
function bar() {
console.log('there');
foo();
}
function baz() {
console.log('hi');
bar();
}
baz();
How these things are executed by the JS runtime is:
- At first
main()
will appear in the stack.main()
is the anonymous function corresponding to the file itself.- then
console.log('hiii there')
will appear in thestack
.- then
baz()
- then
console.log('hi')
- then
bar()
- then
console.log('there')
and like that.
But consider the below code:
console.log('hii there');
setTimeout(function foo() {
console.log('hello there')
});
console.log('hii')
How will this code gets executed?
When we check the 'call stack' we will find:
- console.log(
hii there
) will get executed.- setTimeout(function foo() { console.log('hello there') }); will get executed but it will disappear from the stack before executing console.log('hello there').
- then console.log(
hii
) will get executed.
But where does that setTimeout function went?
Actually
setTimeout
is a function defined inWebAPI
not in actualJS runtime
.
So the function after leaving thecall stack
will enter into theWebAPI
and thatapi
will keep track of thetimer
. When the timer is complete, as it can not directly modify thecall stack
, it will throw the function into theevent loop
ortask queue
.Event loop
has to wait till the stack is clear, before it can push thecallback
on thecall stack
.setTimeout
is not a guaranteed time of execution, it isminimum time
of execution.
When we block the stack with some slow
work, the
browser does not render, (render queue gets stopped).
So during that time, nothing will work, no buttons, no selection, nothing.
Where in case of asynchronous call
, browser gets a chance
to re-render after every call.