Understand the principles of call, apply, and bind, and write simple call, apply, and bind methods by hand

Understand the principles of call, apply, and bind, and write simple call, apply, and bind methods by hand

call principle and implementation

MDN Definition: call()A method calls a function with the given thisvalue and arguments provided separately.

In my own words: change the this point of calling the call method.

Use the syntax:function.call(target, arg1, arg2, arg3)

  • Serving Instructions:
// 全局的name
var name = "全局的name";

// obj对象
const obj = {
    
    
  name: "obj对象的name",
};

// 方法
function printName(a) {
    
    
  console.log(this.name + a);
}

printName(); // 直接调用this指向全局
// 全局的name

printName.call(obj, "附加"); // 改变this指向为obj
// obj对象的name附加

After understanding what call does, then write a myCall method based on the understanding.

Note: 1. call is actually a method on Function.prototype; 2. Any function can access the method on its own prototype

  • Dishes for DIY:
Function.prototype.myCall = function (targetObj = {
     
     }, ...args) {
    
    
  const fn = Symbol("fn"); // 定义一个唯一的 Symbol 避免意外污染替换 targetObj 的属性
  targetObj[fn] = this; // this 就是调用 myCall 方法的“函数本身”
  const result = targetObj[fn](...args); // 通过 targetObj 执行方法,并传入额外参数
  delete targetObj[fn]; // 删除添加的属性
  return result; // 返回执行结果
};

const obj = {
    
    
  name: "alice",
};
// 方法
function printName(a) {
    
    
  console.log(this.name + a);
}
printName.myCall(obj, " is a beauty");
// alice is a beauty

Done! Is it nice to write it out according to the idea? It feels very simple.


apply principle and implementation

The effect of apply is the same as that of call, it is a matter of changing the point of this. The difference: the parameters received by apply are two parameters: the target object and the parameter array

  • Direct DIY dish
Function.prototype.myApply = function (target, argList) {
    
    
  const targetObj = target || {
    
    };
  const fn = Symbol("fn");
  targetObj[fn] = this;
  const result = targetObj[fn](...argList);
  delete targetObj[fn];
  return result;
};

// 测试一下
const obj = {
    
    
  name: "crk",
};
function print(...arr) {
    
    
  console.log(this.name + arr);
}

print.myApply(obj, [1, 2, 3]);

The implementation and principle of bind

The usage is similar to the previous two. It will not be executed immediately after being pointed to by this, but will return a new function that can be executed, and will not be executed automatically.

  • Points to note:
    1. In addition to this, bind() also receives other parameters, and the returned function can also receive parameters (meaning that parameters can be passed when executing the returned function). And these two parts of the parameters need to be passed to the returned function
    2. If the method returned by bind() is executed by new, the internal this point will be changed again.
    3. The properties and properties of the "metamethod" on the prototype chain should be retained method

Simple bind implementation:

Function.prototype.myBind = function () {
    
    
  const args = Array.prototype.slice.call(arguments); // myBind 接口的所有参数
  const targetObj = args.shift(); // 第一个参数是 this 的目标对象,args剩下的是绑定时的参数
  const self = this; // 调用 myBind 的"元方法"

  // new 优先改变 this
  const cbFn = function () {
    
    
    // 当是new的时候,this instanceof self 的值为true,这个时候this应该指向被new的函数自己
    self.apply(
      this instanceof self ? this : targetObj,
      args.concat(Array.prototype.slice.call(arguments))
    );
  };

  // 被bind后生产的函数可以多次调用,是持久的。所以需要保留原型链上的方法和属性。这里使用原型继承
  cbFn.prototype = Object.create(self.prototype);

  return cbFn;
};

Test the basic functions:

const obj = {
    
    
  name: "小强",
};

function foo() {
    
    
  console.log(this.name, ...arguments);
}

foo.myBind(obj, 1, 2, 3)(); // 小强 1 2 3
foo.myBind(obj, 1, 2, 3)(4); // 小强 1 2 3 4

Test the function of the function new after bind

function factory(name) {
    
    
  this.name = name;
  this.fn = function () {
    
    
    return this.name;
  };
}

const newObj = {
    
    
  name: "大强",
};

const bindF = factory.myBind(newObj);
const f = new bindF("大枪");
console.log(f.fn()); // 大枪
  • Although this is specified in myBind, the use of new changes the direction of this

So far, Bi

Guess you like

Origin blog.csdn.net/qq_44900902/article/details/128968937