Every Function is an instance of type Function. A Function is an object. A Function name is a pointer to an object.

// A semicolon is required
let sum = (num1, num2) = > {
  return num1 + num2;
};
// Semicolons are not needed
function sum (num1, num2) {
  return num1 + num2;
}
Copy the code

Arrow function

Arrow functions, while concise, are not suitable for some scenarios. Arrow functions cannot use arguments, super, and new.target, and arrow functions do not contain the prototype attribute.

The function name

A function name is a pointer to a function. A function can have multiple names

function sum(num1, num2) {
  return num1 + num2;
}
/ / 20
console.log(sum(10.10));
/ / 20
let anotherSum = sum;
console.log(anotherSum(10.10)); / / 20
Copy the code

The name attribute

function foo() {}
let bar = function() {};
let baz = () = > {};

// foo
console.log(foo.name);
// bar
console.log(bar.name);
// baz 
console.log(baz.name);
//(empty string)
console.log((() = > {}).name);
// anonymous
console.log((new Function()).name);

function sum(num1, num2) {
  return num1 + num2;
}
let anotherSum = sum;
// sum
console.log(anotherSum.name);
Copy the code

Using bind adds a prefix


function foo() {}
// bound foo
console.log(foo.bind(null).name);


let dog = {
    years: 1.get age() {
        return this.years;
    },
    set age(newAge) {
        this.years = newAge; }}let propertyDescriptor = Object.getOwnPropertyDescriptor(dog, 'age'); 
console.log(propertyDescriptor.get.name); // get age 
console.log(propertyDescriptor.set.name); // set age
Copy the code

parameter

Js defines the number of parameters, and the use of different parameters passed in the case, is not an error. Because the argument in JS is essentially an array. In the body of a non-arrow function, you can access each argument of the function using arguments, which is an array object of classes. Arguments to ECMAScript functions are written for convenience only, not necessarily


function sayHi() {
    console.log("Hello " + arguments[0] + "," + arguments[1]);
}
Copy the code

In non-strict mode, arguments and arguments are bound to each other (but they don’t refer to the same block of memory, just synchronize), and changing arguments[0] changes the value of the first argument as well.

However, if no actual arguments are passed, change arguments[0] to sync.

Arguments to the arrow function

The arguments keyword is not available in arrow functions

There is no overload

There is no overloading of functions in js; the last one overwrites the previous one.

The default parameters


function makeKing(name = 'Henry') {
  return `King ${name} VIII`;
}
Copy the code

If the argument is undefined, the default argument is used. Arguments does not synchronize with default arguments. If arguments are used as default arguments, arguments will not get the value of the default argument.

The default argument may not be a fixed value, or it may be the return value of a function

let ordinality = 0;
function getNumerals() {
  return ordinality++;
}
// Use the return value of getNumerals as the default argument
function makeKing(name = 'Henry', numerals = getNumerals()) {
  return `King ${name} ${numerals}`;
}
// The default argument for numerals. Incrementing after each call
console.log(makeKing());
Copy the code

Default parameter scope with temporary dead zone

The default arguments to functions, like let and const, have a temporary dead band. The default value of the latter parameter, which can be used as the default value.


function makeKing(name = 'Henry', numerals = name) {
  return `King ${name} ${numerals}`;
}
Copy the code

However, the former parameter cannot be used as the default value. The specific reasons are as follows


function makeKing(name = 'Henry', numerals = 'VIII') {
  return `King ${name} ${numerals}`;
}

// Is equivalent to
function makeKing(name, numerals) {
  let name = name || 'Henry';
  let numerals = numerals || 'VIII';
  return `King ${name} ${numerals}`;
}
Copy the code

Extension and collection of parameters

If the function wants to take every item in the array as an argument. You can’t accept array arguments at the same time

If you do not use the extension operator, you can use Apply

let values = [1.2.3.4];
getSum.apply(null, values)
Copy the code

Or use extension operators

let values = [1.2.3.4]; getSum(... values);Copy the code

Arguments can collect arguments passed in using the extension operator


let values = [1.2.3.4]
function countArguments() {
  console.log(arguments.length);
}
/ / 5
countArguments(-1. values);Copy the code

Extended operators that can be used on named and default parameters

function getProduct(a, b, c = 1) {
  return a * b * c;
}
/ / 2
console.log(getProduct(... [1.2]));
/ / 6
console.log(getProduct(... [1.2.3]))
Copy the code

Collect parameters

The extension operator can also be used on function parameters, which become an array

function getSum(. values) {
  / / [1, 2, 3]
  console.log(values)
}

console.log(getSum(1.2.3))
Copy the code

If the extension operator is used as an argument, it cannot have any arguments afterwards because its length is variable

/ / error
function getProduct(. values, lastValue) {}
/ / right
function getProduct(lastValue, ... values) {}
Copy the code

Declarations and expressions of functions

Function declarations and function expressions are treated differently by the JS engine.

Before any code is executed, js reads the function declaration and generates the function definition in the execution context. A function expression, on the other hand, must wait until the code executes to its line before generating the function definition in the execution context.

// Can be executed normally
console.log(sum(10.10));
function sum(num1, num2) {
  return num1 + num2;
}
Copy the code

Function declarations are read and added to the execution context before any code is executed. This process is called function declaration promotion.

The JS engine performs a scan before executing the code, elevating the found function declaration to the top of the source tree.

// You can see it like this
console.log(sum(10.10));
function sum(num1, num2) {
  return num1 + num2;
}

// Inside JS, because function declarations are promoted, it actually looks like this
function sum(num1, num2) {
  return num1 + num2;
}
console.log(sum(10.10));
Copy the code

Function expressions do not have function declaration promotion

// An error will be reported. If the code does not execute to the defined line, then there is no function definition in the execution context
console.log(sum(10.10));
var sum = function(num1, num2) {
  return num1 + num2;
};
Copy the code

Function as value

Functions can be arguments, they can be return values. Functions that return values can be external to the contents of the function.

Function of the internal

this

In standard functions, this is the context object that treats the function as a method call. The this object of a standard function is determined only when it is called, and this is undefined when it is not called.

window.color = 'red';
let o = {
  color: 'blue'
};
function sayColor() {
  // this refers to window
  console.log(this.color);
}
sayColor(); // 'red'
o.sayColor = sayColor;
// This refers to the o object
o.sayColor(); // 'blue'
Copy the code

In the arrow function, this refers to the context in which the arrow function is defined (if so)

window.color = 'red';
let o = {
  color: 'blue'
};
// This is always the window object
let sayColor = () = > console.log(this.color);
sayColor(); // 'red'
o.sayColor = sayColor;
o.sayColor(); // 'red'
Copy the code

In the arrow function, this refers to the context in which the arrow function is defined. If the context of the arrow function is inside the normal function, the context is not determined until the normal function call.

const bar = {
  fn () {
    const fn = () = > {
      console.log(this)
    }
    fn()
  }
}
/ / this is the bar
bar.fn()
const fn = bar.fn
/ / this is a window
fn()
Copy the code
const bar = {
  fn: () = > {
    // This is already defined in the definition
    console.log(this)}}/ / this is a window
// This is defined when the fn function is defined
bar.fn()
Copy the code

caller

The function that calls the current function, arguments.callee.caller, also points to the same reference (but currently tests return undefined).


function a() {
  b();
}
function b() {
  // a
  console.log(b.caller);
}
a();
Copy the code

arguments

Class array object. Contains all the arguments actually passed in when the function is called. Arguments. callee pointer to the function in question.

function factorial(num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * factorial(num - 1); }}// Equivalent to avoid strong coupling with the factorial name
function factorial(num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * arguments.callee(num - 1); }}Copy the code

new.target

Target returns undefined. If new is called, the constructor is returned

Properties and methods of a function

  • Length, length returns the number of function parameters
  • Prototype is where all instance methods of a reference type are stored, all instances shared
  • Apply (), which specifies this. The first argument is the value of this that needs to be set. The second argument can be an array of arguments or arguments object
  • Call (), which specifies this, the first argument, and apply, but the arguments to the function need to be passed in sequence, not arrays
  • Bind (), which is used to specify this, also needs to be passed in. Unlike apply or call, which calls the function immediately, bind returns the wrapped function
  • ValueOf () returns the function itself

Partial function

Bind, another common way to do this is to have a function that has some default arguments

function addArguments(arg1, arg2) {
  return arg1 + arg2
}

// add has an initial parameter of 1
const add = addArguments.bind(null.1)
/ / 3
add(2)
// 3, the second argument is ignored
add(2.3)
Copy the code

Functional expression

The most important difference between function expressions and function declarations is promotion

// There is a problem with this code
if (toggle) {
  function a () {
    console.log(1)}}else {
  function a () {
    console.log(2)}}// In the JS engine, it actually looks like this
function a () {
  console.log(1)}function a () {
  console.log(2)}if (toggle) {
} else{}Copy the code

But if you are using functional expressions, it is safe to do so


let sayHi;
if (condition) {
  sayHi = function() {
    console.log("Hi!");
  };
} else { 10
  sayHi = function() {
    console.log("Yo!");
  };
}
Copy the code

recursive

A function calls itself, and if it recurses by function name, the function is strongly bound. You can use arguments.callee to get a reference to yourself. Using arguments.callee in strict mode will cause an error.

closure

Closures are functions that refer to variables in the scope of another function,


function createComparisonFunction(propertyName) {
  return function(object1, object2) {
    // another scoped variable is used
    let value1 = object1[propertyName];
    let value2 = object2[propertyName];
    if (value1 < value2) {
      return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
      return 0; }}; }Copy the code

If the createComparisonFunction inner function is returned, the propertyName variable can still be used because the inner function retains the scope of the createComparisonFunction.

The scope list for the internal anonymous function contains the AO for the anonymous function, as well as the AO for the external createComparisonFunction function, and the global VO. When createComparisonFunction returns an anonymous function, the variables in createComparisonFunction can still be accessed because the anonymous function contains the AO of createComparisonFunction. As a side effect, createComparisonFunction’s AO cannot be recycled. ♻ ️

——– split line ——-

The little Red Book of closures is not as detailed here as uncle Tom’s blog. Here is uncle Tom’s blog, which is very nice 💗💗💗💗

👍 👍 👍 👍 👍 👍 👍 blog: https://www.cnblogs.com/tomxu/archive/2012/01/18/2312463.html, if you want to see the content of the lean, can see my notes to “learn” a deep understanding of JavaScript: https://github.com/peoplesing1832/blog/issues/43

——– split line ——-

It is important to note that closures preserve the scope of other functions. Overusing closures can cause memory to run out, and sometimes you need to manually free memory

function foo () {
  return function () {}}let bar = foo()
bar()
// Manually release memory
bar = null
Copy the code

this

Since the inner function is the this object that cannot access the outer function, this is the window

window.identity = 'The Window';
  let object = {
    identity: 'My Object'.getIdentityFunc() {
      return function() { return this.identity; }; }};// window, 
console.log(object.getIdentityFunc()());
Copy the code

But if you store the this of an external function in a variable, you can implement a closure to retrieve the external this


window.identity = 'The Window';
let object = {
  identity: 'My Object'.getIdentityFunc() {
    let that = this;
    return function() {
      returnthat.identity; }; }};console.log(object.getIdentityFunc()()); // 'My Object'
Copy the code

A memory leak

function assignHandler() {
  let element = document.getElementById('someElement'); 
  element.onclick = () = > console.log(element.id);
}
Copy the code

Event handlers that use the AO (active object) of assignHandler cause the Element variable to be unrecyclable. How do you avoid memory leaks


function assignHandler() {
  let element = document.getElementById('someElement');
  let id = element.id;
  element.onclick = () = > console.log(id);
  element = null;
}
Copy the code

The element. Id is stored in a variable, but the event handlers still use assignHandler’s AO. The Element variable cannot be reclaimed. Element must be set to NULL in order to touch references to it.

A function expression that is invoked immediately

Block-level scopes can be simulated using IIFE


// IIFE
(function () {
  for (var i = 0; i < count; i++) {
    console.log(i);
  }
})();
console.log(i); // Throw an error
Copy the code

In ES6, let and const are block-level scoped variables that do not require IIFE