手寫系列:call、apply、bind、函數柯里化

少廢話,show my codegit

call

原理都在註釋裏了github

// 不覆蓋原生call方法,起個別名叫myCall,接收this上下文context和參數params
Function.prototype.myCall = function (context, ...params) {
  // context必須是個對象而且不能爲null,默認爲window
  const _this = typeof context === "object" ? context || window : window;
  // 爲了不和原有屬性衝突,定義一個Symbol類型的屬性
  const key = Symbol();
  // call方法的目的是改變函數的this指向,函數的this指向它的調用者,也就是說咱們的目標是改變函數的調用者。
  // 下面的this就是函數自己,給_this增長一個名爲[key]的方法指向this,就能用_this來調用this了
  _this[key] = this;
  const result = _this[key](...params);
  // 獲取函數執行結果後,刪除以上添加的屬性
  delete _this[key];
  return result;
};

apply

和call的區別在於第二個參數app

Function.prototype.myApply = function (context, params) {
  return this.myCall(context, ...params);
};

bind

和call的區別在於不當即執行,返回一個函數便可函數

Function.prototype.myBind = function (context, ...params) {
  const _this = this;
  // 返回的函數也能接收參數,可是是放在params後面
  return function (...args) {
    return _this.myCall(context, ...[...params, ...args]);
  };
};

函數柯里化

函數柯里化,舉例,有以下函數this

function test(a, b, c, d, e) {
  console.log(a + b + c + d + e);
}

有一個curry轉換函數對test函數進行一些轉換prototype

function curry(){
  // todo
}
const transformTest = curry(test, ...args)

轉換以後,本來一次性傳過去的參數如今能夠分步傳參code

// 使得
test(1,2,3,4,5)
// 等同於
transformTest(1)(2)(3)(4)(5)
// 或者
transformTest(1, 2)(3)(4, 5)
// 又或者
transformTest(1, 2, 3, 4)(5)

curry函數應該怎麼寫?orm

function curry(fn, ...args) {
  // 判斷參數個數是否是等於原函數參數個數
  // 若是是,直接返回調用結果
  if ([...args].length >= fn.length) {
    return fn(...args);
  } else {
    // 若是不是,則返回一個函數
    return (...params) => {
      // 將前面傳的所有參數傳給curry,回到第一步的if判斷,直到參數個數知足要求
      return curry(fn, ...args, ...params);
    };
  }
}

本文GitHub連接:手寫系列:call、apply、bind、函數柯里化對象

相關文章
相關標籤/搜索