Vanilla javascript

 

What My Mum Didn't Tell Me

TOPICS

  • Functions
  • IIFE
  • Closure
  • Revealing Module Pattern
  • Prototype Design Pattern

javascript drives me crazy!

JavaScript can be nice to you but it can also drive you crazy. For instance there are seven different ways of declaring functions in JavaScript.

function A(){};            
var B = function(){};       
var C = (function(){});    
var D = function foo(){};  
var E = (function(){       
  return function(){}
})();
var F = new Function();    
var G = new function(){};

Question 1?

A();
function A(){
    console.log("Just keep swimming.");
};
function A(){
    console.log("Just keep swimming.");
};
A();

function HOISTING

// "Just keep swimming."

Question 2?

A();
var A = function (){
    console.log("Just keep swimming.");
};
var A;
A();
A = function (){
    console.log("Just keep swimming.");
};

variable HOISTING

The function name is optional in function expressions, and we call these anonymous.

// Uncaught TypeError: A is not a function(…)

Question 3?

function(){};
(function(){});

Function expressions

The first example will get a syntax error since a function declaration must have a name.

The second example is using grouping operators and is therefore evaluated differently. 

(function(){} + "I think I can."); 
// "function(){}I think I can."

i love my IIFE 

Show of hands who ever needed to define a function and then immediately execute it?

(function() {
    console.log("Shall we play a game?");
})();
function login(){
    console.log("Shall we play a game?");
};
login();

IMMEDIATELY-INVOKED FUNCTION EXECUTION

err... but i need it again 

var login; 
(login = function(player) {
    console.log(player + " shall we play a game?");
})("Joshua");
var login;
(login = function() {
    console.log("Shall we play a game?");
})();

err... but i need to pass in parameter

// Shall we play a game?
login();
// Shall we play a game?
login("Spock")
// Joshua shall we play a game?
// Spock shall we play a game?

dO i need a iife?

(function() {
    var foo = "I've a feeling we're not in Kansas anymore"
    console.log(foo);
})();
// I've a feeling we're not in Kansas anymore
console.log(foo);
// ReferenceError: foo is not defined

Local variables declared using the var keyword are scoped to the enclosing function.

var foo = "There's no place like home"
console.log(foo);
// There's no place like home

(function(){
    console.log(foo);
})()
// There's no place like home

If no function exists, the variables will be created as global variable instead, thus polluting the global scope. To prevent this, we can use an IIFE to create a function wrapper for local variables.

question 4?

It will print 3, three times since the for loop would have finished before the console.logs are executed.

for (var i=0; i<3; i++){
    setTimeout(function(){
        console.log(i);
    },1000);
}
for (var i=0; i<3; i++){
    setTimeout(function(){
        console.log(i);
    },1000);
}

// 3,3,3

If I want to print 0,1,2 instead of 3,3,3 what do I need to do?

Closure

for (var i=0; i<3; i++){
    (function(print){
        setTimeout(function(){
            console.log(print);
        },1000);
    })(i)
}

A closure is an inner function that has access to the outer enclosing function's variables. The closure has three scope chains:

  1. It has access to its own scope
  2. It has access to the outer function's variables
  3. Access to the the global variables

Question 5?

var add = (function(){
    var counter = 0;
    return function(){
        counter++;
        console.log(counter);
    };
})();

The self-invoking function only runs once and returns a function expression. Add is now a function and it can access the counter in the parent scope. Therefore, it is possible for a function to have "private" variables.

add();
// 2
add();
// 3
add();
// 1

show me the money

var TimeMachine = {
    speed : function() {
        return "88";
    },
    future : function() {
        console.log("We don't have enough road to get up to "+this.speed()+".
                        Where we're going, we don't need roads");
    },
    past : function() {
        console.log("When this baby hits "+this.speed()+" miles an hour,
                        you're going to see some serious stuff");
    }
};
TimeMachine.speed();

Sometimes we have functions which are common to others so we would like to extract them out. In this case we want to extract out speed to be use by both future and past function.

// 88

GREAT SCOTT

var TimeMachine = (function(){
    var deLorean = {};
    var speed = function() {
        return "88";
    };
    deLorean.future = function() {
        console.log("We don't have enough road to get up to "+speed()+".
                    Where we're going, we don't need roads");
    };
    deLorean.past = function() {
        console.log("When this baby hits "+speed()+" miles an hour,
                    you're going to see some serious stuff");
    };
    return deLorean;
})();
TimeMachine.speed();

We do not want others to know the speed, so we need to hide speed and make it a private function.

// Uncaught TypeError: TimeMachine.speed is not a function(…)

Defining speed with var will now make the function private.

THE rEVEALING MODULE PATTERN

var TimeMachine = (function(){
    var speed = function() {
        return "88";
    };
    var future = function() {
        console.log("We don't have enough road to get up to "+speed()+".
                    Where we're going, we don't need roads");
    };
    var past = function() {
        console.log("When this baby hits "+speed()+" miles an hour,
                    you're going to see some serious stuff");
    };
    return {
        forward : future,
        backward : past
    };
})();

We've defined what we want to return along with the name, and anything that's not in that return object is "private" and can't be called by the public.

TimeMachine.future();
// Uncaught TypeError: TimeMachine.future is not a function(…)

Constructor pattern

function Tesla(){
    this.model = "X";
    this.print = function(){
        console.log("Tesla X");
    };
}
var myFirstCar = new Tesla();
myFirstCar.print();            // Tesla X
Tesla.print = function(){
    console.log("Tesla Model X!!!");
};
myFirstCar.print();    

What will happen to myFirstCar's print method if we defined a print function on Tesla class?

// Tesla X

You had me at new

Method are copied to all new object instances. 

prototype

A prototype is an object from which other objects inherit properties. Think of the prototype attribute as a characteristic of the object; this characteristic tell us the object's "parent". In simple terms: An object's prototype attribute points to the object's "parent".

Houston, we have a problem

function Tesla(){
    this.model = "X";
}
Tesla.prototype.drive = function(){
    console.log("Driving Tesla Model "+this.model);
};

var myFirstCar = new Tesla();
Tesla.prototype.drive = function(){
    console.log("Autopilot on for Tesla Model "+this.model);
};
myFirstCar.drive();
// Autopilot on for Tesla Model X
myFirstCar.drive();
// Driving Tesla Model X

The drive function is now not deep copied to each other but shared and inherited by all

sharing is caring

function Tesla(){
    this.model = "X";
}
Tesla.prototype = {
    speed : 155,
    drive : function(){
        console.log("Driving Tesla Model "+this.model);
    }
}
var myFirstCar = new Tesla();
var myOtherCar = new Tesla();
myFirstCar.speed // 155
myFirstCar.__proto__.speed = 160

The prototype property does not only apply to methods but also to properties. In this case speed is shared with all Tesla objects.

myFirstCar.speed // 160
myOtherCar.speed 
// 160

My mother thanks you.

My father thanks you.

My sister thanks you.

And I thank you.

Made with Slides.com