1. 程式人生 > >手寫系列:call、apply、bind、函式柯里化

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

少廢話,show my code ## call 原理都在註釋裡了 ```js // 不覆蓋原生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就是函式本身,給context增加一個名為[key]的方法指向this,就能用context來呼叫this了 context[key] = this; const result = _this[key](...params); // 獲取函式執行結果後,刪除以上新增的屬性 delete context[key]; return result; }; ``` ## apply 和call的區別在於第二個引數 ```js Function.prototype.myApply = function (context, params) { return this.myCall(context, ...params); }; ``` ## bind 和call的區別在於不立即執行,返回一個函式即可 ```js Function.prototype.myBind = function (context, ...params) { const _this = this; // 返回的函式也能接收引數,但是是放在params後面 return function (...args) { return _this.myCall(context, ...[...params, ...args]); }; }; ``` ## 函式柯里化 函式柯里化,舉例,有如下函式 ```js function test(a, b, c, d, e) { console.log(a + b + c + d + e); } ``` 有一個curry轉換函式對test函式進行一些轉換 ```js function curry(){ // todo } const transformTest = curry(test, ...args) ``` 轉換之後,原本一次性傳過去的引數現在可以分步傳參 ```js // 使得 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函式應該怎麼寫? ```js 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、函式柯里化](https://github.com/wangmeijian/blog/i