前往->個(gè)人博客可獲得更好的閱讀體驗(yàn)~
題目
編寫一個(gè)方法sum,使sum(1,2,3) 和 sum(1,2)(3)的輸出都為6
感謝前人指路——詳解JS函數(shù)柯里化
前言
這道題目考的是函數(shù)柯里化的概念
柯里化节猿,英語:Currying(果然是滿滿的英譯中的既視感)抵蚊,是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù)凉袱,并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。
看概念檩帐,云里霧里茫虽,上例子!
// 普通的add函數(shù)
function add(x, y) {
return x + y
}
// Currying后
function curryingAdd(x) {
return function (y) {
return x + y
}
}
add(1, 2) // 3
curryingAdd(1)(2) // 3
看了例子施籍,主要概念就是讓函數(shù)返回一個(gè)function可以接受第二個(gè)(或者更多)括號(hào)里的參數(shù)并輸出期望值。
思考
針對(duì)這個(gè)題目概漱,需要做的是:
1丑慎、利用閉包創(chuàng)建一個(gè)數(shù)組保存參數(shù)
2、返回一個(gè)方法瓤摧,用于接收下一個(gè)括號(hào)里的參數(shù)
3竿裂、全部接收后,返回所有參數(shù)的和
代碼
限定參數(shù)數(shù)量
如果僅僅針對(duì)題目照弥,我們得到下面的代碼
// 固定數(shù)量參數(shù)
function constSum() {
// 因?yàn)榫腿齻€(gè)參數(shù)腻异,直接用計(jì)數(shù)器,定義數(shù)組添加參數(shù)这揣,判斷數(shù)組長度也可以
(this.counter = 0), (this.sumNum = 0);
let that = this;
// ...rest是ES6中參數(shù)解構(gòu)的寫法悔常,函數(shù)中的rest為數(shù)組
return function innerSum(...rest) {
rest.forEach((item) => {
that.counter++;
that.sumNum += item;
});
// 判斷
if (that.counter === 3) {
return that.sumNum;
} else {
return innerSum;
}
};
}
let sum = new constSum();
var result = sum(1, 2)(3);
var result2= sum(1, 2, 3);
console.log(result); // 6
console.log(resul2); // 6
這樣可以實(shí)現(xiàn)題目中的效果影斑,但是并不好,因?yàn)橄薅ㄋ?個(gè)參數(shù)机打,如果我們希望擁有更靈活通用的方法呢矫户?
比如可以支持sum(1,2,3)(4)(5)......
不限定參數(shù)數(shù)量
// 不限數(shù)量參數(shù)
function sum(...rest) {
// 第一次執(zhí)行時(shí),定義一個(gè)數(shù)組專門用來存儲(chǔ)所有的參數(shù)
var _args = Array.prototype.slice.call(arguments);
// 在內(nèi)部聲明一個(gè)函數(shù)姐帚,利用閉包的特性保存_args并收集所有的參數(shù)值
var _adder = function() {
_args.push(...arguments);
return _adder;
};
// 利用toString隱式轉(zhuǎn)換的特性吏垮,當(dāng)最后執(zhí)行時(shí)隱式轉(zhuǎn)換障涯,并計(jì)算最終的值返回
_adder.toString = function () {
let sum = _args.reduce(function (a, b) {
return a + b;
});
return sum
}
return _adder;
}
console.log(sum(1)(2)(3)) // 6
console.log(sum(1, 2, 3)(4)) // 10
console.log(sum(1)(2)(3)(4)(5)) // 15
以上可以實(shí)現(xiàn)不限定參數(shù)數(shù)量的sum函數(shù)罐旗。
其中Array.prototype.slice.call
和toString隱式轉(zhuǎn)換
其實(shí)都是js基礎(chǔ)知識(shí)點(diǎn),具體可以另開兩篇文章唯蝶。
但是這里先明白其功能——
一個(gè)是將參數(shù)轉(zhuǎn)換為數(shù)組九秀。
一個(gè)是在返回最后一次執(zhí)行結(jié)束后,return了一個(gè)_adder方法粘我,在輸出時(shí)鼓蜒,正常會(huì)隱式調(diào)用
Function.toString的方法,以字符方式輸出方法征字。因?yàn)樯厦娓膶懥薩adder的toString方法都弹,所以最后沒有以字符方式輸出方法
,而是隱式調(diào)用了我們改寫的輸出了所有參數(shù)的和
的toString方法匙姜。
這樣的方法在chrome可以輸出f 6
這樣的數(shù)字畅厢,但如果輸出一下這個(gè)結(jié)果的類型比如——
// ...上略
console.log(typeof sum(1)(2)(3)) // function
我們會(huì)得到這個(gè)結(jié)果的類型其實(shí)還是function。所以這個(gè)方法其實(shí)是很勉強(qiáng)的實(shí)現(xiàn)了題目的效果氮昧,但得到的數(shù)據(jù)不能直接作為Number來使用框杜。
還是需要顯示調(diào)用
才能得到number類型的結(jié)果——
// ...上略
let sumToNumber = Number.parseInt(sum(1)(2)(3))
console.log(sumToNumber) // 6
console.log(typeof sumToNumber) // number
擴(kuò)展
ES6改寫
使用ES6的不定參數(shù)rest的新特性,該特性可以讓不定參數(shù)
變成一個(gè)數(shù)組
傳入袖肥,不需要訪問arguments
咪辱,也省去了使用Array.prototype.slice.call(arguments);
生成數(shù)組,更加優(yōu)雅椎组。
function sumWithES6(...rest) {
var _args = rest;
var _adder = function (...innerRest) {
_args.push(...innerRest); // 這里使用的是ES6數(shù)組的解構(gòu)
return _adder;
};
_adder.toString = function () {
let sum = _args.reduce(function (a, b) {
return a + b;
});
return sum;
};
return _adder;
}
console.log(sumWithES6(1)(2)(3)); // 6