最近學弟去面了字節跳動,可是因爲面試經驗少,面試的時候緊張了,一時之間沒有寫出來,以後來我交流了一下。那我就來分析分析這道題目。javascript
這題的規則是這樣的java
給定有一個 Add 函數,要支持如下形式的調用面試
Add(1)(2)(3).sumOf(); // 輸出 6 Add(1,2)(3)(4).sumOf(); // 輸出 10 Add(1,2,...)(3)(4)(...).sumOf(); // ...
拿到這種題目,我先來講說我本身的作題流程,通常會去找它最簡單的形態。咱們一步一步來拆解。segmentfault
先去掉 sumOf()
變成了如下形態數組
Add(1,2,...)(3)(4)(...)
嗯....有點熟悉...可是仍是有點複雜,那咱們再去掉無限調用這個限制。微信
Add(1,2,...)(3)(4)
唔,仍是有點難呀...不要緊,再砍, 不要傳入多個參數。閉包
Add(1)(2)(3)
有....有....有那味了....這....這不就是柯里化嗎....函數
有些小朋友可能沒有聽過,對於大朋友而言耳熟能詳,融會貫通。spa
咱們仍是來介紹一下。設計
在《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); } } } // 若是我上述代碼中間換成箭頭函數又會怎麼樣呢~
也許你以爲這題有點簡單,經過簡單的重複練習就能輕鬆記住,可是最主要的是思路,不少事情都是同樣,掌握事情的方法和方向是最重要的。畢竟淘寶也不是一蹴而就的~ 可是隻要方向正確了,都會好起來的。
若是個人文章有幫助到你,但願你也能幫助我,歡迎關注個人微信公衆號 秋風的筆記
,回覆好友
二次,可加微信而且加入交流羣,秋風的筆記
將一直陪伴你的左右。