Computer programs usually contain logical units composed of multiple statements. In JavaScript, these units are called functions. A function is actually a SECTION of JS code block that can be called repeatedly. JavaScript functions are parameterized, and the function definition includes arguments and parameters. Parameters are equivalent to the variables defined in the function, and the arguments are passed in when the function call is run.

I. Function definition

Functions are defined using the keyword function. There are several ways to define functions:

1. Function declaration

Use the function keyword, followed by a list of arguments and the function body.

  • Funcname is the name of the function to be declared. The function name is a required part of the function declaration statement. A function name is a pointer to a function. They have the same behavior as any other variable that contains a pointer to an object. A function can have multiple names. All ECMAScript6 Function objects expose the name read-only property, which contains information about the Function. In most cases, this property holds a Function identifier, or a stringed variable name, which is displayed as an empty string even if the Function has no name. If it is created using the Function constructor, It would be marked ‘Amonymous’. A function name without parentheses can be used to access the function pointer, but the function is not executed.

  • The parentheses can contain zero or more identifiers separated by commas. These identifiers are function parameter names, which are like local variables in the function body.

  • Curly braces wrap one or more javascript statements. These statements make up the body of the function and are executed once the function is called.

  • Duplicate declarations of variables are useless, but duplicate declarations of functions override previous declarations (either variable or function)

  / / syntax:
function funcname(a,b) {
    return a + b;
} 
// Note that the function does not end with a semicolon
Copy the code

2. Function expressions

Functions are defined as expressions with optional function names. Anonymous functions are functions that have no identifier following the function keyword. In general, functions defined as expressions do not need names, which makes the code more concise. This is especially useful for defining functions that are used only once, with a semicolon at the end.

let funcname(a,b){
    return a + b;
}
Copy the code

Function constructor

The Function constructor takes any data argument, but the last argument is always treated as the Function body, and the previous argument enumerates the parameters of the new Function. The Function constructor cannot specify a Function name; it creates an anonymous Function. It is not recommended because it causes code to be parsed twice, first as regular code and second to interpret the string passed to the constructor.

var functionName = new function(){
    statement;
}
Copy the code

4. Arrow function

ECMAScript6 adds the fat arrow (=>) syntax to define function expressions, and arrow functions can be used anywhere function expressions are available. The arrow function syntax is concise, if only one argument, can not use parentheses. Use parentheses only when there are no arguments or multiple arguments, as shown below.

// No arguments
let arrowFuncname = () = > {
    statements;
}
// There is only one argument
let arrowFuncname = a= > {
    statements;
} 
// equivalent to the following
let arrowFuncname = (a) = > {
    statements;
}
// Multiple parameters
let arrowFuncname = (a , b) = >{
    statements;
}
// When the arrow function is followed by only one line of code, the curly braces can be omitted
let arrowFuncname = a= > 3 * a;
// If the arrow function is followed by only one line of code and there is a return inside the code, braces are still required
let arrowFuncname = a= > {return 3 * a}
Copy the code

Note that the arrow function can only be defined before it is used. There is no this object in the arrow function, so this refers to wherever the function is defined (the arrow function inherits this from the outer function call). Without this, it is not a constructor and cannot be called using new. There is no arguments object in arrow functions, and arrow functions have no prototype property.

2. Function parameters

1. Understand the parameters

Passing data from outside a function into a function that can receive and use it is called parameters. Because the parameters of an ECMAScript function are internally represented as an array. The function receives an array when it is called, but it doesn’t care what the array contains, what type it is, and can even pass no arguments if necessary, unlike most other language arguments. In fact, when defining a non-arrow function using the function keyword, you can access the Arguments object inside the function and get the value of each argument passed in from it.

Arguments are enclosed in parentheses, separated by commas (0 or more), and divided into parameters and arguments. Parameters are formal parameters that are actually determined by the arguments inside the parentheses of the function declaration. In non-strict mode, a parameter of the same name can appear in a function and only the last parameter of that name can be accessed. However, an error is reported in strict mode.

Arguments are the actual arguments in the parentheses of the function call. The arguments must correspond to the parameters 1 and 1. When the function is called, enough arguments must be passed. It is common to use logic or operators to set reasonable defaults for omitted parameters.

Arguments object which represents the collection of all arguments is an array of classes. Each data in this collection has its own subscript, and there is also a Length attribute in the collection, which represents the number of arguments. The length of the Arugments object is determined by the number of arguments passed in, rather than the number of parameters given when defining the function. It can only be used inside a function, and an error will be reported if it is used outside the function. Arguments objects are always in sync with the values of the corresponding named arguments. Arguments objects and named arguments do not access the same memory space; they are separate, but have equal values.

function fn(num1,num2){
    arguments[1] = 10;
    console.log(arguments[0] + num2); / / 30
}
fn(20.40);
Copy the code

If the function is defined using the arrow function syntax, then the arguments passed to the function cannot be accessed using the arguments keyword, but only through the defined parameters. You can provide its arguments to the arrow function via an external wrapper function.

let arrowFn = () = > {
    console.log(arguments[0]);
}
arrowFn(5); // Uncaught ReferenceError: arguments is not defined

function wrapperFn(){
    let arrowFn = () = > {
        console.log(arguments[0]); / / 10
    }
    arrowFn();
}
wrapperFn(10);
Copy the code

Arguments to all functions in ECMAScript are passed by value. In other words, copying a value from outside a function to a parameter inside the function is the same as copying a value from one variable to another. It cannot pass arguments by reference; if an object is passed as a parameter, then the value passed is a reference to that object.

// When passing a primitive type, the passed value is assigned to a local variable
function add(num){
    num += 10;
    return num;
}
let count = 10;
let re = add(count);
console.log(re,count);  / / 20 10

// When passing a reference type to a parameter:
function fn(obj){
    obj.age = 20;
}
let person = new Object(a); fn(person);console.log(person.age);  / / 20
// Create a person object outside the function, call it with fn, and pass a copy of the person value to obj, so that obj's reference points to the same object as person

Copy the code

2. Default parameter values

Before and after ECMAScript5.1 we could check if a parameter was undefined to implement the default parameter. If so, we could assign a value to it instead of passing it.

function fn(age){
    age = (typeofage ! = ='undefined')? age :18;
    return `${age}`;
}
console.log(fn()); / / 18
Copy the code

The default parameters of ECMAScript6 can be displayed as follows:

function fn(age = 18){
    return `${age}`;
}
console.log(fn()); / / 18
Copy the code

The default parameters of a function are evaluated only when the function is called, not when the function is defined, and the default value of a function is called only when the function is called but no corresponding arguments are passed in. The arrow function can also use the default arguments as above, but when there is only one argument, use parentheses and do not omit them.

let fn = (age = 18) = > `${age}`;
console.log(fn()); / / 18
Copy the code

Objects can be defined when evaluating default arguments, and functions can be called dynamically, so function arguments must be evaluated in some scope. When we define default values for multiple parameters, it is actually the same as declaring variables sequentially using the let keyword. Parameters are initiated in order, so parameters with default values defined later can refer to previously defined parameters, but previously defined parameters cannot refer to later ones. Parameter initialization sequence follows the temporary dead zone rule. Parameters also exist in their own scope; they cannot refer to the scope of the function body.

    function fn(age = 18) {
        return `${age}`
    }
    console.log(fn()); / / 18

    function fn2() {
        let age = 18;
        return `${age}`
    }
    console.log(fn2()); / / 18

    function fn3(age1 = 18, secondAge = age1) {
        return 'age1:' + `${age1}` + 'age2' + `${secondAge}`;
    }
    console.log(fn3()); //age1:18age218

    // function fn4(age1 = secondAge, secondAge = 18) {
    // return 'age1:' + `${age1}` + 'age2' + `${secondAge}`;
    // }
    // console.log(fn4()); //Uncaught ReferenceError: Cannot access 'secondAge' before initialization

    function fn5(name = defaultName) {
        let defaultName = 'lily';
        return `${defaultName} ${name}`;
    }
    console.log(fn5()); //Uncaught ReferenceError: defaultName is not defined,
Copy the code

3. Inside the function

1, the arguments

Arguments is an array object that contains all arguments passed to a function. This object is only available when a function is defined with the function keyword. Arrow functions do not have arguments. Arguments objects have a callee property that is a pointer to the function of the Arguments object.

2, this

The orientation of this in functions is always an important question. This is the execution body which is fundamentally different from the execution context. Function this can be divided into the following cases:

2.1 Event Binding

Bind a method to an element’s event behavior. When the event behavior is triggered, the method executes, and this in the method is the current element itself. However, ie6-8 implements event binding based on the attachEvent method, event firing, and this in the method refers to the window.

<input type="button" value="click me" id='click'>
    <script>
        document.getElementById('click').onclick = function () {
            // The event is emitted, the method is executed, and this in the method is the element itself
            console.log(this.value); 
        }
    </script>
Copy the code

2.2 Common Method Execution

Normal method execution just depends on whether the function is executed with a “dot” in front of the method name. If there is a “dot”, this is whoever is in front of the dot. If there is no dot, this refers to window in non-strict mode, and undefined in strict mode.

// Ordinary method execution (including self-executing functions, ordinary function execution, object member access)
// The function is executed by itself. If there is a bit of this in the function, it doesn't matter where the function is defined and executed
(function () {
    console.log(this); //=>window}) ();let obj = {
    fn: (function () {
        console.log(this); //=>window
        return function () {}
    })() // Assign the return value of the self-executing function to obj.fn
};
Copy the code

2.3 Constructors

This in the constructor body is an instance of the current class.

function Func() {
   this.name = "F";
   //=> This in the constructor body is an instance of the current class in constructor execution mode, and this.XXX=XXX sets the private property for the current instance
   console.log(this);
}
Func.prototype.getNum = function getNum() {
   // This is not always an instance of a method on a prototype
   console.log(this);
};
let f = new Func;
f.getNum();
f.__proto__.getNum();
Func.prototype.getNum();
Copy the code

2.4 ES6 arrow functions

The arrow function does not have its own this; its this is inherited from the context.

let obj = {
    func: function () {
         console.log(this);
    },
    sum: () = > {
     console.log(this); }}; obj.func();/ / this: obj
obj.sum();     // This is the context of this:window
obj.sum.call(obj); // The arrow function does not have this, even if it is forced to change this:window
Copy the code

2.5 the call/apply/bind

/ / call/bind/apply; / / call/bind/ /apply; / / call/bind/ /

  • call: function.call(thisArg, arg1, arg2, …)

Function: __proto__ (); function: __proto__ ();

When the call method is executed, function is executed, this in the function points to thisArg, and arg1,arg2… Isoparameter values are passed to the function separately.

  • apply:func.apply(thisArg, [argsArray]);

It is the same as call, except that the parameters passed to the function need to be passed in an array.

  • bind:function.bind(thisArg[, arg1[, arg2[, …]]])

The syntax is similar to call, but the function is different from call/apply. Call /apply both execute the current function immediately and change the “this” in the function, whereas bind is a preprocessing idea, based on the fact that bind just prestores the “this” in the function to “thisArg” and the arg1 argument values, but the function is not executed.

As you can see in the code below, the only difference between Call and Apply is that the parameters are passed in an array by apply.

The first argument to the call method, if not passed or passed as null/undefined, refers to window in non-strict mode, and to the value passed in strict mode.

let obj = {
    name: 'obj'
};
function func(x, y) {
    console.log(this, x, y);
}

func.call(obj, 11.12);//obj 11 12
func.apply(obj, [11.12]); //obj 11 12
func.call();//window undefined undefined
func.call(null);//window undefined undefined
func.call(undefined);//window undefined undefined
func.call(11);//Number undefined unefined
Copy the code

3, the new target

A function in ECMAScript has two identities: it can be instantiated as a new object as a constructor, or it can be called as a normal function. ECMAScript adds a new attribute that checks whether a function is called with the new keyword. If the function is called normally, the value of new.target is undefined, and if the function is called with the new keyword, new.target will refer to the invoked constructor.

<input type="button" value="click me" id='click'>
<script>
    function Fn() {
        if (!new.target) {
            throw 'fn must be instantiated using "new"';
        }
        console.log('fn instantiated using "new"');
    }
    new Fn(); //fn instantiated using "new"
    Fn(); //Uncaught fn must be instantiated using "new"
</script>
Copy the code

4. Function calls

It is executed only when the function is called. In general, there are four types of function calls:

1. Function call pattern

Call method: function name (parameter). For normal function calls, the return value of the function is the value of the calling expression.

When calling a function using function call mode, in non-strict mode, this refers to window, and in strict mode, this refers to undefined.

let add = function (a, b) {
    'use strict';
    console.log(this); //undefined
    // alert(this); //Window
    return a + b;
}
let sum = add(3.4);
console.log(sum);/ / 7;
Copy the code

2. Method invocation pattern

Call method: object. Method (parameter). When a function is stored as a property of an object, we call it a method. This is bound to the object when the method is called. If the calling expression contains an action to extract a property, it is called as a method. In short, a method call is a method call on an object, so a method object must have a host object.

A method can use this to access its own object, so it can value or modify the object. The binding of this to the object occurs at call time. Methods that use this to get the context of the object they belong to are called public methods.

Any function called as a method passes in an implicit argument to an object that is the parent of the method call.

Unlike variables, the this keyword is not scoped. Nested functions do not inherit this from the calling function. If a nested function is called as a method, its this refers to the object on which it was called; if a nested function is called as a function, its this refers to the global object (which is undefined in strict mode).

So to sum up:

  • The method invocation pattern is not independent and requires a host, whereas the function invocation pattern is independent
  • Method call mode method: obj.fn(), function call mode method: fn();
  • In the method call pattern, this refers to the host, while in the function call pattern, this refers to the global object
let myObject = {
    value: 0.fn1: function () {
        console.log(this);//myObject
        return this;
    },
    fn2: function () {
        console.log(this);//myObject
        this.value = 1;
    },
    fn3: function () {
        function n() {
            console.log(this);//window
            return this;
        }
        returnn(); }}console.log(myObject.fn1().value);/ / 0
myObject.fn2();
console.log(myObject.fn1().value);/ / 1
console.log(myObject.fn3());//window
Copy the code

Constructor invocation pattern

If a function or method call is preceded by the keyword new, it constitutes a constructor call. New is an operator used to request the creation of an object, which is passed to the constructor’s this and initialized with the constructor.

Var p = new Person();

If the constructor call contains a list of arguments in parentheses, the argument expressions are evaluated and passed into the function. The syntax of the JS constructor call allows omitting the argument list and parentheses if the constructor has no parameters. Any constructor call with no parameters can omit the parentheses.

Constructors usually do not use the return keyword; they usually initialize new objects and display a return when the body of the constructor is finished executing. In this case, the constructor call expression evaluates to the value of the new object.

let o = {
    m: function () {
        return this; }}let obj = new o.m();
console.log(obj, obj === o);//{} false
console.log(obj.constructor === o.m);//true
Copy the code

4. Indirect invocation pattern

Function objects can also contain methods. The call(),apply(), and bind() methods can be used to call functions indirectly.

let obj = {};// Define an empty object
function fn(x, y) {
    console.log(this);//obj
    console.log(x, y);/ / 1, 2
}
fn.apply(obj, [1.2]);
fn.call(obj, 1.2);// Call directly
let b = fn.bind(obj);//bind() cannot call a function
b();// only at this point
Copy the code

Return value

The return statement in a function is used to return the value of the call, preventing the function from continuing. It often appears as the last line of a function. When a return is executed, the function immediately returns and does not execute the rest of the statement. If there is no return, the function returns undefined. It can only appear inside a function, otherwise an error will be reported. A function can have multiple return statements.

function fn(a, b) {
    return a + b;
    alert(1); // will not be executed because it is placed after return
}
console.log(fn(2.3));  / / 5
function fn1(a, b) {
    let c = a + b;
}
console.log(fn1(4.5));//undefined has no return
Copy the code