手寫系列:call、apply、bind、函式柯里化
阿新 • • 發佈:2021-01-01
少廢話,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