What My Mum Didn't Tell Me
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(){};A();
function A(){
console.log("Just keep swimming.");
};function A(){
console.log("Just keep swimming.");
};
A();// "Just keep swimming."A();
var A = function (){
console.log("Just keep swimming.");
};var A;
A();
A = function (){
console.log("Just keep swimming.");
};
The function name is optional in function expressions, and we call these anonymous.
// Uncaught TypeError: A is not a function(…)function(){};
(function(){});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."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();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?");
})();
// 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?(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.
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?
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:
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();// 1var 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.
// 88var 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.
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(…)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
Method are copied to all new object instances.
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".
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
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 // 160