JavaScript function

This article lists the almost aspect of JavaScript Array. The content is mainly from [MDN]((https://developer.mozilla.org), but shorter and convenient for it is in one article.

Define a function

Function definition/declaration

A function definition consist:

  • function keyword.
  • A parameter list enclosed in ().
  • JavaScript statements enclosed in {}.

Example:

function square(number) {
  return number * number;
}

Parameters are passed by value or by reference

Primitive parameters are passed by value which means changes to parameters inside the function are not reflected outside the function.

For non-primitive parameters like objects, the changes to the parameters inside the function are visible outside it.

Function expression

A function in JavaScript can also be a form of a a function expression.

It can be anonymous or has a name.

Examples:

// Anonymous function expression
const square = function(number) { return number * number };
var x = square(4); // x gets the value 16

const factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1) };
console.log(factorial(3));

They are convenient when being as an argument passed to another function:

// map(f, a) is a function that accepts a function as the first parameter.
function map(f, a) {
    let result = [];
    let i;
    for (i = 0; i != a.length; i++)
        result[i] = f(a[i]);

    return result;
}

// Call map(f, a) to pass it a function the first parameter.
const f = function(x) {
   return x * x * x;
}
let numbers = [0, 1, 2, 5, 10];
let cube = map(f,numbers);
console.log(cube); // [0, 1, 8, 125, 1000]

Define a function based on a condition

In JavaScript, a function can be defined based on a condition:

let myFunc;
if (num === 0) {
    myFunc = function(theObject) {
        theObject.make = 'Toyota';
    }
}

Function constructor

Every JavaScript function is actually a Function object. The Function constructor Function() creates a new Function object dynamically.

let helloFunc =  new Function('console.log("Hello")');

Note

Calling the constructor directly can create functions dynamically but suffers from security and similar (but far less significant) performance issues to Global_Objects/eval. However, unlike eval, the Function constructor creates functions that execute in the global scope only.

Difference between Function constructor and function declaration

Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was created. This is different from using Global_Objects/eval with code for a function expression.

var x = 10;

function createFunction1() {
    var x = 20;
    return new Function('return x;'); // this |x| refers global |x|
}

function createFunction2() {
    var x = 20;
    function f() {
        return x; // this |x| refers local |x| above
    }
    return f;
}

var f1 = createFunction1();
console.log(f1());          // 10
var f2 = createFunction2();
console.log(f2());          // 20

While this code works in web browsers, f1() will produce a ReferenceError in Node.js, as x will not be found. This is because the top-level scope in Node is not the global scope, and x will be local to the module.

Function scope

A function can access all variables and functions defined inside the scope in which it is defined.

Nested functions

Functions can be nested. The nested (inner) function is private to its containing (outer) function.

Example1

function addSquares(a, b) {
    function square(x) {
        return x * x;
    }
    return square(a) + square(b);
}
a = addSquares(2, 3); // returns 13
b = addSquares(3, 4); // returns 25
c = addSquares(4, 5); // returns 41

Example2

function A(x) {
    function B(y) {
        function C(z) {
            console.log(x + y + z);
        }
        C(3);
    }
    B(2);
}
A(1); // logs 6 (1 + 2 + 3)

Closure

Since the inner function has access to the scope of the outer function, the variables and functions defined in the outer function will live longer than the duration of the outer function execution, if the inner function manages to survive beyond the life of the outer function. A closure is created when the inner function is somehow made available to any scope outside the outer function.

A complex example

var createPet = function (name) {
    var sex;

    return {
        setName: function (newName) {
            name = newName;
        },

        getName: function () {
            return name;
        },

        getSex: function () {
            return sex;
        },

        setSex: function (newSex) {
            if (typeof newSex === 'string' && (newSex.toLowerCase() === 'male' ||
                newSex.toLowerCase() === 'female')) {
                sex = newSex;
            }
        }
    }
}

var pet = createPet('Vivie');
pet.getName();                  // Vivie

pet.setName('Oliver');
pet.setSex('male');
pet.getSex();                   // male
pet.getName();                  // Oliver

An object (Here it is the object returned by createPet()) containing methods for manipulating the inner variables of the outer function can be returned.

Another example: The outside function does not even have to be assigned to a variable, or have a name. It is called when defined and the returned inner function is assigned to getCode. getCode() means calling the inner function which returns apiCode.

var getCode = (function() {
    var apiCode = '0]Eal(eh&2';// A code we do not want outsiders to be able to modify...

    return function() {
        return apiCode;
    };
})();

getCode();    // Returns the apiCode

Function parameters

Default parameters

// Default parameters

function multiply(a, b = 1) {
  return a * b;
}

multiply(5); // 5

Indefinite number of arguments

// Indefinite number of arguments

function multiply(multiplier, ...theArgs) {
  return theArgs.map(x => multiplier * x);
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]

The arguments object

The arguments of a function are maintained in an array-like object. Within a function, you can address the arguments passed to it as follows:

function myConcat(separator) {
    let result = ''; // initialize list

    // Iterate through arguments
    for (let s of arguments) {
      result += s + separator;
    }
    return result;
}

myConcat(', ', 'red', 'orange', 'blue'); // ", , red, orange, blue, "

Arrow function

An arrow function expression (previously, and now incorrectly known as fat arrow function) has a shorter syntax compared to function expressions and does not have its own this, arguments, super, or new.target. Arrow functions are always anonymous.

Let’s see an example difference using a function and using an arrow function as a parameter (callback).

Use a function:

Until arrow functions, every new function defined its own this value (a new object in the case of a constructor, undefined in strict mode function calls, the base object if the function is called as an “object method”, etc.). This proved to be less than ideal with an object-oriented style of programming.

function Person() {
    this.age = 0;

    var self = this; // Some choose `that` instead of `self`.
                     // Choose one and be consistent.
    setInterval(function growUp() {
        // The callback refers to the `self` variable of which
        // the value is the expected object.
        self.age++;
    }, 1000);
}

Inside growUp(), it can not refer to this (the Person Function object) directly for it has its own this.

Tips

Alternatively, a bound function (Use bind() to create a new function that, when called, has its this keyword set to the provided value) could be created so that the proper this value would be passed to the growUp() function.

function Person() {
       this.age = 0;

       let growUp = function () {
           this.age++;
       };
       let boundedGrowup = growUp.bind(this);
       setInterval(boundedGrowup, 1000);
}

Use an arrow function:

function Person() {
    this.age = 0;

    setInterval(() => {
        this.age++; // |this| properly refers to the person object
    }, 1000);
}

var p = new Person();

An arrow function does not have its own this, the this value of the enclosing execution context is used.

Pass extra parameter to a callback

onload accepts no parameters, to pass extra parameters to it:

  avatar.onload = (function (context, avatar) {
      return function () {
          context.drawImage(avatar, 20, 100, 64, 64);
      }
  })(context, avatar);

Resource