ES6 learning Chapter 7 function extension

Keywords: Javascript ECMAScript

preface

This chapter introduces the extension of functions. Some knowledge that is not commonly used can be understood.
Link to the original text of this chapter: Extension of function.

Default values for function parameters

ES6 allows you to set default values for function parameters, that is, write them directly after the parameter definition.
When the function parameter is not assigned, the default value is assigned to the function parameter.

// The default value is written directly after the row parameter
function sampleFn(sample = 0, sample1 = 0) {
  return sample + sample1;
}

be careful:

  • Parameter variables are declared by default, so they cannot be declared again with let or const.
  • When using parameter defaults, a function cannot have parameters with the same name.
  • Parameter defaults are evaluated lazily.
  • After the default value of the function is specified, the length property of the function returns the number of parameters without a default value specified.
  • Once the default value of the parameter is set, the parameter will form a separate scope (context) when the function is declared and initialized.
// The default value is written directly after the row parameter
function sampleFn(sample = 0, sample1 = 0,sample = 1) { // Cannot have a parameter with the same name

  let sample = 1; // Cannot be declared again

  return sample + sample1;
}

Note: normally, the parameter with the default value defined should be the tail parameter of the function. That is, at the back.

Default value of deconstruction assignment

// The default value of a function can be used in conjunction with the default value of a structure assignment
function sampleFn({ sample = 0, sample1 = 0 } = {}) { // Function parameter defaults
  return sample + sample1;
}

console.log(sampleFn({ sample: 23, sample1: 33 })); // 56 parameter needs to correspond to the type of deconstruction assignment

Scope

When the function parameter is set to the default value and the function is declared for initialization, the function parameter will generate a separate scope. When the initialization is completed, the scope will disappear. Moreover, this behavior only occurs when the function parameter specifies a default value.

let sample = 1;

/* 
    A separate scope appears at the time of declaration
  In this scope, the variable is undefined, so it points to the outer variable
    When a function is called, the internal variable of the function does not affect the default value variable
*/
function sampleFn(sample1 = sample) { 
  let sample = 2;
  console.log(sample1);
  return sample1;
}

sampleFn() // 1

rest parameter

ES6 introduces the rest parameter to obtain the redundant parameters of the function.
The arguments object is an array of classes, and the rest parameter is a real array.

The form is:... Variable name, and the last named parameter of the function is prefixed with.

// In the following example... values is the rest parameter, which is used to obtain redundant parameters
const sample = function (title, ...values) {
  let sample = values.filter(
    (item) => {
      return item % 2 === 0;
    }
  )

  return (title + sample);
}

console.log(sample("Find even number", 1, 2, 6, 2, 1));  // Find even number 2, 6, 2

Note: the rest parameter can only be the last parameter of the function. The length of the function does not include the rest parameter

Strict mode

In JavaScript, as long as the strict mode in the function will act on the function parameters and function body.
ES2016 stipulates that as long as the function parameter uses default value, deconstruction assignment, or extension operator, the internal function cannot be explicitly set to strict mode, otherwise an error will be reported.

function sample() { // Parameters use default values, deconstruction assignment, and extension operators 
  'use strict'; // Turn on strict mode
}

name attribute

The name property of the function returns the function name of the function.

function sample() { };
let sample1 = function () { };
function sample2() {};

console.log(sample.name); // sample
console.log(sample1.name); //  sample1 

// bound sample2 uses the bind method, and the output will have a bound prefix
console.log(sample2.bind({}).name); 
console.log((new Function).name); // The name value of anonymous constructor is anonymous

Arrow function

Brief introduction

ES 6 adds a function definition method, which uses arrows to connect parameter columns with function questions.
The arrow function is equivalent to an anonymous function and simplifies the function definition. The arrow function does not have a prototype.

// Ordinary function
let sample = function (item) {
  return item;
};

// The above function is equivalent to the following function

// Use arrow function
let sample = (item) => { return item}; // Arrow function

Arrow function abbreviation

Yes, the arrow function can also be abbreviated

  1. When there is only one parameter, the bracket to the left of the arrow can be omitted, but when there is no parameter, the bracket cannot be omitted.
  2. When there is only one expression in the function body, the brace to the right of the arrow can be omitted, but the return statement must be omitted and written on one line.
  3. When the body of a function is divided into more than one statement, it is necessary to enclose them in braces and return them with a return statement.
// The following functions are written in the same way
let sample = function (item) {
  return item;
};

let sample = (item) => { return item}; // Arrow functions are not omitted

let sample = item => { return item}; // Omit the left parenthesis

let sample = (item) => item; // Omit the right brace and return

let sample = item => item; // ✌ Omit the left parenthesis and right curly braces and return

// If no special case of return value is required
let sample = item => void item;
console.log(sample()); // undefined

Attention

  • By default, This of the arrow function points to This that defines its scope.
  • Arrow functions cannot be used as constructors.
  • The arrow function cannot use the arguments object, which does not exist in the function body.
  • The arrow function cannot use the yield command, nor can it be used as a Generator function.

this of the arrow function

The arrow function inherits this on the scope chain where it is defined.
The arrow function this has been determined when it is defined, so the arrow function this will not change.
When using call() or apply() methods, you cannot rebind this to the arrow function. The binding () method is invalid.

window.sample = "window within ";

function sampleFn() {
  let thiz = this;
  let sample = "sampleFn within ";

  let sampleObj = {
    sample: "sampleObj within ",

    // Ordinary function
    sampleFn1: function () {
      console.log(thiz === this);
      console.log(this.sample);
    },

    // Arrow function
    sampleFn2: () => {
      // The scope of the arrow function is sampleObj, and the upper layer is sampleFn
      console.log(thiz === this); //this of the arrow function  
      console.log(this.sample);
    }
  }

  sampleObj.sampleFn1();  // False, in sampleobj 
  sampleObj.sampleFn2();  // True, in window
}

sampleFn();

Tail call optimization

There are two concepts

  1. Tail call
    Tail Call is an important concept of functional programming, which means that the last step of a function is to call another function.
  2. Tail recursion
    The function call itself is called recursion. If the tail calls itself, it is called tail recursion.

ES6 clearly stipulates that all ECMAScript implementations must deploy "tail call optimization".
That is to say, as long as tail recursion is used in ES6, stack overflow (or timeout caused by layer upon layer recursion) will not occur, which is relatively memory saving.

What does that mean?

The function of tail call is written as follows in the original text:

We know that function calls will form a "call record" in memory, also known as "call frame", which saves information such as call location and internal variables. If function B is called inside function a, a call frame of B will be formed above the call frame of A. When B runs and returns the result to a, the call frame of B will disappear. If function B calls function C internally, there is also a call frame of C, and so on. All call frames form a call stack.
Since the tail call is the last operation of the function, it is not necessary to retain the call frame of the outer function, because the call location, internal variables and other information will not be used again. As long as the call frame of the inner function is directly used to replace the call frame of the outer function.

Explain it another way

When a function is called, the function execution context will be pushed into the execution stack. The corresponding execution context will not be pushed out of the stack until the function execution is completed.
Call function B inside function A. if function B contains a reference to the variable in function a, the execution context corresponding to function a cannot be out of the stack even if the execution ends. If function B contains a call to function C, the execution context corresponding to functions a and B cannot be out of the stack until function C is executed. And so on. The previous function (inner function) must be in the execution stack This is tail call optimization.

// Tail recursion
function sampleFn(sample) {
  if (sample <= 1) return 1;
  return sampleFn(sample - 1) + sample;
}
sampleFn(2);

be careful:

  • Tail call optimization can only be performed when the inner function does not use the internal variables of the outer function.
  • At present, only Safari browser supports tail call optimization, which is not supported by Chrome and Firefox.

Minor modifications to ES 6

Function argument trailing comma

ES2017 allows the last parameter of a function to have a trailing comma.
Such provisions also make the function parameters consistent with the tail comma rules of arrays and objects.

function sampleFn(
  sample1,
  sample2,
  sample3, // You can add a comma ',' after the last parameter
) {}

toString() modify

Function.prototype.toString()
ES2019 has modified the toString() method of the function instance. It is clear that as like as two peas, the same source code is returned.
The toString() method returns the function code itself. Comments and spaces will be omitted before ES6.

function sampleFn() {
  // notes
}

let sample = sampleFn.toString();
console.log(sample);
//Output exactly the same original code, including spaces and comments
/*
function sampleFn() {
  // notes
}
*/

catch modification

ES2019 changes the requirement that the catch statement must carry parameters. Allow catch statements to omit parameters.

try {
  // ...
} catch { // Without parameters
  // ...
}

Posted by ace21 on Sun, 28 Nov 2021 19:13:09 -0800