Master
JavaScript
Functions
JavaScript has First Class Functions, meaning that functions can be treated just like other data types
function takeResult(anotherFunc) {
var result = anotherFunc();
return `The result is ${result}.`.
}
// assign an anonymous function to a variable
var giveHamster = function() {
return 'hamster';
}
takeResult(giveHamster); // The result is hamster.
/**
* Unnecessarily complicated higher order
* greet function that takes a name and returns a function
*
* @param {string} name - person to greet
* @returns {function} - the function to call that greets
*/
function greet(name) {
return function inner() {
return `hello ${name}`;
};
}
var pointsToInnerFunc = greet('Whiskey');
pointsToInnerFunc(); // hello Whiskey
function myForEach(arr, cb) {
for (let i = 0; i < arr.length; i++) {
cb(arr[i], i);
}
}
This HOF takes a callback!
myForEach(['matt', 'elie', 'joel'], function(item, idx) {
console.log(`${item} is at index ${idx}`);
});
/*
matt is at index 0
elie is at index 1
joel is at index 2
*/
Lots of built-in functions in JavaScript are Higher Order Functions ( HOFs) that are designed to accept callbacks.
The callback pattern usually looks like this:
function greeting(name) {
alert('Hello ' + name);
}
function processUserInput(callback) {
var name = prompt('Please enter your name.');
callback(name);
}
processUserInput(greeting);
Usually callbacks are defined in-line with anonymous functions.
function eachItem(obj, cb) {
for (let key in obj) {
cb(key, obj[key]);
}
}
let obj = { name: 'Whiskey', otherName: 'Hazel' };
eachItem(obj, function(key, val) {
console.log('The key is ' + key + '. the value is ' + val + '.');
});
// The key is name. The value is Whiskey.
// The key is otherName. The value is Hazel.
We'll discuss the following functions that all take callbacks:
1. setTimeOut
2. Array forEach
3. Array map
4. Array filter
5. Array reduce
6. Array sort
setTimeout(function() {
alert('yoooo');
}, 1000);
[1,2,3].forEach(function(element, index) {
console.log(element, index);
});
/*
1 0
2 1
3 2
*/
var oldArr = [1,2,3];
var newArr = oldArr.map(function(element, index) {
return element * index;
});
console.log(newArr);
/*
[0, 2, 6]
*/
var oldArr = [1,2,3,4,5,6,7,8,9,10]
var newArr = oldArr.filter(function(element, index) {
return element % 2 === 0;
});
console.log(newArr);
/*
[2, 4, 6, 8, 10]
*/
var oldArr = [3, 2, 1]
var countDown = oldArr.reduce(function(previous, current, index) {
return previous + ' ' + current;
}, "ready");
console.log(countDown);
/*
ready 3 2 1;
*/
var myArr = [10, 3, 2, 7, 9, 11, 1];
myArr.sort(function(a, b) {
return a - b;
})
console.log(myArr);
/*
1, 2, 3, 7, 9, 10, 11
*/
myFunc
()
{ myFunc }
function myFunc(callback) {
return callback();
}
function myCallBack() {
console.log('foo');
}
myFunc(myCallBack);
myCallback
()
{ myFunc }
{ myCallback }
function myFunc(callback) {
return callback();
}
function myCallBack() {
console.log('foo');
}
myFunc(myCallBack);
As functions return, their call objects get popped off the top of the call stack, and the next item down resumes execution until the stack is empty
{ myFunc }
{ myCallback }
{ myFunc }
return
return
Each call object carries a reference to its scope as well as its parents' scopes via its execution context.
{ myFunc }
{ myCallback }
function myFunc(callback) {
return callback();
}
function myCallBack() {
console.log('foo');
}
myFunc(myCallBack);
Closure is when an inner function "remembers" variables in the outer function's scope...even after the outer function has executed.
We say variables are "closed over."
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
The inner function must reference the count variable of its parent for closure to occur!
/**
* A Higher Order Function w/closure
*/
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
var myCounter = closureCounter();
{ closureCounter }
Call Stack
Memory Heap
/**
* A Higher Order Function w/closure
*/
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
var myCounter = closureCounter();
{ count }
Call Stack
Memory Heap
/**
* A Higher Order Function w/closure
*/
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
var myCounter = closureCounter();
myCounter(); // 1
{ count }
{ innerFunction }
Call Stack
Memory Heap
/**
* A Higher Order Function w/closure
*/
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
var myCounter = closureCounter();
myCounter(); // 1
myCounter(); // 2
{ count }
{ innerFunction }
Call Stack
Memory Heap
/**
* A Higher Order Function w/closure
*/
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
var myCounter = closureCounter();
myCounter(); // 1
myCounter(); // 2
var mySecondCounter = closureCounter();
{ count }
Call Stack
Memory Heap
{ closureCounter }
/**
* A Higher Order Function w/closure
*/
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
var myCounter = closureCounter();
myCounter(); // 1
myCounter(); // 2
var mySecondCounter = closureCounter();
mySecondCounter(); // 1
{ count }
Call Stack
Memory Heap
{ count }
{ innerFunction }
/**
* A Higher Order Function w/closure
*/
function closureCounter() {
var count = 0;
return function innerFunction() {
return ++count;
};
}
var myCounter = closureCounter();
myCounter(); // 1
myCounter(); // 2
var mySecondCounter = closureCounter();
mySecondCounter(); // 1
myCounter(); // 3
{ count }
Call Stack
Memory Heap
{ count }
{ innerFunction }
One of the two main patterns in JavaScript programming is the module pattern, which groups programs into functions called modules.
var myModule = (function(){
var private = { name: 'nobody' };
return {
getName: function() {
return private.name;
},
setName: function(newName) {
private.name = newName;
return newName;
}
};
})();
myModule.getName(); // "nobody"
myModule.setName('Elie');
myModule.getName(); // "Elie"
Encapsulation - the ability to restrict access to private stuff
Flexible namespace, for example jQuery is a module aliased as $.
What benefits does this give us?
function outer() { // step 1
var count = 0; // step 2
return function inner() { // step 3
return ++count; // step 4
}
}
var myCounter = outer(); // step 5