A brief introduction to this, bind, call & apply in JavaScript

A brief introduction to this, bind, call & apply in JavaScript

thisis a rather special thing, basically it can be understood that the pointing thisof is the pointing of the nearest call, so thisit is also a confusing knowledge point in JS.

The thisprevious basically uses the arrow function, because the arrow function does not contain bindings to this, arguments, superor , so when using the arrow function, thisthe direction of is easier to judge, but recently I feel that it is time to study this, call, andapply .bind

The pointing problem of this

As mentioned above, thisthe pointing to adopts the principle of nearest call, take the following code as an example:

const person = {
    
    
  name: 'John',
  greet() {
    
    
    console.log(this);
    console.log('Hello ' + this.name);
  },
};

Under normal circumstances, the pointergreet in should refer to , which is correct in the case of the following call:thisperson

person.greet();

insert image description here

In this case, greetit is called through personthis object, so greetthe binding environment is personthe object itself.

However, calling it in another way will have different results:

const {
    
     greet } = person;
greet();

At this time, greetthe pointer becomes global, or becomes undefined in strict mode:

insert image description here

insert image description here

This is because greetis deconstructed, and it is called under the global object at this time, in other words, at this time thiswill be automatically bound to globalthe object .

Another way to call:

const user = {
    
    
  name: 'user',
};

user.greet = person.greet;

user.greet();

At this time, greetbecause it is usercalled, the bound object is user:

insert image description here

In most cases this, the problem is not very big, but sometimes it will be a troublesome thing to use callback, such as the following to simulate a mount callback and implement delayed execution:

const example = {
    
    
  addEventListener(cb) {
    
    
    this.cb = cb;
  },
  click() {
    
    
    this.cb();
  },
};

example.addEventListener(person.greet);
example.click();

At this time, the pointer greetin becomes example:

insert image description here

This method is also often implemented behind the scene, so the direction thisof is quite unclear.

In some cases, this is where bind, calland applycan help.

bind

bindwill create a new function, and bindwill thisbind as the first passed parameter.

I think back to when I used React's class based component, when I didn't use the arrow function, I always used it bindto execute:

class ExplainBindingsComponent extends Component {
    
    
  constructor() {
    
    
    super();

    this.onClickMe = this.onClickMe.bind(this);
  }

  onClickMe() {
    
    
    console.log(this);
  }
}

This is to thisbind in the current class so that it does not follow the principle of proximity. The first parameter here is the object to be bound. It can be used when the first bound object does not matter null. Use thisrefers to the current object, or you can explicitly use an instantiated object.

In the above cases, the bindbinding rewriting method is as follows:

// 'use strict';

const person = {
    
    
  name: 'John',
  greet() {
    
    
    console.log(this);
    console.log('Hello ' + this.name);
  },
};

const {
    
     greet } = person;
greet();
greet.bind(person)();

const user = {
    
    
  name: 'user',
};

user.greet = person.greet.bind(person);

user.greet();

const example = {
    
    
  addEventListener(cb) {
    
    
    this.cb = cb;
  },
  click() {
    
    
    this.cb();
  },
};

example.addEventListener(person.greet.bind(person));
example.click();

insert image description here

insert image description here

insert image description here

In this way, it can bindbe thisbound to a fixed object so that it is not affected by the proximity principle. In addition, bindother parameters can also be accepted and passed to the called function, such as:

const person = {
    
    
  name: 'John',
  greet(from) {
    
    
    console.log(this);
    console.log('Hello ' + this.name + ' from ' + from);
  },
};

const {
    
     greet } = person;
// greet();
greet.bind(person, 'Sam')();

In some cases, using can bindalso simplify the code, for example, the following code can realize a basic addition, subtraction, multiplication and division operation:

const math = {
    
    
  accumulated: 0,
  add(num) {
    
    
    const oldNum = this.accumulated;
    this.accumulated += num;
    console.log(`${
      
      oldNum} + ${
      
      num} = ${
      
      this.accumulated}`);
  },
  substract(num) {
    
    
    const oldNum = this.accumulated;
    this.accumulated -= num;
    console.log(`${
      
      oldNum} - ${
      
      num} = ${
      
      this.accumulated}`);
  },
  multiply(num) {
    
    
    const oldNum = this.accumulated;
    this.accumulated *= num;
    console.log(`${
      
      oldNum} * ${
      
      num} = ${
      
      this.accumulated}`);
  },
  divide(num) {
    
    
    const oldNum = this.accumulated;
    this.accumulated /= num;
    console.log(`${
      
      oldNum} / ${
      
      num} = ${
      
      this.accumulated}`);
  },
};

math.add(10);
math.substract(5);
math.multiply(2);
math.divide(5);

insert image description here

In this case, you can use bindto simplify the operation:

const math = {
    
    
  accumulated: 0,
  calculation(operation, num) {
    
    
    let oldNum = this.accumulated;
    if (operation === '+') {
    
    
      this.accumulated += num;
    } else if (operation === '-') {
    
    
      this.accumulated -= num;
    } else if (operation === '*') {
    
    
      this.accumulated *= num;
    } else if (operation === '/') {
    
    
      this.accumulated /= num;
    }
    console.log(`${
      
      oldNum} ${
      
      operation} ${
      
      num} = ${
      
      this.accumulated}`);
  },
};

const {
    
     calculation } = math;
calculation.bind(math, '+', 10)();
calculation.bind(math, '-', 5)();
calculation.bind(math, '*', 2)();
calculation.bind(math, '/', 5)();

The final running results are also consistent:

insert image description here

It does not mean that it must be used bindto execute, but other methods can also be used to make the code more clear and readable, and improve reusability

call & apply

callapplyand will not create a new function, but their usage is similar to bind, the first parameter is thisthe pointer of , but callcan pass unlimited parameters, and applywill accept an array like structure as the second parameter :

call(thisArg, arg1, /* …, */ argN);

apply(thisArg, argsArray);

According to mdn, under normal circumstances, when constructed is not involved, andbind can be regarded as having the same effect:call

You can generally see const boundFn = fn.bind(thisArg, arg1, arg2) as being equivalent to const boundFn = (...restArgs) => fn.call(thisArg, arg1, arg2, ...restArgs) for the effect when it’s called (but not when boundFn is constructed).

reference

Guess you like

Origin blog.csdn.net/weixin_42938619/article/details/130738314