# Mastering Every Aspect of JavaScript Functions with Ease in 30 Minutes

JavaScript functions are very useful for code development and maintenance.

I should mention the previous articles in the JavaScript Definitive Guide:

This article will introduce the following contents:

## Why we need JavaScript Functions?

A JavaScript function is a block of code designed to perform a specific task.

We know that the area calculation formula for a circle is:

S = π r 2

When we know the radius `r` of a circle, we can calculate the area according to the formula. Suppose we need to calculate the area of ​​three different circles:

``````var r1 = 12.34;
var r2 = 9.08;
var r3 = 73.1;
var s1 = 3.14 * r1 * r1;
var s2 = 3.14 * r2 * r2;
var s3 = 3.14 * r3 * r3;``````

When the code appears to be regularly repeated, you need to be careful. It is troublesome and inflexible to write `3.14 * x * x` many times. What if you want to change `3.14` to  `3.14159265359`?

With a function, we don’t have to write `s = 3.14 * x * x` over and over again. Instead we make a more meaningful function call, e.g., `s = area_of_circle(x)`. And the function `area_of_circle` itself only needs to be defined once, while we can invoke it multiple times.

Basically all high-level languages ​​support functions, and JavaScript is no exception. JavaScript functions are not only “first class citizens”, but also can be used like variables, with very powerful abstraction capabilities.

## Abstraction

Abstraction is a very common concept in mathematics. For example:

Calculating the sum of the series: `1 + 2 + 3 + ... + 100`, is very inconvenient to write. So the mathematician invented the summation symbol, which can be written as:

This abstract notation is very powerful, because we can see that the ∑ symbol can be understood as summation, rather than being reduced to a low-level addition.

Moreover, this abstract notation is extensible, such as:

In fact, this formula is: (1 * 1 + 1) + (2 * 2 + 1) + (3 * 3 + 1) + … + (100 * 100 + 1).

With abstraction, we do not need to consider the underlying specific computing process, but directly solve the problem at a higher level.

When writing computer programs, functions are the most basic way of abstracting code.

## Function Definition and Invocation

### Defining Function

In JavaScript, the way to define a function is as follows:

``````function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}``````

The above `abs()` function is defined as follows:

• The `function` keyword indicates that this is a function definition;
• `abs` is the name of the function;
• `(x)` The parameters of the function are listed in parentheses, and multiple parameters are separated by `,`;
• `{...}` The code between the brackets is the function body. It contain several statements.

Note that once the `return` statement inside the function body is executed, the function is terminated and the result is returned. Therefore, the function can internally implement very complex logic through conditional judgment and looping.

If there is no `return` statement, the result will be returned after the function is executed, but the result is `undefined`.

Since the JavaScript function is also an object, the `abs()` function defined above is actually a function object, and the function name `abs` can be treated as a variable pointing to the function.

Therefore, the second way to define a function is as follows:

``````var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};``````

In this way, `function (x) { ... }` is an anonymous function that has no function name. However, this anonymous function is assigned to the variable `abs`, so the anonymous function can be called by the variable `abs`.

The above two definitions are completely equivalent . Note that the second method needs to add one semicolon `;` at the end of the function body, indicating the end of the assignment statement.

### Function Calls

When a function is called, the parameters are passed in order:

``````abs(10); // => 10
abs(-9); // => 9``````

JavaScript allows you to input any number of arguments without affecting the call. More arguments can be passed into a function, although they are not needed inside the function:

``````abs(10, 'blablabla'); // => 10
abs(-9, 'haha', 'hehe', null); // => 9``````

You can also call a function with no parameters. But this may cause unexpected behaviour.

``abs(); // => NaN``

At this point the parameter `x` of the function `abs(x)` will be set to `undefined` and the result of the calculation is `NaN`.

To avoid receiving `undefined`, you can check the parameters:

``````function abs(x) {
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}``````

### Arguments

JavaScript also has a keyword `arguments` that works only inside functions. The keyword always points to all parameters passed in by the caller of the current function.

With `arguments`, you can get all the parameters passed in by the caller. That is, even if the function does not define any parameters, you can still get the value of the parameter:

``````function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}

abs(); // 0
abs(10); // 10
abs(-9); // 9``````

### Rest Parameters

Since the JavaScript function allows to receive any number of parameters, so we have to use `arguments` to get all the parameters:

``````function foo(a, b) {
var i, rest = [];
if (arguments.length > 2) {
for (i = 2; i<arguments.length; i++) {
rest.push(arguments[i]);
}
}
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}``````

In order to get the parameters other than the defined parameters `a``b`we have to use `arguments`, and then loop the index starting from 2 in order to exclude the first two parameters. This is very awkward. Is there a better way to get additional `rest` parameters?

The ES6 standard introduces the rest parameter, and the above function can be rewritten as:

``````function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}

foo(1, 2, 3, 4, 5);
// Result:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

foo(1);
// Result:
// a = 1
// b = undefined
// Array []``````

The rest parameter can only be written at the end, with the `...` identifier in front. From the running result, the parameters passed in are first bounded to `a``b` and the extra parameters are passed to the variable  `rest` in the form of an array. Therefore, we no longer need to use `arguments` to get all the parameters.

If the parameters passed in are not filled with the normally defined parameters, it does not matter. The rest parameter will receive an empty array (note that it is not `undefined`).

WARNING: The `arguments` feature is no longer recommended. Use the rest parameter.

Because the rest parameter is a new ES6 feature, you need to test if the browser supports it. Write a `sum()` function with the rest parameter , receive any arguments and return their sum:

``````'use strict';

// TODO: Write the sum function.
function sum() {

}

// test:
var i, args = [];
for (i=1; i<=100; i++) {
args.push(i);
}
if (sum() !== 0) {
console.log('Test failed: sum() = ' + sum());
} else if (sum(1) !== 1) {
console.log('Test failed: sum(1) = ' + sum(1));
} else if (sum(2, 3) !== 5) {
console.log('Test failed: sum(2, 3) = ' + sum(2, 3));
} else if (sum.apply(null, args) !== 5050) {
console.log('Test failed: sum(1, 2, 3, ..., 100) = ' + sum.apply(null, args));
} else {
console.log('test passed!');
}``````

### Be careful with your return statement

We have talked about the JavaScript engine that it has a mechanism to automatically add a semicolon at the end of the line, which may allow you to encounter a large pitfall of the `return` statement:

``````function foo() {
return { name: 'foo' };
}

foo(); // { name: 'foo' }``````

If you split the return statement into two lines:

``````function foo() {
return
{ name: 'foo' };
}

foo(); // undefined``````

Be careful , because the JavaScript engine automatically adds a semicolon mechanism at the end of the line, the above code actually becomes:

``````function foo() {
return; // A semicolon is automatically added, which is equivalent to return undefined;
{ name: 'foo' }; // This line of statements has not been executed.
}``````

So the correct multi-line writing is:

``````function foo() {
return { // There is no automatic semicolon here, because { indicates that the statement has not ended yet.
name: 'foo'
};
}``````

### Exercise 1

Define a function `area_of_circle()` that calculates the area of ​​a circle . It has two parameters:

• r: indicates the radius of the circle;
• Pi: indicates the value of π, if not, the default is 3.14
``````'use strict';

function area_of_circle(r, pi) {
}
// Test:
if (area_of_circle(2) === 12.56 && area_of_circle(2, 3.1416) === 12.5664) {
console.log('test passed');
} else {
console.log('test failed');
}``````

John is a JavaScript rookie. He wrote a `max()` function that returns the larger of the two numbers:

``````'use strict';

function max(a, b) {

if (a > b) {
return
a;
} else {
return
b;
}
}
console.log(max(15, 20));``````

But John complained that his browser is flawed, and the `max()` function always returns `undefined` no matter what numbers have been passed in. Please help him point out the bug and fix it.

## Variable Scope and Deconstruction Assignment

In JavaScript, variables declared by the `var` keyword is actually scoped.

If a variable is declared inside a function body, the scope of the variable is the entire function body, and the variable cannot be referenced outside the function body:

``````'use strict';

function foo() {
var x = 1;
x = x + 1;
}

x = x + 2; // ReferenceError! Unable to reference variable x outside of function``````

If two different functions declare the same variable, then the variable only works in the body of the respective function. In other words, variables of the same name inside different functions are independent of each other and do not affect each other:

``````'use strict';

function foo() {
var x = 1;
x = x + 1;
}

function bar() {
var x = 'A';
x = x + 'B';
}``````

Since JavaScript functions can be nested, internal functions can access variables defined by external functions. But the external functions can not access variables defined by internal functions.

``````'use strict';

function foo() {
var x = 1;
function bar() {
var y = x + 1; // Bar can access foo's variable x!
}
var z = y + 1; // ReferenceError! Foo can't access bar variable y!
}``````

What if the name of variables in internal and external functions are duplicated? To test it out:

``````'use strict';
function foo() {
var x = 1;
function bar() {
var x = 'A';
console.log('x in bar() = ' + x); // 'A'
}
console.log('x in foo() = ' + x); // 1
bar();
}
foo();``````

When looking for variables, JavaScript functions start from their own definitions, from “inside” to “outside”. If the internal function defines a variable with the same name as the external function, the variable of the internal function will “mask” the variable of the external function.

However, I suggest you to use different names for variables to avoid confusion.

### Variable Promotion

JavaScript function has a feature, it will first scan the entire function body statement, “lift” all declared variables to the top of the function:

``````'use strict';

function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob';
}

foo();``````

Although it is a strict mode, the statement `var x = 'Hello, ' + y;` does not report an error because the variable `y` is declared later. But the `console.log` display `Hello, undefined` meaning that the value of the variable `y` is `undefined`. The reason behind this beaviour is that the JavaScript engine automatically raises the declaration of variable `y`, but does not increase the assignment of `y`.

For the above `foo()`function, the code interpreted by the JavaScript engine is equivalent to:

``````function foo() {
var y; // Raise the declaration of the variable y, at this time y is undefined
var x = 'Hello, ' + y;
console.log(x);
y = 'Bob';
}``````

Due to this weird “characteristic” of JavaScript, when we define variables inside a function, we strictly follow the rule of “first declare all variables inside the function”. The most common practice is to use a `var` variable to declare all the variables used inside the function:

``````function foo() {
var x = 1, // x is initialized to 1
y = x + 1, // y is initialized to 2
z, i; // z and i are undefined
// Other statements
for (i=0; i<100; i++) {
...
}
}``````

### Global Scope

Variables that are not defined within any function are existed in the global scope. In fact, JavaScript has a global `window` object by default, and a global scope variable is actually bounded to `window` as an attribute:

``````'use strict';

var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'``````

Therefore, direct access to the global variable `course` or `window.course` has exactly the same result.

As you may have noticed, since there are two ways to define a function. The function defined by the variable style, i.e., `var foo = function () {}`, is actually a global variable. Therefore, the definition of the top-level function is also treated as a global variable and bounded to the `window` object:

``````'use strict';

function foo() {
}

foo(); // call foo() directly
window.foo(); / / Called by window.foo()``````

Actually, the `alert()` function is also a property of the `window` variable:

``````'use strict';

// Save alert to another variable:
// Assign a new function to alert:
window.alert = function () {}
/ / Restore alert:
alert (' can also use alert ()!');``````

This shows that JavaScript actually has only one global scope. Any variable (the function is also treated as a variable), if it is not found in the current function scope, will continue to look up, and finally, if it is not found in the global scope, an `ReferenceError` error is reported.

### Namespace

Global variables are bounded to the `window` object. Different JavaScript files that use the same global variables or define top-level functions with the same name will cause naming conflicts, which is hard to debug.

One way to reduce conflicts is to bind all of your own variables and functions to a global variable. E.g:

``````// The only global variable MYAPP:
var MYAPP = {};

// Other variables:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;

// Other functions:
MYAPP.foo = function () {
Return 'foo';
};``````

Putting all of your own code into a unique namespace `MYAPP` will greatly reduce the possibility of global variable conflicts.

Many well-known JavaScript libraries adopt this technique: jQuery, YUI, underscore, and more.

### Local Scope

We can not use `var` to define variables with local scope, i.e., in a block of statements such as loops:

``````'use strict';

function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // can still reference variable i
}``````

In order to achieve the block-level scope, ES6 introduced a new keyword `let`, which can declare a block-level variable:

``````'use strict';

function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
// SyntaxError:
i += 1;
}``````

### Constant

The keywords `var` and `let` are used to declare variables, where the variable can be changed later. If you want to declare a constant, it is not possible before ES6. We usually use all uppercase variables to indicate “this is a constant, do not modify its value”.

The ES6 standard introduces the new keyword `const` to define constants. `const` and `let` both have block-level scope:

``````'use strict';

const PI = 3.14;
PI = 3; // Some browsers do not report an error, but have no effect!
PI; // 3.14``````

## Destructive Assignment

Starting with ES6, JavaScript introduces destructive assignment that assigns values ​​to a set of variables at the same time.

What is destructive assignment? Let’s take a look at the traditional approach of how to assign the elements of an array to several variables:

``````var array = ['hello', 'JavaScript', 'ES6'];
var x = array[0];
var y = array[1];
var z = array[2];``````

Now, in ES6, you can use destructive assignment to assign values ​​directly to multiple variables:

``````'use strict';

// If the browser supports destructuring assignments, no error will be reported:
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];``````

If the array itself is nested, you can also destructure the assignment by the following form. Noting that the nesting level and position are consistent:

``````let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'``````

Destructive assignments can also ignore certain elements:

``````let [, , z] = ['hello', 'JavaScript', 'ES6']; // Ignore the first two elements, only assign the third element to z
z; // 'ES6'``````

If you need to take a few properties from an object, you can also use destructive assignment to quickly get the specified properties of the object:

``````'use strict';

var person = {
name: 'John',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
var {name, age, passport} = person;``````

When destructuring an object, you can also directly assign values ​​to nested object properties, as long as the corresponding levels are consistent:

``````'use strict';
var person = {
name: 'John',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school',
city: 'Beijing',
zipcode: '100001'
}
};
var {name, address: {city, zip}} = person;
name; // 'John'
city; // 'Beijing'
zip; // Undefined, because the property name is zipcode instead of zip
// Note: address is not a variable, but to get city and zip to get the properties of a nested address object.
address;// Uncaught ReferenceError: address is not defined``````

When destructing an object property with a destructor assignment, if the corresponding property does not exist, the variable will be assigned to the value `undefined`.

If the variable name and attribute name to be used are inconsistent, you can get it with the following syntax:

``````var person = {
name: 'John',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};

// Assign the passport attribute to the variable id:
let {name, passport:id} = person;
name; // 'John'
id; // 'G-12345678'
// Note: The passport is not a variable, but to get the variable id to get the passport attribute:
passport; // Uncaught ReferenceError: passport is not defined``````

Destructuring assignments can also use default values, which avoids the `undefined` problem of non-existing properties:

``````var person = {
name: 'John',
age: 20,
gender: 'male',
passport: 'G-12345678'
};

// If the person object does not have a single attribute, the default assignment is true:
var {name, single=true} = person;
name; // 'John'
single; // true``````

Sometimes, if a variable has already been declared, a syntax error will be reported when the variable is assigned again:

``````// Variable declaration
var x, y;
// Destructive assignment
{x, y} = { name: 'John', x: 100, y: 200};
// Uncaught SyntaxError: Unexpected token =``````

This is because the JavaScript engine treats the `{` opening statement as a block and the `=` symbol is no longer legal. The solution is to use parentheses:

``````var x, y;
({x, y} = { name: 'John', x: 100, y: 200});``````

### Application Scenarios

Destructive assignments can greatly simplify the code in many cases. For example, swapping the values ​​of two variables `x` and `y` can be written like this. No temporary variables are required:

``````var x=1, y=2;
[x, y] = [y, x]``````

Quickly get the domain name and path of the current page:

``var {hostname:domain, pathname:path} = location;``

If a function receives an object as a parameter, you can use destructive assignment to directly bind an object’s properties to variables. For example, the following function can quickly create a `Date` object:

``````function buildDate({year, month, day, hour=0, minute=0, second=0}) {
return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}``````

It is convenient that the incoming object only needs to have three properties `year``month` and `day`:

``````buildDate({ year: 2017, month: 1, day: 1 });
// Sun Jan 01 2017 00:00:00 GMT+0800 (CST)``````

You can also pass in `hour``minute` and `second` properties:

``````buildDate({ year: 2017, month: 1, day: 1, hour: 20, minute: 15 });
// Sun Jan 01 2017 20:15:00 GMT+0800 (CST)``````

Using destructive assignments can reduce the amount of code, but it needs to work in modern browsers that support this feature. Browsers that currently support destructive assignment include Chrome, Firefox, Edge, and more.

## Object Method

Bind a function in an object, called the method of this object.

In JavaScript, the definition of an object is like this:

``````var person = {
name: 'John',
birth: 1990
};``````

However, if we bind a function to `person`, we can do more. For example, write a `age()` method and return `John's` age:

``````var person = {
name: 'John',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};

person.age; // function person.age()
person.age();``````

A function bounded to an object is called a method, and it has no difference from a normal function. But it uses a `this` keyword internally.

So what is the `this` stuff?

Inside a method, the `this` keyword is a special variable that always points to the current object, which is the variable `person`. So, `this.birth` actually means `person.birth`.

Let us write above codes separately:

``````function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}

var person = {
name: 'John',
birth: 1990,
age: getAge
};

person.age(); // => outputs the right result, 29
getAge(); // NaN``````

Why does the function `getAge()` called independently returns `NaN`Please note that we have entered a big pitfall of JavaScript.

If the JavaScript function use the `this` keyword, what is `this` pointing to?

The answer is, depending on the situation!

If called in the form of a method, for example `person.age()`, the keyword `this` points to the called object, that is `person`. This is in line with our expectations.

If the function is called separately, for example `getAge()`, at this point, the function `this` points to the global object, that is `window`.

Even more worse way is that if you write:

``````var fn = person.age; // Get the person's age function first
fn(); // NaN``````

It is not working!

IMPORTANT: To use the keyword `this` correctly, you must use the form `obj.xxx()` to call a method!

Since this is a huge design mistake, it is not that simple to correct. ECMA decided to let the keyword `this` point to `undefined` in strict mode, so you will get an error:

``````'use strict';

var person = {
name: 'John',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};

var fn = person.age;
fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined``````

This decision simply exposes the error in time and does not address the correct object that `this` should be pointed to.

Sometimes, you may rewrite the method in the following way:

``````'use strict';

var person = {
name: 'John',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth;
}
return getAgeFromBirth();
}
};

person.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined``````

The result was wrong again! The reason is that the `this` pointer is only pointed within the function of the method `age`. And in the function `getAgeFromBirth`, `this` points to `undefined`! (In non-strict mode, it re-points to the global object `window`!)

To achieve this, we use a `that` variable to capture `this` first:

``````'use strict';

var person = {
name: 'John',
birth: 1990,
age: function () {
var that = this; // Capture this at the beginning of the method
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // Use that instead of this
}
return getAgeFromBirth();
}
};

person.age(); // 25``````

By using `var that = this;`, you can safely define other functions inside the method instead of stacking all the statements into one method.

### Apply

In a separate function call, depending on whether it is in strict mode, `this` points to `undefined` or `window`. However, we can still control the `this` pointer!

To specify which object the pointer `this` points to, you can use the function’s own `apply` method, which takes two arguments, the first argument is the variable that needs to be bounded, and the second argument is an `Array` that represents the function’s parameters.

Use the `apply` method to make a `getAge()`call:

``````function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}

var person = {
name: 'John',
birth: 1990,
age: getAge
};

person.age(); // success
getAge.apply(person, []); // 25, this points to person, empty parameter``````

Another similar approach is the `call()` method where the differences are:

• The `apply()` method packs the parameters into `Array`;
• The `call()` method passes the parameters in order.

For example, call `Math.max(3, 5, 4)`, use `apply()` and `call()` as follows:

``````Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5``````

For normal function calls, we usually bind `this` to `null`.

### Decorator

Utilizing the `apply()` method, we can also dynamically change the behavior of a function.

All JavaScript objects are dynamic, and even the built-in functions, we can redirect them to new functions.

Now suppose we want to count how many times the function `parseInt()` has been called. You can find all the calls and add them manually adds the code `count += 1`. But this is too awkward. The best solution is to replace the default with our own function `parseInt()`:

``````'use strict';

var count = 0;
var oldParseInt = parseInt; // save the original function

window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // call the original function
};

// Test:
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3``````

## Higher-Order Function

What is a higher order function?

Since a variable can point to a function, and a function’s argument can receive the variable, then one function can receive another function as a parameter. This function is called a higher-order function.

One of the simplest higher order function is:

``````function add(x, y, f) {
return f(x) + f(y);
}``````

When we call `add(-5, 6, Math.abs)`, parameters `x``y` and `f` receive `-5``6` and function `Math.abs`, respectively. According to the function definition, we can derive the calculation process as:

``````x = -5;
y = 6;
f = Math.abs;
f(x) + f(y) ==> Math.abs(-5) + Math.abs(6) ==> 11;
return 11;``````

Verify with code:

``````'use strict';

function add(x, y, f) {
return f(x) + f(y);
}
var x = add(-5, 6, Math.abs); // 11
console.log(x);``````

### Map and Reduce

If you’ve read Google’s famous paper ” MapReduce: Simplified Data Processing on Large Clusters, “, you can probably understand the concept of map/reduce.

### Map

For example, if we have a function f(x)=x2 , to apply this function to an array `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, we can use the `map` method as following:

The `map()` method is defined in `Array`. We call `map()`method on an `Array` with our own function. In last, we get a new `Array`:

``````'use strict';

function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);``````

Note: The argument passed to the `map()` method is the function `pow`.

Why not directly calculate the results with a loop?

``````var f = function (x) {
return x * x;
};

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var result = [];
for (var i=0; i<arr.length; i++) {
result.push(f(arr[i]));
}``````

Indeed, we can accomplish this computation without `map`. But from the loop code above, we can’t understand the code at a glance “put f(x) on every element of the Array and generate a new Array of results.”

So, as a higher-order function, `map()` in fact abstracts the rules of the operation. So we have ability to not only calculate the simple f(x)=x2, but also calculate any complex function. For example, converting all the numbers into strings:

``````var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']``````

Only one line of code is sufficient.

### Reduce

Let’s learn another concept: reduce. The `reduce()` method is also defined in `Array`. It applies a function to the array, where the function must receive two parameters. Concretely, the function is used in the following way:

``[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)``

For example, for summation of an `Array`, you can use `reduce` to achieve:

``````var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25``````

#### Exercise 2

Using the `reduce()` to compute the product of an array:

``````'use strict';

function product(arr) {
}

// Test:
if (product([1, 2, 3, 4]) === 24 && product([0, 1, 2]) === 0 && product([99, 88, 77, 66]) === 44274384 ) {
console.log('Test passed!');
}
else {
console.log('Test failed!');
}``````

To transform `[1, 3, 5, 7, 9]` into an integer 13579, `reduce()` can also do us a favour:

``````var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x * 10 + y;
}); // 13579``````

If we continue to improve this example, we can find a way to turn a string `13579` into an `Array` — `[1, 3, 5, 7, 9]` and then use `reduce()` to write a function that converts a string to a Number.

#### Exercise 3

Implement a `string2int()` function with map and reduce operations. Don’t use the built-in `parseInt()` function.

``````'use strict';

function string2int(s) {
}

// Test:
if (string2int('0') === 0 && string2int('12345') === 12345 && string2int('12300') === 12300) {
if (string2int.toString().indexOf('parseInt') !== -1) {
console.log('Do not use parseInt()!');
} else if (string2int.toString().indexOf('Number') !== -1) {
console.log('Do not use Number()!');
} else {
console.log('test passed!');
}
}
else {
console.log('Test failed!');
}``````

#### Exercise 4

Please change the non-standard English names entered by the users into the first letter uppercase and other lowercase canonical names.

Input: `['adam', 'LISA', 'barT']`, output: `['Adam', 'Lisa', 'Bart']`.

``````'use strict';

function normalize(arr) {
}

// Test
if (normalize(['adam', 'LISA', 'barT']).toString() === ['Adam', 'Lisa', 'Bart'].toString()) {
console.log('test passed!');
}
else {
console.log('Test failed!');
}``````

John hopes to convert strings into integers, with the following simple code:

``````'use strict';

var arr = ['1', '2', '3'];
var r;
r = arr.map(parseInt);
console.log(r);``````

The results turned out to be `1, NaN, NaN`. Please help John find the reason and correct the code.

Hint: Refer to the documentation for Array.prototype.map() .

### Filter

Filter is also a common operation, it is used to filter out some elements of an array, and then return the remaining elements.

Similar to the `map()` method, the `filter()` method receives function as input. The difference is that `filter()` applies the passed function on each element in turn, and then decides retain or discard the element based on the returned value of the passed function.

For example, in an `Array`, delete the even number, just keep the odd number, you can write:

``````var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
return x % 2 !== 0;
});
r; // [1, 5, 9, 15]``````

To delete all empty strings in an array, you can write:

``````var arr = ['A', '', 'B', null, undefined, 'C', '  '];
var r = arr.filter(function (s) {
return s && s.trim();
});
r; // ['A', 'B', 'C']``````

It can be seen that the key point to use this higher-order function is to correctly implement a “filter” function.

### Callback

The received callback function of `filter()` can actually have multiple parameters. Usually we only use the first parameter to represent an element of an array. The callback function can also accept two other parameters, indicating the position of the element and the array itself:

``````var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
console.log(element); // Print 'A', 'B', 'C' in sequence
console.log(index); // print 0, 1, 2 in sequence
console.log(self); // self is the variable arr
return true;
});``````

Utilize `filter`, repeated elements in an array can be easily removed :

``````'use strict';

var r,
arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];

r = arr.filter(function (element, index, self) {
return self.indexOf(element) === index;
});

console.log(r.toString());``````

Removing a duplicated element relies on the fact that the `indexOf` method always returns the position of the first element.

### Exercise 5

Please try to use `filter()` to filter out the prime numbers:

``````'use strict';

function get_primes(arr) {
}

// Test:
var x,
r,
arr = [];

for (x = 1; x < 100; x++) {
Arr.push(x);
}
r = get_primes(arr);
if (r.toString() === [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71 , 73, 79, 83, 89, 97].toString()) {
console.log('test passed!');
} else {
console.log('Test failed: ' + r.toString());
}``````

### Sorting Algorithm

Sorting is often used in programs. Whether using bubble sorting or quick sorting, the core of sorting is to compare the size of two elements. We can compare numbers directly, but what about strings and objects? It is meaningless to directly compare them from mathematical aspects. So the process of comparison must be abstracted by functions.

For two elements `x` and `y`, the comparison function works as follows:

• if `x < y`, return `-1`;
• if `x == y`, return `0`;
• if `x > y`, return `1`.

The `sort()` method is used for sorting, but the results of sorting may surprise you:

``````// looks normal:
['Google', 'Apple', 'Microsoft'].sort(); // ['Apple', 'Google', 'Microsoft'];

// The apple is at the end:
['Google', 'apple', 'Microsoft'].sort(); // ['Google', 'Microsoft", 'apple']

// Unable to understand the result:
[10, 20, 1, 2].sort(); // [1, 10, 2, 20]``````

In the second sort, `apple` ranked last because the strings are sorted according to ASCII, and the lowercase ASCII `a` is after the uppercase letters.

What is the third sort result? Can simple numeric sorting be wrong?

This is because the `sort()`method first converts all elements to String and then sorts them. The result is `'10'` ranked first because the character `'1'` is smaller than `'2'` in the ASCII.

If you don’t know the default rule of the `sort()` method, sort the numbers directly will definitely encounter incomprehensible behaviours!

Fortunately, the `sort()`method is a higher-order function, it can also receive a comparison function to achieve a custom sort.

To sort by number, we can write:

``````'use strict';

var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr); // [1, 2, 10, 20]``````

If you want to sort in reverse order, we can put the big number in front:

``````var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return 1;
}
if (x > y) {
return -1;
}
return 0;
}); // [20, 10, 2, 1]``````

By default, sorting strings is based on their positions in the ASCII table. Now, we propose that sorting should ignore case and sort in alphabetical order. To implement this algorithm, you don’t have to make any changes to the existing code, as long as we can define a comparison algorithm that ignores the case:

``````var arr = ['Google', 'apple', 'Microsoft'];
arr.sort(function (s1, s2) {
x1 = s1.toUpperCase();
x2 = s2.toUpperCase();
if (x1 < x2) {
return -1;
}
if (x1 > x2) {
return 1;
}
return 0;
}); // ['apple', 'Google', 'Microsoft']``````

In fact, first convert the strings to uppercase (or both to lowercase) and then compare them.

As can be seen from the above examples, the abstraction capabilities of higher-order functions are very powerful, and the core code can be kept very concise.

Finally, we should mention that the `sort()` method will modify `Array` directly, and the array returned is still current `Array`:

``````var a1 = ['B', 'A', 'C'];
var a2 = a1.sort();
a1; // ['A', 'B', 'C']
a2; // ['A', 'B', 'C']
a1 === a2; // true, a1 and a2 are the same``````

### Array

For arrays, in addition to `map()``reduce``filter()``sort()`, the `Array` object also provides a lot of very useful high-order functions.

#### Every

The `every()` method can determine if all elements of an array meet the test condition.

For example, given an array containing several strings, determine if all strings meet the specified test condition:

``````'use strict';
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.every(function (s) {
return s.length > 0;
})); // true, Because each element satisfies s.length>0

console.log(arr.every(function (s) {
return s.toLowerCase() === s;
})); // false, Because not every element is all lowercase``````

#### Find

The `find()` method is used to find the first element that meets the test condition, and if found, returns this element; otherwise, returns `undefined`:

``````'use strict';
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.find(function (s) {
return s.toLowerCase() === s;
})); // 'pear'

console.log(arr.find(function (s) {
return s.toUpperCase() === s;
})); // undefined``````

#### findIndex

`findIndex()` is similar to `find()`. It is also used to find the first element that meets the test condition. The difference is that `findIndex()` will return the index of the finded element. If not found, return `-1`:

``````var arr = ['Apple', 'pear', 'orange'];
console.log(arr.findIndex(function (s) {
return s.toLowerCase() === s;
})); // 1

console.log(arr.findIndex(function (s) {
return s.toUpperCase() === s;
})); // -1``````

#### forEach

`forEach()` is similar to `map()`. It also applies the passed function to each element, but does not return a new array. The `forEach()` method often used to traverse arrays, so the passed function does not need to return a value:

``````'use strict';
var arr = ['Apple', 'pear', 'orange'];
arr.forEach(console.log); // Print each element in turn``````

## Closure

### Function as the Return Value

In addition to accepting functions as arguments, higher-order functions can also return functions as result.

Let’s implement summation of an `Array`. Usually, the summation function is defined like this:

``````function sum(arr) {
return arr.reduce(function (x, y) {
return x + y;
});
}

sum([1, 2, 3, 4, 5]); // 15``````

However, what if you don’t need to sum immediately, but in the code that follows, recalculate as needed?

Instead of returning the result of the summation, you can return the summed function!

``````function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}``````

When we call `lazy_sum()`, the result is not the summation result, but the summation function:

``var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()``

When the function `f` is called , the result of the summation is actually calculated:

``f(); // 15``

In this example, we define the function `sum` in the function `lazy_sum`, and the internal function `sum` can refer to the parameters and local variables of the external function `lazy_sum`. When `lazy_sum` returns the function `sum`, the related parameters and variables are saved in the returned function. This program structure is called “Closure”, which has great power.

Please note that when we call `lazy_sum()`, each call returns a new function, even if the same argument is passed in:

``````var f1 = lazy_sum([1, 2, 3, 4, 5]);
var f2 = lazy_sum([1, 2, 3, 4, 5]);
f1 === f2; // false``````

The results of the sum call of `f1()` and `f2()` do not affect each other.

### Closure

Notice that the returned function references a local variable `arr` inside its definition. When a function returns a function, its internal local variables are also referenced by the new function. So the closure is simple to use, and it is not easy to implement.

Another problem to be aware of is that the returned function is not executed immediately. Instead `f()` is executed until it is called. Let’s look at an example:

``````function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];``````

In the above example, each time a loop is created, a new function is created. And then the three functions created are added to one `Array` and returned.

You might think that calling `f1()``f2()` and the `f3()` should return `1``4``9`, respectively. But the actual result is:

``````f1(); // 16
f2(); // 16
f3(); // 16``````

All are `16`! The reason is that the returned function references the variable `i`, but it is not executed immediately. When all three functions are returned, the variables `i` they referenced has became `4`, so the result is `16`.

One thing to keep in mind is that: when returning a closure, the returned function should not reference any loop variables, or variables that will change later.

What if you must quote a loop variable? The method is to create a function that binds the current value of the loop variable with the parameter of the function. Regardless of how the loop variable is subsequently changed, the value bounded to the function argument is unchanged:

``````function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

f1(); // 1
f2(); // 4
f3(); // 9``````

Note that the syntax for “create an anonymous function and execute it immediately” is used here:

``````(function (x) {
return x * x;
})(3); // 9``````

In theory, creating an anonymous function and executing it right away can be written like this:

``function (x) { return x * x } (3);``

However, due to the problem of JavaScript syntax parsing, a SyntaxError error is reported. So the entire function definition needs to be enclosed in parentheses:

``(function (x) { return x * x }) (3);``

Usually, an anonymous function that is executed immediately can be written as this:

``````(function (x) {
return x * x;
})(3);``````

Having said that, isn’t the closure only meant to return a function and then delay execution?

Of course not! Closures have very powerful features. Give a example:

In object-oriented programming languages, such as Java and C++, to encapsulate a private variable inside an object, you can modify a `private` member variable.

In a language like JavaScript, there are only functions and no `class` mechanism. With a closure, you can also encapsulate a private variable. We create a counter with JavaScript:

``````'use strict';

function create_counter(initial) {
var x = initial || 0;
return {
inc: function () {
x += 1;
return x;
}
}
}``````

It works like this:

``````var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13``````

In the returned object, a closure is implemented that carries a local variable `x`. External code can not access to the variable `x`. In other words, a closure is a function that carries a state, and its state can be completely hidden from the outside.

Closures can also turn multi-parameter functions into single-parameter functions. For example, to calculate xy , you can use the `Math.pow(x, y)` function. But considering that x2 and x3 are often calculated, we can use closures to create new functions `pow2` and `pow3`:

``````'use strict';

function make_pow(n) {
return function (x) {
return Math.pow(x, n);
}
}``````

## Arrow Function

A new type of function has been added to the ES6 standard: Arrow Function.

Why it is the name arrow function? Because it is defined by an arrow:

``x => x * x``

The arrow function above is equivalent to:

``````function (x) {
return x * x;
}``````

Before continuing to learn the arrow function, please test if your browser supports the arrow function in ES6:

``````'use strict';
var fn = x => x * x;
console.log ('Your browser supports ES6's Arrow Function!');``````

The arrow function is equivalent to an anonymous function and simplifies function definition.

The arrow function has two formats. The first is similar as above, which contains only one expression, omitting `{ ... }` and `return`. There is another way to include multiple statements, and you can’t omit `{ ... }`and `return`:

``````x => {
if (x > 0) {
return x * x;
}
else {
return - x * x;
}
}``````

If the argument is not one, you need to add the brackets `()`:

``````// Two arguments:
var f1 = (x, y) => x * x + y * y

// No argument:
var f2 = () => 3.14

// Variable parameters:
var f3 = (x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}``````

If you want to return an object, be aware that if it is a single expression, you will get an error if you write in this way:

``````// SyntaxError:
x => { foo: x }``````

Because the brackets `{ ... }` is a grammatical conflict with the function body. It should be changed to:

``````// ok:
x => ({ foo: x })``````

### This Pointer

The arrow function seems to be a shorthand for anonymous functions, but in fact, there is a clear distinction between the arrow function and the anonymous function: the `this` pointer of the arrow function is in the lexical scope, which is determined by the context.

Looking back at the previous example, the following example does not give the expected result due to the error handling of the binding of `this` by the JavaScript function:

``````var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = function () {
return new Date().getFullYear() - this.birth; // This points to window or undefined
};
return fn();
}
};``````

Now, the arrow function completely fixes the `this` pointer. `this` always pointing to the lexical scope, which is the outer caller `obj`:

``````var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // This points to the obj object
return fn();
}
};
obj.getAge(); // 25``````

If you does not use the arrow function, you can write a hack like this as we said before:

``var that = this;``

It is no longer needed.

Since the lexical scope is already bounded to `this` in the arrow function, when the arrow function is used with `call()` or `apply()`, the `this` binding cannot be performed. I.e., the first parameter passed in is ignored:

``````var obj = {
birth: 1990,
getAge: function (year) {
var b = this.birth; // 1990
var fn = (y) => y - this.birth; // this.birth is still 1990
return fn.call({birth:2000}, year);
}
};
obj.getAge(2015); // 25``````

### Exercise 6

Use the arrow function to simplify the function passed in when sorting:

``````'use strict'
var arr = [10, 20, 1, 2];
arr.sort((x, y) => {
???
});
console.log(arr); // [1, 2, 10, 20]``````

## Generator

The generator is a new data type introduced by the ES6 standard. A generator looks like a function, but can return multiple times.

Let’s review the concept of functions first. A function is a complete piece of code. Calling a function is passing in the arguments and returning the result:

``````function foo(x) {
return x + x;
}

var r = foo(1); // Invoke the foo function``````

During the execution of the function, if the `return` statement is not encountered, the execution logic can not return to the called code. (If there is no `return` statement, the function implicit executes `return undefined;` in the end of the function.)

The generator is very similar to the function, defined as follows:

``````function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}``````

The generator differs from the function in that the generator is defined with  `function*` (note the extra `*` symbol). And, in addition to the `return` statement, it can `yield` multiple results.

Most of the beginners immediately get confused. The generator is a “function” that can return multiple times? Is it useful?

Let’s see this example.

The famous Fibonacci sequence, which consists `0``1` at the beginning:

``0 1 1 2 3 5 8 13 21 34 ...``

To write a function that produces a Fibonacci sequence, you can write:

``````function fib(max) {
var t,
a = 0,
b = 1,
arr = [0, 1];
while (arr.length < max) {
[a, b] = [b, a + b];
arr.push(b);
}
return arr;
}

// Test:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]``````

The function can only be returned once, so one must returns an `Array`. However, if you switch to a generator, you can return a number at a time and keep returning multiple times.

Rewrite above codes with a generator as follows:

``````function* fib(max) {
var t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n++;
}
return;
}``````

Try it directly:

``fib(5); // fib {[[GeneratorStatus]]: "suspended" [[GeneratorReceiver]]: Window}``

Calling a generator directly is not the same as calling a function. The invocation of  `fib(5)` just creates a generator object and has not yet been executed.

There are two ways to call the generator object.

One is to repeatedly call the `next()` method of the generator object:

``````var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}``````

The `next()` method executes the generator’s code, then returns an object `{value: x, done: true/false}` each time it encounters the `yield` keyword, and then “pauses”. The `value` is the value returned by `yield`. The `done` indicates whether the generator has finished. If `done` is `true`, then `value` is the value return by the `return` keyword.

NOTICE: When the returned `done` is `true`, it means that the generator object has finished its job. Do not continue to call `next()`.

The second method is to use `for ... of` to iterate the generator object directly with a loop, which does not require our own judgment of `done`:

``````'use strict'

function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
for (var x of fib(10)) {
console.log(x); // => 0, 1, 1, 2, 3, ...
}``````

What is the advantage of generator compared to ordinary functions?

Because the generator can return multiple times during execution, it looks like a function that remembers the state of execution. With this, writing a generator can do what you need to do with object-oriented programming. For example, to save a state with an object, you have to write:

``````var fib = {
a: 0,
b: 1,
n: 0,
max: 5,
next: function () {
var r = this.a,
t = this.a + this.b;
this.a = this.b;
this.b = t;
if (this.n < this.max) {
this.n++;
return r;
} else {
return undefined;
}
}
};``````

It is quite cumbersome to save the state with the properties of the object.

Another great benefit of generator is the ability to turn asynchronous callback code into “synchronous” code. This benefit will not be realized until after learning AJAX.

Without generator, you need to write code like this when using AJAX:

``````ajax('http://url-1', data1, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-2', data2, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-3', data3, function (err, result) {
if (err) {
return handle(err);
}
return success(result);
});
});
});``````

The more callbacks, the more ugly the code.

With the beautiful era of generators, you can write this when using AJAX:

``````try {
r1 = yield ajax('http://url-1', data1);
r2 = yield ajax('http://url-2', data2);
r3 = yield ajax('http://url-3', data3);
success(r3);
}
catch (err) {
handle(err);
}``````

It seems to be synchronous code, the actual execution is asynchronous.

### Exercise 7

To generate an auto-incrementing ID, you can write a `next_id()` function:

``````var current_id = 0;

function next_id() {
current_id++;
return current_id;
}``````

Since the function cannot save state, a global variable `current_id` is needed to hold the number.

No closure, try generator rewrite:

``````'use strict';
function* next_id() {
}

// Test:
var x,
pass = true,
g = next_id();
for (x = 1; x < 100; x ++) {
if (g.next().value !== x) {
pass = false;
console.log('Test failed!');
break;
}
}
if (pass) {
console.log('test passed!');
}``````

## Closing Words

Thanks for reading this long article!

Congratulations! You now know how to write a function, a closure, a arrow function. You are an expert of JavaScript functions.