var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"John",
lastName: "Doe"
}
var person2 = {
firstName:"Mary",
lastName: "Doe"
}
person.fullName.call(person1); // Will return "John Doe"
(function(){
const temp = 'World';
console.log(`Hello ${temp}`);
})();
// 'Hello World'
// this function has two blocks, same var name that run independently
(function() {
// block A
const name = 'Block A';
console.log(`Hello from ${name}`);
}());
(function() {
// block B
const name = 'Block B';
console.log(`Hello from ${name}`);
}());
// Hello from Block A
// Hello from Block B
function party(){
// this one runs
console.log('Wow this is amazing!');
party = function(){
// then when it is set to a variable it only returns this new definition
console.log('Been there, got the T-Shirt');
}
}
const beachParty = party; // note that the party function has not been invoked
beachParty(); // the party() function has now been redefined, even though it hasn't been called
explicitly
// 'Wow this is amazing!'
party();
// 'Been there, got the T-Shirt'
beachParty(); // but this function hasn't been redefined
// 'Wow this is amazing!'
beachParty(); // no matter how many times this is called it will remain the same
// 'Wow this is amazing!'
// Losing properties *****************
party.music = 'Classical Jazz'; // set a property of the function
party();
// "Wow this is amazing!"
party.music; // function has now been redefined, so the property doesn't exist
// undefined
function factorial(n) {
if (n === 0) {
return 1;
} else {
return n * factorial(n - 1); // keeps going until it reaches the condition
}
}
Chapter 4. You’ll recall that they’re functions passed to other functions as arguments and then invoked
inside the function they are passed to
****** remember nested callbacks can be ugly *******
function sing(song,callback) {
console.log(`I'm singing along to ${song}.`);
callback();
}
function dance() {
console.log("I'm moving my body to the groove.");
//( We’re just logging a simple message to the console in these examples, but these functions could be used
to do anything in a practical sense.)
}
sing('Let It Go',dance);
// 'I'm singing along to Let It Go.'
// 'I'm moving my body to the groove.'
A promise represents the future result of an asynchronous operation
Promises don't do anything that can't already be achieved using callbacks,
but they help simplify the process, and avoid the convoluted code that can
result from using multiple callbacks.
const promise = new Promise( (resolve, reject) => {
// initialization code goes here
if (success) {
resolve(value);
} else {
reject(error);
}
});
returning one of two outcomes:
Resolved ― the asynchronous operation was completed successfully.
Rejected ― the asynchronous operation didn’t work as expected, wasn't successfully completed or resulted in
an error.
// an example
const dice = {
sides: 6,
roll() {
return Math.floor(this.sides * Math.random()) + 1;
}
}
console.log('Before the roll');
const promise = new Promise( (resolve,reject) => {
const n = dice.roll();
setTimeout(() => {
(n > 1) ? resolve(n) : reject(n);
}, n*1000);
});
promise.then( result => console.log(`I rolled a ${result}`) )
.catch( result => console.log(`Drat! ... I rolled a ${result}`) );
console.log('After the roll');
Allowing more than one process to happen (still single threaded though), and more importantly out of order -
callbacks can handle some of this too.
function wait(message, callback, seconds){
setTimeout(callback,seconds * 1000);
console.log(message);
}
function selfDestruct(){
console.log('BOOOOM!');
}
invoke the wait() function then log a message to the console, we can see how JavaScript works
asynchronously:
wait('This tape will self-destruct in five seconds ... ', selfDestruct, 5);
console.log('Hmmm, should I accept this mission or not ... ?');
// 'This tape will self-destruct in five seconds ... '
// 'Hmmm, should I accept this mission or not ... ? '
// 'BOOOOM!'
// this one uses eval() that will give the scope valuation of a string.
const x = 1;
function evalAndReturnX(code) {
eval(code);
return x;
}
console.log(evalAndReturnX("var x = 2"));
// → 2
console.log(x);
// → 1
// this is a function constructor that takes in the comma separated arguements and following is the function
- no scope problems here
let plusOne = Function("n", "return n + 1;");
console.log(plusOne(4));
// → 5
*****************************
function greeter(greeting = 'Hello') {
return function() {
console.log(greeting);
}
}
const englishGreeter = greeter();
englishGreeter();
// Hello
const frenchGreeter = greeter('Bonjour');
frenchGreeter();
// Bonjour
const germanGreeter = greeter('Guten Tag');
germanGreeter();
// Guten Tag
Closures are one of JavaScript’s most powerful features
Functions declared from within another function have access to any variables declared in the outer
function’s scope.
function outer() {
const outside = 'Outside!';
function inner() {
const inside = 'Inside!';
console.log(outside);
console.log(inside);
}
return inner;
}
const closure = outer(); // now assign a variable to the return value of the outer() function
It now has access to the variables created insideboththe outer() and inner() functions
closure();
// Outside!
Inside!
// This allows some skirting around scope and gives access to inside variables.
function closure() {
const a = 1.8;
const b = 32;
return c => c * a + b;
}
const toFahrenheit = closure();
toFahrenheit(30); // 86
JavaScript has always supported functional-style programming due to functions being first-class objects.
The ability to pass functions as arguments, return them from other functions, and use anonymous functions
and closures, are all fundamental elements of functional programming that JavaScript excels at.
PURE FUNCTIONS
1. return value of a pure function should only depend on the values provided as arguments
2. There are no side-effects. A pure function doesn't change any values or data elsewhere in the program.
3. Referential transparency. Given the same arguments, a pure function will always return the same result.
// example
function reverse(string) {
return string.split('').reverse().join('');
}
const message = 'Hello JavaScript';
reverse(message); // 'tpircSavaJ olleH'
message // hasn't changed // 'Hello JavaScript'
Currying allows you to turn a single function into a series of functions instead.
This is useful if you find that you’re frequently calling a function with the same argument.
For example, the following multiplier() function is a generic function that returns the product of two
numbers that are provided as arguments:
function multiplier(x,y) {
return x * y;
}
// calculate a tax rate of 22% on a £400 sale using 0.22 and 400 as arguments
const tax = multiplier(0.22,400); // 88
// code at the start that allows it to be curried
function multiplier(x,y) {
if (y === undefined) {
return function(z) {
return x * z;
}
} else {
return x * y;
}
}
* Functions have built-in properties such as length , but can have custom properties added.
* All functions have call() and apply() methods that can invoke a function with the value of this bound
to an object that is provided as an argument.
* Immediately Invoked Function Expressions or IIFEs are functions that are enclosed in parentheses and
immediately followed by double parentheses so they’re invoked. They are useful for namespacing variables and
setting default values.
* Functions are able to dynamically redefine themselves in the body of the function, depending on
certain conditions.
* A recursive function will keep invoking itself until a certain condition is met.
* A callback is a function that’s provided as an argument to another function.
* Callbacks are frequently used in asynchronous programming as part of the event loop. This means that
a program can continue to run in a single thread while waiting for another task to be completed.
* Promises can be used instead of callbacks to deal with multiple asynchronous actions in sequence.
They also provide a nicer mechanism for handling errors.
* Functions that return other functions are known as higher-order functions.
* A closure is the process of keeping a reference to a variable available outside the scope of the
function it was originally defined in.
* A generator is created by placing an asterisk character (*) after the function keyword.
* A generator function will return an iterator object that provides a next() method, which returns the
next value in a sequence that is defined in the generator function.
* unctional programming involves breaking processes down into steps that can be applied as a series of
functions.
* Pure functions are functions that don't rely on the state of the code they are called from, have no
side-effects, and always give the same result when given the same arguments (referential transparency).
* Currying or partial application is the process of applying one argument at a time to a function. A new
function is returned until all the arguments have been used.