前言
最近學弟去面了字節跳動,但是由於面試經驗少,面試的時候緊張了,一時之間沒有寫出來,之後來我交流了一下。那我就來分析分析這道題目。
正文
這題的規則是這樣的
給定有一個 Add 函數,要支持以下形式的調用
Add(1)(2)(3).sumOf(); // 輸出 6
Add(1,2)(3)(4).sumOf(); // 輸出 10
Add(1,2,...)(3)(4)(...).sumOf(); // ...
拿到這種題目,我先來説説我自己的做題流程,一般會去找它最簡單的形態。我們一步一步來拆解。
先去掉 sumOf() 變成了以下形態
Add(1,2,...)(3)(4)(...)
嗯....有點熟悉...但是還是有點複雜,那我們再去掉無限調用這個限制。
Add(1,2,...)(3)(4)
唔,還是有點難呀...沒關係,再砍, 不要傳入多個參數。
Add(1)(2)(3)
有....有....有那味了....這....這不就是柯里化嗎....
有些小朋友可能沒有聽過,對於大朋友而言耳熟能詳,融會貫通。
我們還是來介紹一下。
在《javascript高級程序設計》這本書中有如下介紹:
與函數綁定緊密相關的主題是函數柯里化,它用於創建已經設置好的一個或者多個參數的函數。函數柯里化的基本方法和函數綁定是一樣的:使用一個閉包返回一個函數。兩者的區別在於,當函數被調用時,返回的函數還需要設置一些傳入的參數。
我們來寫寫看:
function Add(x) {
return function (y) {
return return functio (z) {
return x + y + z;
}
}
}
// 簡潔寫法
const Add = x => y => z => x+y+z;
執行一下
Add(1)(2)(3) // 6
是我們要的那味~
那麼我們既然已經寫出了這個形態,我們就一步一步反推。
這個時候千萬別緊張,我們從最低級的形態出發,寫出一個最基本的形態,能夠有效地幫助我們建立自信心,吃下定心丸,按照這種方式,哪怕我們最終沒有寫出完美的結果,讓面試官看到你思考解題的過程,也是一種加分。
好,接着説~
那我們接下來需要實現這個樣子。
Add(1,2,...)(3)(4)
傳入參數不止一個
我們知道,對於不確定參數個數,我們可以使用 arguments 這個對象來獲取到所有的入參,但是 arguments 不是一個 Array,但是我們可以使用 ES6 中的 Spread syntax (展開語法)去將他變成一個數組。表演繼續。
function Add() {
const nums = [...arguments];
return function() {
nums.push(...arguments);
return function() {
nums.push(...arguments);
return nums.reduce((a, b) => a + b);
}
}
}
nice!已經離我們最終的形態越來越近了。接下來是這個函數能夠無限的進行調用。
Add(1,2,...)(3)(4)(...)
那麼怎麼樣才能無限調用呢?沒錯,用遞歸。
function Add() {
const nums = [...arguments];
function AddPro() {
nums.push(...arguments);
return AddPro;
}
return AddPro;
}
嗯,其實我們寫到這裏發現了... 由於是無限遞歸,我們沒辦法確定最後一次函數調用,因此我們需要最後顯式調用一個結束的方法來打印出最後的數據。
很自然地,我們可以在 AddPro 添加一個方法 sumOf 來解決這個問題。
學弟就是卡在這裏地方,被函數添加上一個方法搞懵了。你是否知道呢?
function Add() {
const nums = [...arguments];
function AddPro() {
nums.push(...arguments);
return AddPro;
}
AddPro.sumOf = () => {
return nums.reduce((a, b) => a + b);
}
return AddPro;
}
好啦好啦,結束啦。
等等
在最後,我再來補充一種方案,function 不僅可以繼續掛載 function ~ 還可以掛載變量哦~
function Add() {
if (!Add.nums) {
Add.nums = [];
}
Add.nums.push(...arguments);
return Add;
}
Add.sumOf = () => {
return Add.nums.reduce((a, b) => a + b);
}
如果上述回答有更優解,請公眾號後台回覆,留下你的微信,紅包相送。
我們總結一下,小小的面試題涉及到的基礎知識。
閉包、遞歸、作用域、函數與對象
基礎就是基礎,永遠是你爸爸,掌握好基礎,以不變應萬變。
一個彩蛋
function Add() {
const nums = [...arguments];
return () => {
nums.push(...arguments);
return () => {
nums.push(...arguments);
return nums.reduce((a, b) => a + b);
}
}
}
// 如果我上述代碼中間換成箭頭函數又會怎麼樣呢~
後記
也許你覺得這題有點簡單,通過簡單的重複練習就能輕鬆記住,但是最主要的是思路,很多事情都是一樣,掌握事情的方法和方向是最重要的。畢竟淘寶也不是一蹴而就的~ 但是隻要方向正確了,都會好起來的。
最後
如果我的文章有幫助到你,希望你也能幫助我,歡迎關注我的微信公眾號 秋風的筆記,回覆好友 二次,可加微信並且加入交流羣,秋風的筆記 將一直陪伴你的左右。