The article was first published on a personal blog

takeaway

this

I remember that I wrote an article about two years ago to understand this in JS. The two sentences summed up at that time are as follows:

  1. Normal functions point to function callers: an easy way to do this is to see if there is a dot in front of the function, and if there is, point to the value in front of the dot.
  2. The arrow function points to the domain in which the function is used: note the understanding of scope, only of the function{}Constitutes a scope, object{}As well asif(){}Do not constitute a scope; At that time, I didn’t have a very deep understanding of the internal principle of this, so I could only sum up the criteria I used to judge it at that time based on many difficulties ENCOUNTERED. I’m going to go into a little bit of depth here again. Train of thought still revolve above summary those two sentences.

Ordinary function calls

  1. The default binding
var a = 'luckyStar';
function foo() {
    console.log(this.a);
}
foo();
// luckyStar
Copy the code

Foo () calls directly. In non-strict mode, this refers to the window; in strict mode, this refers to undefined;

  1. Implicit binding
var a = 'luckyStar';
var obj = {
    a: 'litterStar',
    foo() {
        console.log(this.a);
    }
}
obj.foo(); / / 1.
// litterStar

var bar = obj.foo; 
bar(); / / 2.
// luckyStar 

setTimeout(obj.foo, 100); / / 3.
// luckyStar 
Copy the code

Position ①, obj.foo(), is passed by obj. The operator calls foo(), so it points to the value obj.

Foo is assigned to bar, but foo is actually assigned to bar. When bar() is called, there is no caller, so the default binding rule is used.

In position 3, setTimeout is assigned to obj.foo, but foo is still called. When it is called, there is no caller, so the default binding rule is used.

Pay attention to position ② and position ③.

  1. Explicitly bound
function foo() {
    console.log(this.name);
}
const obj = {
    name: 'litterStar'
}
const bar = function() {
    foo.call(obj);
}
bar();
// litterStar
Copy the code

Using Call, Apply can explicitly change the reference to this, which is covered in more detail below.

  1. The new binding
function Foo(name) {
    this.name = name;
}
var luckyStar = new Foo('luckyStar');
luckyStar.name; 
// luckyStar
Copy the code

To explain the above results, start with the process of New

  1. Create a new empty object obj
  2. Points the prototype of the new object to the prototype of the current function
  3. The newly created object is bound to the current this
  4. If no other object is returned, obj is returned, otherwise something else is returned
function _new(constructor, ... arg) {
    // create a new empty object obj
    const obj = {};
    // set the new object's prototype to the current function's prototype
    obj.__proto__ = constructor.prototype; // The newly created object is bound to const result =constructor.apply(obj, arg); Return typeof result === 'object'? Return typeof result === 'object'? result : obj; } function Foo(name) {this.name = name;
}
var luckyStar = _new(Foo, 'luckyStar');
luckyStar.name; //luckyStar
Copy the code

Arrow function call

There is no this binding in the arrow function, because this points to the field used by the function. Arrow functions cannot be constructors

const obj = {
    name: 'litterStar',
    say() {
        console.log(this.name);
    },
    read: (a)= > {
        console.log(this.name);
    }
}
obj.say(); // litterStar
obj.read(); // undefined
Copy the code

Call, apply, bind

Call (), function.prototype.call (), function.prototype.apply, function.prototype.bind (), All functions are instances of Funciton, so all functions can call call, apply, and bind.

Call, apply, bind

Similarities:

The first argument to call, apply, and bind is this. If you don’t care who this is, you can set it to null

Difference:

  • When a function calls call, apply returns the value of the call.
  • Bind, on the other hand, returns a new function, and you need to add a little bracket to call it.
  • The difference between Call and apply is that call takes a list of parameters, while Apply takes an array.

But with the introduction of ES6… Expand the operator, and in many cases there is not much difference between using Call and applying.

For example, find the largest value in an array

const arr = [1.2.3.5];
Math.max.call(null. arr);Math.max.apply(null, arr);
Copy the code

Math. Max is a numerical method, which is not present in arrays, but we can use the math. Max method to calculate the maximum value of the current array by calling and applying.

Hand write call, apply, bind

Implement a call:

  • If this is not specified, it points to window by default
  • Sets the function as a property of the object
  • Execute the function by specifying this to the function and passing in the given argument
  • Execute &delete this function and return the result of the function execution
Function.prototype.myCall = function(thisArg = window) {
    // thisarg.fn refers to the current function fn (fn.mycall)
    thisArg.fn = this;
    // The first argument is this, so take the rest of the arguments
    const args = [...arguments].slice(1);
    // Execute the function
    constresult = thisArg.fn(... args);ThisArg does not exist, so it needs to be removed
    delete thisArg.fn;
    return result;
}

function foo() {
    console.log(this.name);
}
const obj = {
    name: 'litterStar'
}
const bar = function() {
    foo.myCall(obj);
}
bar();
// litterStar
Copy the code

Implementing an Apply procedure is similar to call, except that the parameters are different and will not be described here

Function.prototype.myApply = function(thisArg = window) {
    thisArg.fn = this;
    let result;
    // Check if there is a second argument
    if(arguments[1]) {
        // The apply method is called with an array as its second argument, so expand arguments[1] before passing in the functionresult = thisArg.fn(... arguments[1]);
    } else {
        result = thisArg.fn();
    }
    delete thisArg.fn;
    return result;
}

function foo() {
    console.log(this.name);
}
const obj = {
    name: 'litterStar'
}
const bar = function() {
    foo.myApply(obj);
}
bar();
// litterStar
Copy the code

Implement a bind

The bind() method creates a new function. When bind() is called, this of the new function is specified as the first argument to bind(), and the remaining arguments will be used as arguments to the new function.

Function.prototype.myBind = function(thisArg) {
    // Save this for the current function
    const fn = this;
    // Save the original parameters
    const args = [...arguments].slice(1);
    // Return a new function
    return function() {
        // Get a new parameter again
        const newArgs = [...arguments];
        /** * 1. Change this to thisArg * 2. Pass multiple arguments to the function at once
        return fn.apply(thisArg, args.concat(newArgs))
    }
}

const obj1 = {
    name: 'litterStar',
    getName() {
        console.log(this.name)
    }
}
const obj2 = {
    name: 'luckyStar'
}

const fn = obj1.getName.myBind(obj2)
fn(); // luckyStar
Copy the code

Most of the handwritten part of the code referred to more online writing methods. The premise of writing code is to understand what the function is, how it works, and what it does.

Important reference

  • JavaScript you Don’t Know (Volume 1)
  • Can’t use call,apply,bind, how to use JS to implement call or apply function?
  • JavaScript in-depth simulation of bind implementation
  • “Intermediate and advanced front-end interview” JavaScript handwritten code unbeatable secrets
  • 22 high-frequency JavaScript handwritten interview questions and answers
  • Polyfill of bind on MDN

other

Recently, WE launched a 100-day front-end advanced plan, which is mainly to dig into the principle behind each knowledge point. Welcome to follow the wechat public account “Mucode star”, and we will study together and punch the clock for 100 days.