Skip to content

Instantly share code, notes, and snippets.

@shafayeatsumit
Forked from LearningMaterial/a) understandJS.md
Created October 10, 2017 05:28
Show Gist options
  • Save shafayeatsumit/0e9251bbddefc3390ff88456d197ccdd to your computer and use it in GitHub Desktop.
Save shafayeatsumit/0e9251bbddefc3390ff88456d197ccdd to your computer and use it in GitHub Desktop.
Notes of Javascript_The_Weird_Parts

Javascript Understanding The Weird Parts

Conceptual Aside

# Syntax Parsers
# Lexical Environments
# Execution Contexts

Syntax Parsers

       A PROGRAM THAT READS YOUR CODE AND DETERMINES WHAT IT DOES AND IF ITS GRAMMER IS VALID

Lexical Environments

        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

Execution Context:

     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.

NAME/VALUE PAIR

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

OBJECT

A COLLECTION OF NAME VALUE PAIRS
The simplest definition when talking about `JS`

Example

 Address : {
       Street: 'Main',
       Number: 100;
       Apartment: {
           Floor: 3,
           Number: 101
        }

  }

Execution Context (Global)

# Whenever we write a JS code an execution context will be created and run. The base execution context is the `global
execution context`

Global Execution context creates 2 things for us

   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.

Window Object

 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 happening when you run a Js code. compilation and interpretation. In the compilation phase no assignment operation will be happened. And in the interpretation phase the actual execution will take place.

In the avobe example.

         At `compilation` phase variable a (only declaration)  and function b will sits in the global scope. After that
         `interpretation` phase will be occured. 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 varible called a is
         declared but it doedn't know the value of a. This behaviour is called `HOISTING`.

In the avobe example

At the compilation phase

     `function b` and function `a` sits in the global execution context. 

And in the interpretation phase

      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

In the above example,

At the compilation phase

function b, function a and variable myvar will sits in the global execution context.

At the interpretation phase,

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.

Dynamic Typing

    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.

Example of Dynamic Typing

var isNew =  true;
isNew = 'Yup';
isNew = 1;

Primitive Types

A TYPE OF DATA THAT REPRESENTS A SINGLE VALUE

Classification of primitive types:-

undefined

  undefines represents lack of existence (`you shouldn't set a variable to this`)

null

  null also represents lack of existence (`you can set a variable to this`)

boolean

 true or false

number

floating point number(there's always some decimals). Unlike other programming languages, there's
only one `number` type... and it can make math weird.

string

a sequence of characters (both '' and "" can be used).

symbol

used in ES6.

Operators

A SPECIAL FUNCTION THAT IS SYNTACTICALLY (WRITTEN) DIFFERENTLY

generally operators take two parameters and return one result.

Operator Precedence and Associativity

Operator Presidence

   WHICH OPERATOR FUNCTION GETS CALLED FIRST

Functions are called in order of precedence. (Higher presidency wins)

Associativity

  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:

In the above example,

    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.

Coercion

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

Comparison Operators

Example of comparison Operators are given below:-

In the above example,

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!

"==" vs "==="

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!

Benefits of type coercion

var a;

// goes to internet and looks for a value

if(a) {
    console.log("Something is there");
}

In the above example,

  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.

Let's see another example:-

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

We will see couple of examples to solidify our type coercion concept

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.

Default values

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>

In the above example

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. 👍

Objects and dots

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];

Objects and Objects Literals

Object Literals

var person = {};

Example of Object Literals

var person = {
    firstname: 'Ashiqur',
    lastname: 'Rahman',

    address: {
        street: '111 Main St.',
        city: 'New York',
        state: 'NY'
    }
};

Pass object to javascript function

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

Creating Object on the fly

      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

Namespace

  A CONTAINER FOR VARIABLES AND FUNCTIONS

Typically to keep variables and functions with the same name separate. We don't have namespace in Javascript

Faking namespaces

      We can create namespace by creating objects.

Examples of faking namespace

//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. 👍

JSON and OBJECT Literals

{
  "firstname" : "Ashiqur",
  "isAProgrammer" : true
}

In JSON properties have to be wrapped in quotes.

Conversion of Object literals to JSON and vice versa

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 }

FIRST CLASS FUNCTIONS:

EVERYTHING YOU CAN DO WITH OTHER TYPES YOU CAN DO WITH FUNCTIONS

Assign them to variables, pass them around, create them on the fly.

Example

function greet() {
    console.log("Hi");
}

greet.language = "Engish";

console.log(greet.language);

// output
// English

Function Statements AND function expressions

Expression

A UNIT OF CODE THAT RESULTS IN A VALUE

it doesn't have to save to a variable.

Example of function expression

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.

Pass a function as parameter

function happy(fn) {
    fn();
}

happy(function(){
    console.log("I passed as a function parameter");
});

//output
// I passed as a function parameter

By value vs By reference

 Primitives are passed by value
 Objects are passed by reference

Example

// 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!' }

Objects Function and this

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();

Arrays - Collection of Anything

       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

arguments

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
----------

Another example

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 in JS

       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

Immediately Invoked Function Expressions IIFEs

 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

Understanding Closures

A function which remembers its scope during the time of its declaration.

From the previous photo we can see that,

       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.

Another Example:

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 👍

Function Factory

 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.

CALLBACK FUNCTION

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

Another example

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

Call(), Apply(), Bind()

Bind()

Lets see an example

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()

Call() and Apply()

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

Function borrowing

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.

Function Currying

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

Functional Programming

Let's see some example:

// 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 ]

More examples

// 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

Object-oriented Javascript and prototypal inheritance

Inheritance

   One Object gets access to the properties and methods of another object.

PROTOTYPAL INHERITANCE

  • 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

Reflection:

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 Constructors new and the History of JavaScript

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.

Another example

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.

Function Constructors

 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.

Function Constructors and 'PROTOTYPE'

   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.

Built-in function constructors

var a = new String("ashik");
a.length;

//output
5

Add feature

String.prototype.isLengthGreaterThan = function(limit) {
    return this.length > limit; 
}

console.log("Ashik".isLengthGreaterThan(3));

//output
true

Object.create and Pure Prototypal Inheritance

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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment