实现js的call-apply-bind函数

84 阅读2分钟

实现js的call-apply-bind函数

因为call-apply-bind 函数底层通过C++实现,只能实现函数的大致功能.我只做了简单的一些边界处理( edge case ),你还可以添加更多的边界处理.

实现call()

// 给所有的函数添加一个FhCall的方法
Function.prototype.FhCall = function(thisArg, ...args){
  console.log('args的值:', args); // []

  // 问题: 是哪个函数调用了FhCall
  // 1.获取需要被执行的函数
  var fn = this
  // 2.把thisArg转为对象类型(防止传入非对象类型)
  // (thisArg!==null && thisArg!=undefined)对传入 0 进行处理 
  thisArg = (thisArg!==null && thisArg!=undefined) ? Object(thisArg) : window
  // 3.调用需要被执行的函数
  thisArg.fn = fn
  var result = thisArg.fn(...args) // 剩余参数,有没有传参.默认为 []
  // 删除对象中的属性名
  delete thisArg.fn
  // 4.将最终的结果返回出去
  return result
}


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

// 自定义的call
var result = abc.FhCall('abc',1,2,6)
console.log(result);

var result = abc.FhCall('abc')
console.log(result);

实现apply()

Function.prototype.FhApply  = function(thisArg, argArray){ // argArray = [] 可以设置默认值进行处理
  var fn = this
  // (thisArg!==null && thisArg!=undefined)对传入 0 进行处理(edge case)
  thisArg = (thisArg!==null && thisArg!=undefined) ? Object(thisArg) : window // 对特殊的忽略显式绑定进行处理
  thisArg.fn = fn
  // apply()时,注意传过来的数组. 没有传值时是undefined 不能被展开.
  // argArray = argArray ? argArray : []
  argArray = argArray || []
  var result = thisArg.fn(...argArray)
  delete thisArg.fn
  return result
}

function foo() {
  console.log('foo被执行', this);
}
function sum(num1, num2) {
  console.log('sum被执行', this);
  return num1 + num2
}

foo.FhApply({ name: 'Fhup' })
foo.FhApply(null) 

// 剩余的参数放在数组中
var result = sum.FhApply({ age: 18 },[1,2,3])
console.log(result)

实现bind()

Function.prototype.FhBind = function(thisArg, ...argArray){
  // 1. 获取需要调用的函数
  var fn = this

  // 2. 绑定this
  thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
  return function(...args){
    thisArg.fn = fn
    
    // 3. 将参数进行依次排列(合并)
    var finalArgs = [...argArray, ...args]
    var result = thisArg.fn(...finalArgs)
    delete thisArg.fn
    
    // 4. 返回结果
    return result
  }
  
}


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



var newSum = sum.FhBind('abc',1, 2)
var result = newSum(3, 4)
console.log(result);

// 默认bind()的三种传参方式
// var newSum = sum.bind('aaa', 10, 20, 30)
// newSum()
// var newSum = sum.bind('aaa')
// newSum(10, 20, 30)
// 两个参数依次传入
// var newSum = sum.bind('aaa', 10)
// newSum(20, 30, 40)