Realize apply, call, bind

1. Implement the call function

// 给所有的函数添加一个hhcall的方法
Function.prototype.hhcall = function (thisArg, ...args) {
    
    
  //默认进行隐式绑定(可以获取到是哪一个函数调用了hhcall)
  // 1.获取需要被执行的函数
  var fn = this;

  // 2.将thisArg转成对象类型(防止它传入的是非对象类型)
  // 通过Object()转即可
  thisArg = 
  thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;

  // 3.调用需要被执行的函数
  // 相当于在thisArg这个对象加上了fn这个属性
  // 然后通过thisArg.fn()调用这个函数,相当于进行了隐式绑定,
  //使this指向thisArg这个对象
  thisArg.fn = fn;
  var result = thisArg.fn(...args);
  delete thisArg.fn;

  // 4.将最终的结果返回出去
  return result;
};
//测试:
function foo() {
    
    
  console.log("foo函数被执行", this);
}

function sum(num1, num2) {
    
    
  console.log("sum函数被执行", this, num1, num2);
  return num1 + num2;
}

// 系统的函数的call方法
foo.call(undefined); //window对象
var result = sum.call({
    
    }, 20, 30); //{} 20 30
console.log("系统调用的结果:", result); //系统调用的结果: 50

// 自己实现的函数的hhcall方法
// 默认进行隐式绑定(可以获取到是哪一个函数调用了hhcall)
foo.hhcall({
    
     name: "fifih" }); //foo函数被执行 {name: 'fifih', fn: ƒ}
foo.hhcall(undefined); //foo函数被执行 window对象
var result = sum.hhcall("abc", 20, 30); 
//sum函数被执行 String {'abc', fn: ƒ} 20 30
console.log("hhcall的调用:", result); //hhcall的调用: 50

2. Implement the apply function

// 自己实现hhapply
Function.prototype.hhapply = function (thisArg, argArray) {
    
    
  // apply后面的参数需要以数组的形式传入
  // 1.获取到要执行的函数
  var fn = this;

  // 2.处理绑定的thisArg
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;

  // 3.执行函数
  thisArg.fn = fn;
  var result;

  // if (!argArray) { // argArray是没有值(没有传参数)
  //   result = thisArg.fn()
  // } else { // 有传参数
  //   result = thisArg.fn(...argArray)
  // }

  // argArray = argArray ? argArray: []
  argArray = argArray || [];
  result = thisArg.fn(...argArray);
  delete thisArg.fn;

  // 4.返回结果
  return result;
};
//测试
function sum(num1, num2) {
    
    
  console.log("sum被调用", this, num1, num2);
  return num1 + num2;
}

function foo(num) {
    
    
  return num;
}

function bar() {
    
    
  console.log("bar函数被执行", this);
}

// 系统调用
var result = sum.apply("abc", [20, 30]); 
//sum被调用 [String: 'abc'] 20 30
console.log(result); //50

// 自己实现的调用
var result = sum.hhapply("abc", [20, 30]); 
//sum被调用 [String: 'abc'] { fn: [Function: sum] } 20 30
console.log(result); //50

var result2 = foo.hhapply("abc", [20]);
console.log(result2); //20

// edge case边界情况
bar.hhapply(0); //bar函数被执行 [Number: 0] { fn: [Function: bar] }

3. Implement the bind function

//自己实现hhbind函数
Function.prototype.hhbind = function (thisArg, ...argArray) {
    
    
  // 1.获取到真实需要调用的函数
  var fn = this;

  // 2.绑定this
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;

  function proxyFn(...args) {
    
    
    // 3.将函数放到thisArg中进行调用
    thisArg.fn = fn;
    // 特殊: 对两个传入的参数进行合并
    var finalArgs = [...argArray, ...args];
    var result = thisArg.fn(...finalArgs);
    delete thisArg.fn;

    // 4.返回结果
    return result;
  }
  return proxyFn;
};
//测试
function foo() {
    
    
  console.log("foo被执行", this);
  return 20;
}

function sum(num1, num2, num3, num4) {
    
    
  console.log(this, num1, num2, num3, num4);
  return num1 + num2 + num3 + num4;
}

// 系统的bind使用
var bar = foo.bind("abc");
bar(); //foo被执行 [String: 'abc']

var newSum = sum.bind("aaa", 10, 20, 30, 40);
newSum(); //[String: 'aaa'] 10 20 30 40

var newSum = sum.bind("aaa");
newSum(10, 20, 30, 40); //[String: 'aaa'] 10 20 30 40

var newSum = sum.bind("aaa", 10);
newSum(20, 30, 40); //[String: 'aaa'] 10 20 30 40

// 使用自己定义的hhbind
var bar = foo.hhbind("abc");
var result = bar(); //foo被执行 [String: 'abc'] { fn: [Function: foo] }
console.log(result); //20

var newSum = sum.hhbind("abc", 10, 20);
var result = newSum(30, 40); 
//[String: 'abc'] { fn: [Function: sum] } 10 20 30 40
console.log(result); //100

4. Supplement: remaining parameters (...args)

// rest parameters
function sum(...nums) {
    
    
  console.log(nums);
}

sum(10); //[10]
sum(10, 20); //[ 10, 20 ]
sum(10, 20, 30); // [ 10, 20, 30 ]
sum(10, 20, 30, 40, 50); //[ 10, 20, 30, 40, 50 ]

// 展开运算符 spread
var names = ["abc", "cba", "nba"];
// var newNames = [...names]
function foo(name1, name2, name3) {
    
    
  console.log(name1, name2, name3); //abc cba nba
}
foo(...names);

Guess you like

Origin blog.csdn.net/weixin_53737663/article/details/127163290