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 anymoreconsole.log(foo);
// ReferenceError: foo is not definedLocal 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 homeIf 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,3If 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:
- It has access to its own scope
- It has access to the outer function's variables
- 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();// 2add();// 3add();// 1show 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.
// 88GREAT 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 XTesla.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 XmyFirstCar.drive();// Driving Tesla Model XThe 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 // 155myFirstCar.__proto__.speed = 160The prototype property does not only apply to methods but also to properties. In this case speed is shared with all Tesla objects.
myFirstCar.speed // 160myOtherCar.speed // 160My mother thanks you.
My father thanks you.
My sister thanks you.
And I thank you.
vanillajs
By Thomas Truong
vanillajs
- 73