“This is the sixth day of my participation in the August More Text Challenge.

【1】JavaScript review (1) 【2】JavaScript review (2) 【3】JavaScript review (3)

Say “call”, “apply” and “bind” by hand

  • In common
    • call,applybindIt’s all about changethisPointing to.
    • The first argument is passed inthis
  • The difference between
    • callThe second pass is the argument list, andapplyThe second pass is an array of multiple arguments.
    • The difference in return values:
      • callIs the return value of the caller, or if the caller has no return valueundefined.
      • applyThe return result of the call is specifiedthisThe result of a function with values and parameters.
      • bindReturns a copy of the original function that has the specifiedthisAnd initial parameters.

Write a part

  • Write a call
// First define a MyCall method on the prototype of 'Function'
Function.prototype.MyCall = function () {

    // The first argument is the changed this
    let context = arguments[0];
    
    // Since the list of 'call' arguments is variable, we use 'slice' to remove the first 'this' to retrieve the rest of the arguments
    let arg = [...arguments].slice(1); 
    
    // Where 'this' refers to the caller of' MyCall '
    // In 'context', add a function of the caller whose property name is the same function.
    context[this] = this;
    
    // Return the result of the function's execution, and delete the function
    return context[this] (... arg),delete context[this];
}
Copy the code

Now let’s test our MyCall:

/ / 1
let obj = {
    age: 'obj123'};function a(){
    console.log(this.age);
};

a(); // undefined refers to 'window', but 'window' does not have the attribute 'age', so it is' undefined ';

a.MyCall(obj); // obj123 now 'this' in' a 'refers to' obj ', so you can access 'age' inside


// 2 Use an example from MDN to test it
function Product(name, price) {
  this.name = name;
  this.price = price;
}

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

console.log(new Food('cheese'.5)); // Food {name: Food, price: "cheese", category: "food"}
Copy the code

The above two examples use MyCall written by myself, and both work fine. Now let’s look at Apply.

  • Handwritten apply
Function.prototype.MyApply = function (context, arg) {
    context = context || window;
    context[this] = this;
    let result = context[this] (... arg)delete context[this];
    return result; 
}
Copy the code

In fact, apply and call are similar, but the second parameter is passed in a different way, so it is easy to write. As usual, let’s use the MDN example to test:

/ / 1
var array = ['a'.'b'];
var elements = [0.1.2];
array.push.MyApply(array, elements);
console.log(array); // ["a", "b", 0, 1, 2]

/ / 2
var numbers = [5.6.2.3.7];
var max = Math.max.MyApply(null, numbers);
var min = Math.min.MyApply(null, numbers);
console.log(max, min); / / 7, 2
Copy the code

Or very smooth completion ~

Bind bind bind bind bind bind bind bind

  • Write a bind
Function.prototype.MyBind = function () {
    // Get the 'this' to point to
    let context = arguments[0];
    // Get the parameters passed in
    let arg = [...arguments].slice(1);
    // Save the current caller
    let _this = this;
    // Bind's property is to return a function
    return function requestFn() {
        // Here is how to call the return function
        if(this instanceof requestFn){
            // If it is called by 'new', do the following
            return new_this(... arg, ... arguments); }// Plain call
        return _this.apply(context, arg.concat([...arguments]))
    }
}
Copy the code

Same old, more testing:

const module = {
  x: 42.getX: function() {
    return this.x; }};const unboundGetX = module.getX;
console.log(unboundGetX()); // undefined

const boundGetX = unboundGetX.MyBind(module);
console.log(boundGetX()); / / 42
Copy the code

Or very smooth execution success ~

The principle of the new

  • Create an empty object ({})
  • Add an attribute __proto__ to this empty object, linking it to the constructor’s prototype object
  • And then take this empty object asthisThe context in which the
  • Returns if the function does not return a reference valuethis