This points to a detailed explanation, the combination of mind map and code, let you understand this, call, apply. Series (1)

Posted Jun 16, 20209 min read

this points to a detailed explanation

This is my first article in segmentfault, welcome to correct me
Thinking + map + sample code => ship new version

table of Contents

  • Foreword + thinking questions
    1. The point of this
  • Second, call and apply
    1. Simulate a call
  • Four, bind
    1. End

Foreword + thinking questions

I remember when I was looking for an internship, I always added a sentence to my resume-familiar with Js, such as this point, call, apply, etc...

image

And every time I submit a resume, I will go through the following steps

  • Before the interview, ask Du Niang-what kind of points can this point be divided into ~, what is the difference between call and apply? The bottom gas has soared from 0%to 50%;
  • During the interview, the interviewer threw a few questions at random, I can give the answer "firmly", the result is always unsatisfactory...
  • After the interview, I will shamefully delete this one on my resume. And then I added this again when I submitted my resume...

image

Thinking questions

The following questions are the hot questions I searched on the Internet. If the big brothers can easily answer and have clear ideas, you may wish to directly like it(after all, it also consumes a lot of brain cells), It would be even better if the bigwigs could point out one or two in the comments! ! !

Fill in the blank:

  • Executing the function in Javascript will create a new function. The new function and the called function have the same function body. When the target function is called, this value points to the first parameter.

Questions and Answers:

  • Please talk about the types of functions that change the this pointer inside the function, what is the difference between them?
  • What kind of points can this point into?

Code Analysis Question:

var name ='window'

var person1 = {
  name:'person1',
  show1:function() {
    console.log(this.name)
  },
  show2:() => console.log(this.name),
  show3:function() {
    return function() {
      console.log(this.name)
    }
  },
  show4:function() {
    return() => console.log(this.name)
  }
}
var person2 = {name:'person2'}

person1.show1()
person1.show1.call(person2)

person1.show2()
person1.show2.call(person2)

person1.show3()()
person1.show3().call(person2)
person1.show3.call(person2)()

person1.show4()()
person1.show4().call(person2)
person1.show4.call(person2)()

First, this point

Enter the "pointing to this" keyword on Baidu and Google, there must be thousands of articles, and it is not necessary to read all the articles in order to master it in a comprehensive and non-dead corner, right? So it is better to sort out a solid frame and fill it along with our ideas.

mind Mapping

Insert picture description here

The essence of this section:

  • this always(in non-strict mode) points to an object, and the specific point to which object is dynamically bound based on the execution environment of the function at runtime, not the environment when the function is declared;

  • Except for the less commonly used with and eval, specific to practical applications, this point can be divided into four types:

    • Method call as object;
    • Called as an ordinary function;
    • Constructor call;
    • call or apply call;
    • In the arrow function, this points to this in the upper scope of the function;
  • The difference between constructor and ordinary function lies in the call method;

  • A,call(B) => can be understood as the method A is called within the scope of B;

Analysis

1, method call as object

When a function is called as a method of an object, this points to the object

var obj = {
    a:'yuguang',
    getName:function(){
        console.log(this === obj);
        console.log(this.a);
    }
};

obj.getName(); //true yuguang

2. Call as an ordinary function

When a function is not called as an attribute of an object, but as a normal function, this always points to the global object(in browsers, it is usually the Window object)

window.name ='yuguang';

var getName = function(){
    console.log(this.name);
};

getName(); //yuguang

Or the following confusing code:

window.name ='Lao Wang'
var obj = {
    name:'yuguang',
    getName:function(){
        console.log(this.name);
    }
};

var getNew = obj.getName;
getNew(); //Lao Wang

In ES5's strict mode, this is specified as not pointing to the global object, but undefined

3, constructor call

Except for some built-in functions, most of the functions in Js can become constructors, they are no different from ordinary functions

The difference between constructor and ordinary function lies in the call method:
When the new operator calls a function, it always returns an object, this usually also points to this object

var MyClass = function(){
    this.name ='yuguang';
}
var obj = new MyClass();
obj.name; //yuguang

However, if an object is explicitly returned, then the result of this operation will eventually return this object.

var MyClass = function() {
    this.name = 1;
    return {
        name:2
    }
}
var myClass = new MyClass();
console.log('myClass:', myClass); //{name:2}

As long as the constructor does not display any data returned, or returns data of a non-object type, it will not cause the above problem.

4, call or apply call

Compared with ordinary function calls, this function can be dynamically changed with call and apply

var obj1 = {
    name:1,
    getName:function(num ='') {
        return this.name + num;
    }
};

var obj2 = {
    name:2,
};
//It can be understood that the obj1.getName() function is called in the scope of obj2
console.log(obj1.getName()); //1
console.log(obj1.getName.call(obj2, 2)); //2 + 2 = 4
console.log(obj1.getName.apply(obj2, [2])); //2 + 2 = 4

5. Arrow function

The arrow function does not create its own this, it only inherits this from the upper layer of its scope chain.

Therefore, in the following code, this in the function passed to setInterval is the same as this in the enclosed function:

this.val = 2;
var obj = {
    val:1,
    getVal:() => {
        console.log(this.val);
    }
}

obj.getVal(); //2

Common pits

Just like the title, sometimes this will point to undefined

Case 1

var obj = {
    name:'1',
    getName:function(params) {
        console.log(this.name)
    }
};
obj.getName();

var getName2 = obj.getName;
getName2();

At this time, when getName2() is called as an ordinary function, this points to the global object-window.

Case 2

When we want to encapsulate the Dom method ourselves to streamline the code:

var getDomById = function(id) {
    return document.getElementById(id);
};
getDomById('div1') //dom node

So let's see if it works like this?

var getDomById = document.getElementById
getDomById('div1') //Uncaught TypeError:Illegal invocation

This is because:

  • When we call the method of the document object, this in the method points to document.
  • When we use the method in document with getId and then call it as a normal function, the this of the function content points to the global object.

Use call and apply to correct situation two

document.getElementById =(function(func) {
    return function(){
        return func.call(document, ...arguments)
    }
})(document.getElementById)
//Use the immediate execution function to save the document in scope

image

Second, call and apply

Don t resist it because of its powerfulness , we must do it to understand and be familiar with it.

mind Mapping

Insert picture description here

1. The difference between call and apply

Let's look at the difference first, because they are almost no different, and the following code examples can be easily switched between call and apply.

When they were designed, the things to be done were exactly the same. The only difference was that the format of the parameters was not the same.

  • apply accepts two parameters

    • The first parameter specifies the pointing of this object in the function body
    • The second parameter is a subscripted parameter set(can be an array or array-like)
  • The parameters accepted by call are not fixed

    • The first parameter specifies the pointing of this object in the function body
    • The second parameter and subsequent parameters for function call

Because in all(non-arrow) functions, you can refer to the parameters of the function in the function through the arguments object. This object contains every parameter passed to the function, which itself is an array-like, we apply more common in actual use.

Call is syntactic sugar wrapped in apply. If we know the number of parameters explicitly and want to show them, we can use call.

When using call or apply, if the first parameter we pass in is null, this in the function body will default to the host object, which is window in the browser.

How to borrow other objects

We can directly pass null to replace any object

Math.max.apply(null, [1, 2, 3, 4, 5])

2. What can call and apply do?

Use a specified value of this and one or more parameters given separately to call a function-When to MDN

  • Call the constructor to implement inheritance;
  • Call the function and specify the context of this;
  • Call the function without specifying the first parameter;

1. Call the constructor to implement inheritance

To achieve the effect of inheritance by "borrowing":

function Product(name, price) {
    this.name = name;
    this.price = price;
}

function Food(name, price) {
    Product.call(this, name, price); //
    this.category = food;
}

var hotDog = new Food('hotDog', 20);

2. Call the function and specify this of the context

At this time this is pointed to obj

function showName() {
    console.log(this.id +':' + this.name);
};

var obj = {
    id:1,
    name:'yuguang'
};

showName.call(obj)

3. Use call to simply call a function

Math.max.apply(null, [1,2,3,10,4,5]); //10

  1. Simulate a call

Let s first look at what the call needs to do

var foo = {
    value:1
};
function show() {
    console.log(this.value);
};
show.call(foo); //1

Just like solving equations, we need to find breakthroughs in known conditions:

  • call makes the pointing of this change to point to foo;
  • show function was executed;
  • The incoming parameter should be this + parameter list;

First edition code

The 3 points mentioned above, only completed one point, and the parameters passed in

var foo = {
    value:1
};
function show() {
    console.log(this.value);
};
Function.prototype.setCall = function(obj) {
    console.log(this); //At this point this points to show
    obj.func = this; //Turn the function into an internal property of the object
    obj.func(obj.value); //Specify the function
    delete obj.func //Delete the function, when nothing happens~
}
show.setCall(foo);

Second Edition Code

In order to solve the parameter problem, we need to be able to get the parameters and pass them in correctly:

var foo = {
    value:1
};
function show(a, b) {
    console.log(this.value);
    console.log(a + b);
};
Function.prototype.setCall = function(obj) {
    obj.fn = this; //Turn the function into an internal property of the object
    var args = [];
    for(let i = 1; i <arguments.length; i++){
        args.push('arguments[' + i +']');
    }
    eval('obj.fn(' + args +')'); //incoming parameters
    delete obj.fn; //Delete the function, when nothing happens~
}

show.setCall(foo, 1, 2); //1 3

At this point, we can do it, using call with multiple parameters, but what if you only want to use a certain method?

Third Edition Code

Function.prototype.setCall = function(obj) {
    var obj = obj || window;
    obj.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i <len; i++) {
        args.push('arguments[' + i +']');
      }
      var result = eval('obj.fn(' + args +')');
      delete obj.fn;
      return result;
};
//have a test
var value = 2;
var obj = {value:1 };

function bar(name, age) {
      console.log(this.value);
      return {
        value:this.value,
        name:name,
        age:age
      }
}
bar.setCall(null); //2
console.log(bar.setCall(obj,'yuguang', 18));

Four, bind

The bind() method creates a new function. When bind() is called, the this of the new function is specified as the first parameter of bind(), and the remaining parameters will be used as parameters of the new function for use in the call MDN

When call and apply are mentioned, bind cannot be avoided. We try to simulate a bind method in order to deepen our understanding:

Function.prototype.bind = function(obj) {
    var _this = this; //Save the function that calls bind
    var obj = obj || window; //Make sure this is pointed to. If obj is empty, the scope of this needs to be topped.
    return function(){
        return _this.apply(obj, arguments); //fix the pointing of this
    }
};

var obj = {
    name:1,
    getName:function(){
        console.log(this.name)
    }
};

var func = function(){
    console.log(this.name);
}.bind(obj);

func(); //1

It seems that returning a copy of the original function and having the specified this value is quite reliable~

Write at the end

The first part of the basic part of JavaScript internal power. It is concluded that this series has been greatly encouraged and inspired by . The total number of chapters in this series is to be determined, and we are guaranteed to be the highest in the interview. Frequently, but often overlooked in work.

JavaScript Internal Power Series:

  1. This article
  2. Next article pre-issue:prototype and prototype chain

about me

  • Flower name:Yu Guang
  • One front-end development, limited level, learning modestly

Other precipitation

If you see the last, you may wish to bookmark, like, comment! ! !
Constantly updated, your three consecutive is my biggest motivation, openly accept the criticism and guidance of the big brothers, and encourage!