-
-
Save LearningMaterial/d3a145bbfc20e64ae10ba4d0bec604ed to your computer and use it in GitHub Desktop.
# Syntax Parsers
# Lexical Environments
# Execution Contexts
A PROGRAM THAT READS YOUR CODE AND DETERMINES WHAT IT DOES AND IF ITS GRAMMER IS VALID
WHERE SOMETHINGS SITS PHYSICALLY IN THE CODE YOU WRITE
lexical means having to do with words or grammar
. Lexical environment exists in programming languages in which
where
you write something is important
A WRAPPER TO HELP MANAGE THE CODE THAT IS RUNNING
There are lots of lexical environments. Which one is currently running is managed via execution contexts.
A NAME WHICH MAPS TO A UNIQUE VALUE
The name may be defined more than once, but only can have one value in any given `context`.
That value may be more than name/value pairs
A COLLECTION OF NAME VALUE PAIRS
The simplest definition when talking about `JS`
Address : {
Street: 'Main',
Number: 100;
Apartment: {
Floor: 3,
Number: 101
}
}
# Whenever we write a JS code an execution context will be created and run. The base execution context is the `global
execution context`
1) Global Object
2) special variable called `this`
Javascript engine creating this 2 things for you whenever the code is run. Because the code is wrapped inside the execution context.
Whenever we create a global variable or function we are actually creating a property of the global object. In the case of browser the
global object is window object!
b(); | |
console.log(a); | |
var a = 'Hello World!'; | |
function b() { | |
console.log('Called b!'); | |
} | |
// output | |
//called b | |
//undefined |
There are 2 things happening when you run a Js code. compilation
and interpretation
. In the compilation
phase no assignment operation will happen. And in the interpretation
phase the actual execution will take place.
At `compilation` phase variable a (only declaration) and function b will sit in the global scope. After that
`interpretation` phase will occur. In `interpretation` phase b is invoked and `called b` is printed in the console. Then `undefined` is printed in the console because global scope knows there is a variable called a is declared but it doesn't know the value of a. This behaviour is called `HOISTING`.
`function b` and function `a` sits in the global execution context.
when a() is invoked a new execution context will be created for `function a` and inside `function a` when
`function b` is invoked a new execution context will be created for `function a`
// Simple example of Scope chain | |
function b() { | |
console.log(myVar); | |
} | |
function a() { | |
var myVar = 2; | |
b(); | |
} | |
var myVar = 1; | |
a(); | |
// OUTPUT IS 1 |
function b
, function a
and variable myvar
will sits in the global execution context.
when function a
is invoked, a new execution context for function a
will be created. When function b
is invoked inside
function a
a new execution context will be created for function b
. Inside function b
variable myvar
is printed. What will be the output? You may think that the output will be undefined
. But the thing is in JS where you write something is important I mean lexical environment
matters. When function b
doesn't find myvar
in its execution context, it looks where this function lexically situated
by the time its creation. You already know it is situated in the global execution context by the time of its creation.
In global execution context myvar=1
. So, the output is 1. Here, global execution context
is the outer reference for
function b
. This incident is called Scope chain
.
YOU DON'T TELL THE ENGINE WHAT TYPE OF DATA A VARIABLE HOLDS, IT FIGURES IT OUT WHILE YOUR CODE
IS RUNNING.
variables can hold different types of values because it's all figured out during execution.
var isNew = true;
isNew = 'Yup';
isNew = 1;
A TYPE OF DATA THAT REPRESENTS A SINGLE VALUE
undefines represents lack of existence (`you shouldn't set a variable to this`)
null also represents lack of existence (`you can set a variable to this`)
true or false
floating point number(there's always some decimals). Unlike other programming languages, there's
only one `number` type... and it can make math weird.
a sequence of characters (both '' and "" can be used).
used in ES6.
A SPECIAL FUNCTION THAT IS SYNTACTICALLY (WRITTEN) DIFFERENTLY
generally operators take two parameters and return one result.
WHICH OPERATOR FUNCTION GETS CALLED FIRST
Functions are called in order of precedence.
(Higher presidency wins
)
WHAT ORDER OPERATOR FUNCTIONS GET CALLED IN: LEFT-TO-RIGHT OR RIGHT-TO-LEFT
WHEN FUNCTIONS HAVE THE SAME PRESIDENCY.
Example of Associativity is given below:
the output is 4 for all 3 console.log. Because Assignment operator (==) is right associative.
So, associativity
comes into play when two or more operators have the same precedence.
CONVERTING A VALUE FROM ONE TYPE TO ANOTHER
This happens quite often in JavaScript because it is dynamically
typed.
var a = 1 + '2';
console.log(a);
In the above example, number 1 is converting into string 1
that's why output is 12
Example of comparison Operators are given below:-
The output of both lines is true. But you may think that 3 < 2 < 1 will give false
as output But the thing is,
from the rule of associativity we know that <
operator is left-to-right associative. So, at first, it evaluates
3 < 2. Which returns false. Now it is false < 1
. In JS numeric value of false is 0. so now it becomes 0 < 1
which is true. That's why the output is true
!
var x = 99;
x == "99" // true;
x === "99" // false
We can see that, ==
performs type coercion
while ===
doesn't. It is safer to use ===
Trust me, It can save your life!
var a;
// goes to internet and looks for a value
if(a) {
console.log("Something is there");
}
variable a is undefined. So it will be converted to false as a result of type coercion.
So, nothing will be printed in the console.
var a;
a = "hi";
// goes to internet and looks for a value
if(a) {
console.log("Something is there");
}
Something is there // output
In the above snippet, the value of a is a String. And it is converted to true as a result of type coercion.
So Something is there will be printed in the console
var a;
a = 0;
// goes to internet and looks for a value
if(a) {
console.log("Something is there");
}
In the above example, nothing will be printed in the console. Because 0
will be converted to false
as
a result of type coercion
. But 0 might be a valid value. How can we solve this now?. Ok see the below example:
var a;
a = 0;
// goes to internet and looks for a value
if(a || a === 0) {
console.log("Something is there");
}
Something is there // output
In the above example, presidency of ===
is higher than presidency of ||
So, a===0 will be converted into
true
then a will be converted into false. At the end, (false || true) will return true. As a result,
Something is there
will be printed in the console.
Let's see an example:
function greet(name) {
console.log("Hello " + name);
}
greet("Ashik");
greet();
Hello Ashik // output
Hello undefined // output
In the above example greet function
is invoked two times. when greet()
function is invoked first time it
will give Ashik
as an argument. So in the execution context of greet function
value of name
is Ashik
.
As a result Hello Ashik
is printed in the console. It is a normal concept.
But, what about the 2nd calling of greet
function? This time it doesn't give any argument, but greet function
expects an argument. Since there is no argument when greet function is invoked value of name
will be undefined
. And as a result of type coercion
in the console.log primitive type
undefined
will be converted into string undefined
. Then Hello undefined
will be printed in the console. This is a problem.
Before going to that solution. we will see some code example:
>undefined || "hi"
<"hi"
>null || "Hello"
<"Hello
>"Hi" || "Hello"
<"Hi"
In the above examples,
we see that ||
operator returns those values which are happened to be converted
into true
. And if both operands are happened to be converted into true it returns the first operand.
Now, let's move on to the solution:
function greet(name) {
name = name || '<Your name here>';
console.log("Hello " + name);
}
greet("Ashik");
greet();
//output
Hello Ashik
Hello <Your name here>
when greet()
is invoked for the first time it gives an argument. So inside the execution context
of greet
value of name is Ashik
. So, In the first line of greet
function, it will be looked like
name = "Ashik" || '<Your name here>';"
As I said earlier when both operands are converted to true, JS will
return the first operand. In that case, the first operand is Ashik
. So, Hello Ashik will be printed in the console.
when greet()
is invoked for the second time it gives no argument. So inside the execution context
of greet
value of name is undefined
. So, In the first line of greet
function, it will be looked like
name = undefined || '<Your name here>';"
Between undefined
and '<Your name here>
,
Your name here will be converted into true
. So in that case, Hello '<Your name here>'
is printed in the console. 👍
var person = new Object();
person["firstName"] = "Tony";
person["LastName"] = "Alicea";
var firtNameProperty = "firstName";
console.log(person[firstNameProperty]);
console.log(person.firstName);
//output
Tony
Tony
There are 2 ways to access properties of an object:
- Dot notation: something.bar.
- Bracket notation: something['bar'].
The value between the brackets can be any expression. Therefore, if the property name is stored in a variable, you have to use bracket notation:
var foo = 'bar';
something[foo];
var person = {};
var person = {
firstname: 'Ashiqur',
lastname: 'Rahman',
address: {
street: '111 Main St.',
city: 'New York',
state: 'NY'
}
};
var coder = {
firstName: 'Ashiqur',
lastName: 'Rahman',
addres: {
street: '111 Main St.',
city: 'New York',
state: 'NY'
}
};
function greet(placeHolder) {
console.log("Hi, " + placeHolder.firstName + " " + placeHolder.lastName);
}
greet(coder);
//output
Hi, Ashiqur Rahman
In JavaScript, We can also create an object when the function is called.
var coder = {
firstName: 'Ashiqur',
middleName: 'Rahman',
lastName: 'Ashik',
address: {
permanent: 'Comilla',
present: 'Dhaka'
}
};
function greet(placeholder) {
console.log(placeholder.lastName);
}
// pass object on a function
greet(coder);
// create object on the fly
greet({
firstName: 'Tamim',
lastName: "Iqbal"
});
//output
Ashik
Iqbal
A CONTAINER FOR VARIABLES AND FUNCTIONS
Typically to keep variables and functions with the same name separate.
We don't have namespace in Javascript
We can create namespace by creating objects.
//without namespacing
var greet = "Hello";
var greet = "Assalamualaikum";
console.log(greet);
// with fake namespacing
var english = {
greet: "Hello"
};
var bangali = {
greet: "Assalamualaikum"
}
console.log(english);
console.log(bangali);
//output
Assalamualaikum
{ greet: 'Hello' }
{ greet: 'Assalamualaikum' }
From the above code, we can see that when there are no namespacing
available, greet = "Hello"; is overwritten by greet = "Assalamualaikum"; But, by creating objects we can make the separate container for
english
and bangali
greetings. 👍
{
"firstname" : "Ashiqur",
"isAProgrammer" : true
}
In JSON properties
have to be wrapped in quotes.
var objectLiteral = {
firstName: "Ashiqur",
isAProgrammer: true
};
//CONVERT OBJECT LITERAL INTO JSON
console.log(JSON.stringify(objectLiteral));
//CONVERT JSON INTO OBJECT LITERAL
var jSONvalue = JSON.parse('{"firstName": "Ashiqur", "isAProgrammer" : true}');
console.log(jSONvalue);
//output
{"firstName":"Ashiqur","isAProgrammer":true}
{ firstName: 'Ashiqur', isAProgrammer: true }
EVERYTHING YOU CAN DO WITH OTHER TYPES YOU CAN DO WITH FUNCTIONS
Assign them to variables, pass them around, create them on the fly.
function greet() {
console.log("Hi");
}
greet.language = "Engish";
console.log(greet.language);
// output
// English
A UNIT OF CODE THAT RESULTS IN A VALUE
it doesn't have to save to a variable.
var anonymousGreet = function() {
console.log("hi");
}
anonymousGreet();
// output
Hi
function expressions are not hoisted. Because in global execution context
, it recognized as a variable, not as a function.
function happy(fn) {
fn();
}
happy(function(){
console.log("I passed as a function parameter");
});
//output
// I passed as a function parameter
Primitives are passed by value
Objects are passed by reference
// by value (primitives)
var a = 3;
var b;
b = a; // copy of value a is created but different memory location
a = 2;
console.log("Pass by value-");
console.log(a);
console.log(b);
// by reference (all objects (including functions))
var c = {greeting : 'hi'};
var d;
d = c; // points d at the same location of the memory where c points to.
c.greeting = 'Hello'; // mutate
console.log("Pass by reference-");
console.log(c);
console.log(d);
// by reference (even as parameters)
function changeGreet(obj) {
obj.greeting = 'Hola!'; // mutate
}
changeGreet(d);
console.log(c);
console.log(d);
// equals operators sets up new memory space (new address)
c = {greeting: 'Howdy'};
console.log(c);
console.log(d);
============================================================================================================
//**output**
Pass by value-
2
3
Pass by reference-
{ greeting: 'Hello' }
{ greeting: 'Hello' }
{ greeting: 'Hola!' }
{ greeting: 'Hola!' }
{ greeting: 'Howdy' }
{ greeting: 'Hola!' }
Every time a function is run Js engine gives us this special variable called this
. And this
can be pointing
to different things depending on how the function is invoked!
This can create a lot of confusion.
We will see some example and try to find a solution:
console.log(this); // this points to global object
Window
When you create a function this keyword also points to the global object Window
function a() {
console.log(this);
}
a();
But, when a method is attached to an object then this
keyword points to that object instead of global object
var c = {
name : 'The C object',
log : function() {
console.log(this); // `this` points to `c` object
}
}
c.log();
So, we can easily change the property of that object from the attached method of that object using this
keyword.
var c = {
name : 'The C object',
log : function() {
this.name = "updated C object"; // changing the property
console.log(this);
}
};
Let's create a function inside that method
var c = {
name : 'The C object',
log : function() {
this.name = "updated C object";
console.log(this);
var setName = function(newName) {
// this points to global object
this.name = newName;
}
setName("Updated Again, The C object");
console.log(this);
}
};
c.log();
It is sad but true that this
inside internal function points to the global object. But we expected that
this
will point to c object
. Let's see how can we solve this:
We can store the this
object to a variable in the first line of an object method. Then we can use that
variable instead of this
as objects are pass by reference!
var c = {
name : 'The C object',
log : function() {
var self = this;
self.name = "updated C object";
console.log(self);
var setName = function(newName) {
// this points to c object
self.name = newName;
}
setName("Updated Again, The C object");
console.log(self);
}
};
c.log();
JS arrays can hold anything!
Let's see an example
var arr = [
1,
false,
{
name : 'Tony',
address: '111 Main St.'
},
function(name) {
var greetings = 'Hello ';
console.log(greetings + name);
},
'holla'
]
arr[3](arr[2].name);
arr[3]("Ashik");
//output
Hello Tony
Hello Ashik
THE PARAMETERS YOU PASS TO A FUNCTION
javascript gives you a keyword of the same name which contains them all.
function greet (firstname,lastname,language) {
language = language || "en";
if(arguments.length === 0) {
console.log("Missing parameters");
console.log("--------------------");
return;
}
console.log(firstname);
console.log(lastname);
console.log(language);
console.log("----------");
}
greet();
greet("John");
greet("John","Doe");
greet("John","Doe","en");
//output
Missing parameters
--------------------
John
undefined
en
----------
John
Doe
en
----------
John
Doe
en
----------
function varArg() {
var sum=0;
for(var i = 0; i<arguments.length; i++) {
sum = sum + arguments[i];
}
console.log(sum);
}
varArg(10,20,30,40,50);
//output
150
function overloading is not supported in JS. But we can take some approach to make it
function greet(firstname,lastname,language) {
language = language || "en";
if(language === "en") {
console.log("Hello " + firstname + " " + lastname);
}
if(language === "bn") {
console.log("Holla " + firstname + " " + lastname);
}
}
function greetEnglish(firstname,lastname) {
greet(firstname,lastname,"en")
}
function greetBangla(firstname,lastname) {
greet(firstname,lastname,"bn");
}
greetEnglish("John","Doe");
greetBangla("Ashiqur","Rahman");
//output
Hello John Doe
Holla Ashiqur Rahman
In JS we can invoked the function at the time of its creation.
Let's see some example:
//using an Immediately Invoked function Expressions IIFEs
var greeting = function(name) {
return 'Hello ' + name;
}('Ashik');
console.log(greeting);
//output
Hello Ashik
Classical Example of IIFE
var firstName = 'Tony';
(function(name){
var greeting = 'Hello';
console.log(greeting + " " + name);
}(firstName));
//output
Hello Tony
A function which remembers its scope during the time of its declaration.
though execution context of greet() is popped up when the function is called,
the returned function can remember its scope chain when it is created. That's why `whattosay`
is available there.
function buildFunction() {
var arr = [];
for(var i=0; i<3; i++) {
arr.push(
function() {
console.log(i);
}
)
}
return arr;
}
var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();
//output
3
3
3
you might be thinking that output should be 0 1 2. But the thing is when buildFunction
returns an array,
The value of i is 3 and at the execution context of the buildFunction
i=3
and 3 array elements(functions)
are created. But they are not executed.
then execution context of buildFunction
popped up but whats on memory is still hanging around! So, when
fs0 is called it doesn't find i
in its own execution context but it is available on memory space of
the buildFunction
execution context.
Here, the value of i is 3. So, 3 is printed. Same thing happened when fs1 and fs2 invoked 👍
Factory just means the function that returns and makes other things for me.
function makeGreeting(language) {
return function(firstname, lastname) {
if (language === 'en') {
console.log('Hello ' + firstname + ' ' + lastname);
}
if (language === 'es') {
console.log('Hola ' + firstname + ' ' + lastname);
}
}
}
var greetEnglish = makeGreeting('en');
var greetSpanish = makeGreeting('es');
greetEnglish('John', 'Doe');
greetSpanish('John', 'Doe');
//output
Hello John Doe
Hola John Doe
Each time outer function (makeGreeting function) is invoked a new execution context will be created.
A FUNCTION YOU GIVE TO ANOTHER FUNCTION, TO BE RUN WHEN THE OTHER FUNCTION IS FINISHED.
So, the function you call(i.e. invoke) calls back
by calling the function you gave it when it finishes.
// Example of callback
function add(num1,num2) {
console.log(num1 + num2);
}
function sub(num1,num2) {
console.log(num1 - num2);
}
function func(num1,num2,callback) {
console.log("This gets executed first");
callback(num1,num2);
}
func(20,10,add);
func(20,10,sub);
//output
This gets executed first
30
This gets executed first
10
function tellMeWhenDone(callback) {
var a = 1000; // some work
var b = 2000; // some work
callback(); // the 'callback', it runs the function I give it!
}
tellMeWhenDone(function() {
console.log('I am done!');
});
//output
I am done
I call you, you call the function that I gave you
var person = {
firstName : 'John',
lastName: 'Doe',
getFullName : function() {
var fullName = this.firstName + " " + this.lastName;
return fullName;
}
}
var logName = function(lang1,lang2) {
console.log("Logged: " + this.getFullName());
}
In the above example, in this line, console.log("Logged: " + this.getFullName());
this points to global
object. But I can control it so that it can point to person
object. By using logName.bind()
we can create
a copy of the logName function and inside the parenthesis, we can give whatever object I want to point this
variable. Look at the snippet below:
logName.bind(person);
we can use bind
method like this:
var person = {
firstName : 'John',
lastName: 'Doe',
getFullName : function() {
var fullName = this.firstName + " " + this.lastName;
return fullName;
}
}
var logName = function(lang1,lang2) {
console.log("Logged: " + this.getFullName());
}
var personLogName = logName.bind(person);
personLogName();
//output
Logged: John Doe
We can also use bind
method like this
var person = {
firstName : 'John',
lastName: 'Doe',
getFullName : function() {
var fullName = this.firstName + " " + this.lastName;
return fullName;
}
}
var logName = function(lang1,lang2) {
console.log("Logged: " + this.getFullName());
}.bind(person);
logName();
//output
Logged: John Doe
So that, this.getFullName()
will now become person.getFullName()
var person = {
firstName : 'John',
lastName: 'Doe',
getFullName : function() {
var fullName = this.firstName + " " + this.lastName;
return fullName;
}
}
var logName = function(lang1,lang2) {
console.log("Logged: " + this.getFullName());
console.log('Arguments: ' + lang1 + ' ' + lang2);
console.log('-----------');
}
//bind
var logPersonName = logName.bind(person);
logPersonName("bangla","english");
// call
logName.call(person,"bangla","english");
//apply
logName.apply(person,["bangla","english"]);
//output
Arguments: bangla english
-----------
Logged: John Doe
Arguments: bangla english
-----------
Logged: John Doe
Arguments: bangla english
-----------
In Call()
and Apply()
we can give whatever object we want to point this
variable when we invoke that function!
Both are almost same but in apply()
we need to give function parameter within array
var man = {
firstName: 'Tony',
lastname: 'Alica',
getFullName : function() {
var fullName = this.firstName + " " + this.lastname;
return fullName;
}
};
var man2 = {
firstName : 'Ashiqur',
lastname : 'Rahman'
};
console.log(man.getFullName.apply(man2));
//output
Ashiqur Rahman
In the above example, both man and man2 object have same property firstName
and lastname
. I want to borrow
man2's
value of firstName
and lastname
by invoking man's
property. By using apply
or call
method we can get this feature.
CREATING A COPY OF A FUNCTION WITH SOME PRESET PARAMETERS
very useful in mathematical situations.
function multiply(a,b) {
return a*b;
}
var multiplyBy2 = multiply.bind(this,2);
console.log(multiplyBy2(4));
var mutiplyBy3 = multiply.bind(this,3);
console.log(mutiplyBy3(5));
//output
8
15
In the above example, we set a permanent value of parameter a
of multiply
function by using bind()
.
var multiplyBy2 = multiply.bind(this,2);
this code snippet set the value of a=2 which is permanent.
So when we invoke multuplyBy2
function, we can only give the value of b.
Another way of doing this:
var f = function(a,b) {
return a*b;
}.bind(this,2);
console.log(f(8));
console.log(f(6));
console.log("------------------");
//output
16
12
// Normal
var ara1 = [1,2,3];
console.log(ara1);
var ara2 = [];
for(var i =0; i<ara1.length; i++) {
ara2.push(ara1[i] * 2);
}
console.log(ara2);
console.log("---------------");
// Functional programming
function mapForEach(arr,fn) {
var newNum = [];
for(var i=0; i<arr.length; i++) {
newNum.push(
fn(arr[i])
)
};
return newNum;
}
var num1 = [1,2,3];
console.log(num1);
var num2 = mapForEach(num1,function(item){
return item*2;
});
console.log(num2);
var num3 = mapForEach(num1,function(item){
return item>2;
});
var checkPastLimit = function(limiter, item) {
return item > limiter;
}
var num4 = mapForEach(num1,checkPastLimit.bind(this,1));
console.log(num4);
var checkPastLimitSimplified = function(limiter) {
return function(limiter,item) {
return item>limiter;
}.bind(this,limiter);
}
var num5 = mapForEach(num1,checkPastLimitSimplified(2));
console.log(num5);
console.log(num3);
//output
[ 1, 2, 3 ]
[ 2, 4, 6 ]
---------------
[ 1, 2, 3 ]
[ 2, 4, 6 ]
[ false, false, true ]
[ false, true, true ]
[ false, false, true ]
// Find max,min,sum of an array using function programming
function araFunc(arr,fn) {
fn(arr);
}
// maximum element of the array
var ara = [10,20,40,30];
console.log("This is our array: " + ara);
araFunc(ara,function(ara){
for(var i =0; i<ara.length; i++) {
if(ara[0] < ara[i]) {
ara[0] = ara[i]
}
}
console.log("Highest element of the array: " + ara[0]);
});
console.log("--------------------");
//minimum element of the array
var ara1 = [4,1,43,2];
console.log("This is our array " + ara1);
araFunc(ara1,function(ara1){
for(var i=0; i<ara1.length; i++) {
if(ara1[0] > ara1[i]) {
ara1[0] = ara1[i]
}
}
console.log("Minimum element of the array: " + ara1[0]);
});
console.log("--------------------");
// sum of the array
var ara2 = [10,20,30,40];
console.log("This is our array " + ara2);
araFunc(ara2,function(ara2){
var sum=0;
for(var i=0; i<ara2.length; i++) {
sum += ara2[i];
}
console.log("Summation of the array: " + sum);
});
//output
This is our array: 10,20,40,30
Highest element of the array: 40
--------------------
This is our array 4,1,43,2
Minimum element of the array: 1
--------------------
This is our array 10,20,30,40
Summation of the array: 100
One Object gets access to the properties and methods of another object.
- Simple
- flexible
- extensible
- easy to understand.
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}
var john = {
firstname: 'John',
lastname: 'Doe'
}
// don't do this EVER! for demo purposes only!!!
john.__proto__ = person;
console.log(john.getFullName());
console.log(john.firstname);
var jane = {
firstname: 'Jane'
}
jane.__proto__ = person;
console.log(jane.getFullName());
person.getFormalFullName = function() {
return this.lastname + ', ' + this.firstname;
}
console.log(john.getFormalFullName());
console.log(jane.getFormalFullName());
//output
John Doe
John
Jane Default
Doe, John
Default, Jane
AN OBJECT CAN LOOK AT ITSELF, LISTENING AND CHANGING ITS PROPERTIES AND METHODS.
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}
var john = {
firstname: 'John',
lastname: 'Doe'
}
// don't do this EVER! for demo purposes only!!!
john.__proto__ = person;
for (var prop in john) {
if (john.hasOwnProperty(prop)) {
console.log(prop + ': ' + john[prop]);
}
}
var jane = {
address: '111 Main St.',
getFormalFullName: function() {
return this.lastname + ', ' + this.firstname;
}
}
var jim = {
getFirstName: function() {
return firstname;
}
}
_.extend(john, jane, jim);
console.log(john);
function Person() {
this.firstname = 'John';
this.lastname = 'Doe';
console.log("This function is invoked");
}
var john = new Person();
console.log(john);
//output
This function is invoked
Person { firstname: 'John', lastname: 'Doe' }
In the above example, new operator creates an empty
object and when the function is invoked this
variable points to the empty object. And then whatever I do with that empty object using this variable,
will end up as part of that object and that's what returned.
function Person(firstname,lastname) {
console.log(this);
this.firstname = firstname;
this.lastname = lastname;
console.log("This function is invoked");
}
var john = new Person("John","Doe");
console.log(john);
var jane = new Person("Jane","Doe");
console.log(jane);
//output
Person {}
This function is invoked
Person { firstname: 'John', lastname: 'Doe' }
Person {}
This function is invoked
Person { firstname: 'Jane', lastname: 'Doe' }
So, here I am constructing objects using functions.
A NORMAL FUNCTION THAT IS USED TO CONSTRUCT OBJECTS.
The this
variable point a new empty object and that empty object is returned from the function automatically
when the function finishes execution.
When you use function constructor it already sets the prototype for you.
The prototype
property on a function is not the prototype
of the function. It's the prototype
of any
objects created if you are using the function as function constructor.
When you call the new
keyword it creates an empty object. And it sets the prototype of that empty object
to the prototype property of the function that you call.
function Person(firstname, lastname) {
console.log(this);
this.firstname = firstname;
this.lastname = lastname;
console.log('This function is invoked.');
}
Person.prototype.getFullName = function() {
return this.firstname + ' ' + this.lastname;
}
var john = new Person('John', 'Doe');
console.log(john);
var jane = new Person('Jane', 'Doe');
console.log(jane);
Person.prototype.getFormalFullName = function() {
return this.lastname + ', ' + this.firstname;
}
console.log(john.getFormalFullName());
// output
Person {}
This function is invoked.
Person { firstname: 'John', lastname: 'Doe' }
Person {}
This function is invoked.
Person { firstname: 'Jane', lastname: 'Doe' }
Doe, John
So, john
and jane
both get access to the getFullName
method. Because it is their prototype.
var a = new String("ashik");
a.length;
//output
5
String.prototype.isLengthGreaterThan = function(limit) {
return this.length > limit;
}
console.log("Ashik".isLengthGreaterThan(3));
//output
true
Create an object and use these as the prototype for other objects. You give it to an object and that becomes the prototype of that new empty object.
var person = {
firstname: 'Default',
lastname: 'Default',
greet: function() {
return 'Hi ' + this.firstname;
}
}
var john = Object.create(person);
console.log(john.greet());
//hide default values
john.firstname = 'John';
john.lastname = 'Doe';
console.log(john.greet());
//output
Hi Default
Hi John
#POLYFILL CODE THAT ADDS A FEATURE WHICH THE ENGINE MAY LACK.
// polyfill
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation'
+ ' only accepts the first parameter.');
}
function F() {}
F.prototype = o;
return new F();
};
}
var person = {
firstname: 'Default',
lastname: 'Default',
greet: function() {
return 'Hi ' + this.firstname;
}
}
var john = Object.create(person);
john.firstname = 'John';
john.lastname = 'Doe';
console.log(john);