JavaScript??际謱戭}之柯里化與數(shù)組扁平化的實現(xiàn)
以下題目來自其它博客,但是問題的答案都是根據(jù)筆者自己的理解做出的。如果你最近想要換工作或者鞏固一下自己的前端知識基礎(chǔ),不妨和我一起參與到每日刷題的過程中來,如何?
第四天要刷的手寫題如下:
- 手寫一個函數(shù),實現(xiàn)柯里化功能
- 手寫一個函數(shù),實現(xiàn)數(shù)組扁平化的功能
- 手寫一個函數(shù),實現(xiàn)數(shù)組去重的功能
下面是我自己寫的答案:
1. 手寫一個函數(shù),實現(xiàn)柯里化功能
分析: 柯里化的本質(zhì)是**收集到一定數(shù)量的參數(shù)(稱為生產(chǎn)資料更為合適)**之后才去執(zhí)行既定的函數(shù),如果參數(shù)的數(shù)目小于既定函數(shù)執(zhí)行所需要的個數(shù)則不執(zhí)行,而是繼續(xù)收集參數(shù)。
如果用代碼來表示,可以設(shè)既定函數(shù)為f
,柯里化之后映射成為函數(shù)g
,g在執(zhí)行的時候會對積累到的參數(shù)的數(shù)目進行判斷,如果數(shù)目是足夠的,則返回f的執(zhí)行結(jié)果(相當于執(zhí)行了f),如果參數(shù)的數(shù)目不夠,則將此次調(diào)用傳入的參數(shù)累積起來,然后返回函數(shù)g'
,等待下一次調(diào)用。**返回的g'
函數(shù)和g
具有相同的德行。
根據(jù)上面的分析,首先需要一個私有域存儲已經(jīng)收集到了的參數(shù),這就需要用到閉包了;而執(zhí)行既定函數(shù)的參數(shù)數(shù)目可以直接從既定函數(shù)上獲?。?code>f.length表示函數(shù)需要的形參數(shù)目。
現(xiàn)在嘗試性的寫一下:
function _G (f) { if(typeof f !== "function") throw new Error('f must be a function!'); return function (...rest) { const currentParams = [...rest]; const currentLength = currentParams.length; if(currentLength >= f.length) return f.apply(this, currentParams); // return _G(f); ??? } }
這里無法處理參數(shù)不夠的時候如何返回一個g'
的問題。上面分析到g'
和g
性質(zhì)相同,所以g'
和g
都是由_G
產(chǎn)生的,所以問題出在_G
沒有設(shè)計好,一個參數(shù)根本無法區(qū)分g'
和g
。
于是,需要增加一個形參,表示目前g
類已經(jīng)收集到的參數(shù):
function _G (f, alreadyCollectedParams = []) { if(typeof f !== "function") throw new Error('f must be a function!'); return function (...rest) { const currentParams = [...alreadyCollectedParams, ...rest]; const currentLength = currentParams.length; if(currentLength >= f.length) return f.apply(this, currentParams); return _G(f, currentParams); } } function add (a,b,c) { return a+b+c; } const c_add = _G(add); console.log(c_add(1)(2)(3)); // 6 console.log(c_add(1, 2)(3)); // 6 console.log(c_add(1)(2, 3)); // 6 console.log(c_add(1, 2, 3)); // 6
使用ES6創(chuàng)建極簡版:
// 極簡版 // const __G = (f, alreadyCollectedParams = []) => (...rest) => [...alreadyCollectedParams, ...rest].length >= f.length ? f.apply(this, [...alreadyCollectedParams, ...rest]) : _G(f, currentParams); const __G = (f, a = []) => (...r) => (_ = [...a, ...r], _.length >= f.length ? f.apply(this, _) : __G(f, _));
2. 手寫一個函數(shù),實現(xiàn)數(shù)組扁平化的功能
所謂數(shù)組扁平化指的就是如果數(shù)組中的元素依然是數(shù)組,則將內(nèi)嵌數(shù)組中的元素拿出來直接放到上層數(shù)組中即可。
2.1 方法一:forEach 和 push
一個最基本的想法就是,創(chuàng)建一個_flat方法用來遍歷這個數(shù)組,然后再在歷過程中對數(shù)組中的每一個元素進行判斷;如果元素的類型不是數(shù)組則直接push到記錄數(shù)組中去,如果元素的類型是數(shù)組,則對此內(nèi)嵌數(shù)組遞歸調(diào)用_flat; 這樣相當于對任何一級的數(shù)組的每一個元素都進行了遍歷,也就是使用深度遍歷算法。
function _flat (targetArray, container = []) { if(!Array.isArray(targetArray)) return container; targetArray.forEach( item => { if (!Array.isArray(item)) { container.push(item); } else { _flat(item, container); } } ) return container; } const rst = _flat([[[[[[1],2],3],4],5,6],7]); // const rst = _flat('[[[[[[1],2],3],4],5,6],7]'); console.log('rst: ', rst);
2.2 方法二: Array.prototype.flat
ES6中Array的原型上增加了一個名為flat的方法,其作用就是將嵌套數(shù)組拆包一次;顯然沒拆一次,整個數(shù)組的元素數(shù)目是(非嚴格)單調(diào)遞增的;根據(jù)這個性質(zhì),使用while循環(huán)一直對其拆包,直到某兩次拆完之后元素數(shù)目相等.
function _flat2 (targetArray) { if(!Array.isArray(targetArray)) return []; let _loop = targetArray; while(1){ const beforeFlat = _loop.length; const _Arr = _loop.flat(); const afterFlat = _Arr.length; if(beforeFlat == afterFlat) return _Arr; _loop = _Arr; } } const rst2 = _flat2([[[[[[1],2],3],4],5,6],7]); console.log('rst2: ', rst2);
2.3 方法三: findIndex 和 splice
如果在遍歷之前就知道為內(nèi)嵌數(shù)組元素的序列號就好了,這樣只需要到對應(yīng)的位置上找到并將其展開就可以了;這個過程一直持續(xù)到原數(shù)組中再也找不到內(nèi)嵌數(shù)組元素就停止下來。 這種方法是在原來的數(shù)組上直接操作的,會改變原數(shù)組的內(nèi)容
function _flat3 (targetArray) { if(!Array.isArray(targetArray)) return []; while(1){ const arrItemIndex = targetArray.findIndex( item => Array.isArray(item) ) if(arrItemIndex === -1) return targetArray; targetArray.splice(arrItemIndex, 1, ...targetArray[arrItemIndex]); } } const rst3 = _flat3([[[[[[1],2],3],4],5,6],7]); console.log('rst3: ', rst3);
2.4 方法四: stack
- 使用棧這種數(shù)據(jù)結(jié)果,其本質(zhì)上和遞歸的算法是完全相同的;但是使用棧來理解的話,會極大的減小心智負擔
- 使用兩個棧a和b,開始的時候?qū)⒃紨?shù)組整體放入到a棧中去,此時b棧為空;
- 然后對a棧執(zhí)行下面的動作,直到a棧為空:
- 彈棧->判斷彈出元素是否是數(shù)組,如果不是,則進入棧b,如果是則拆包一次,再重新進入棧a
- 最后輸出棧b即可
function _flat4 (targetArray) { if(!Array.isArray(targetArray)) return []; // 原始數(shù)組全部入a棧 const a = [...targetArray]; const b = []; while(a.length){ const _tmp = a.pop(); if (Array.isArray(_tmp)) { a.push(..._tmp); // 這里不要遍歷push,顯得很low,a.concat(_tmp)也可 } else { b.push(_tmp); } } return b; } const rst4 = _flat4([[[[[[1],2],3],4],5,6],7]); console.log('rst4: ', rst4);
3. 手寫一個函數(shù),實現(xiàn)數(shù)組去重的功能
就是字面意思,不難理解!
3.1 利用set對象的機制,將數(shù)組先變成set然后將set再變成數(shù)組
// 一行搞定 const unique = (array) => [...newSet(array)];
3.2 繼續(xù)使用兩個棧
- 繼續(xù)使用兩個棧a和b,a執(zhí)行下面的動作直到空棧
- 彈棧->判斷彈出元素在b棧中是否存在,如果存在丟棄,如果不存在進入棧b
const unique2 = (array) => { if(!Array.isArray(array)) return []; const a = [...array]; const b = []; while(a.length){ const item = a.pop(); // const item = a.shift(); if(b.includes(item)) continue; b.push(item); } return b; }
可以將pop改成shift有利于保證順序
3.3 3.2改進版本
對上面的實現(xiàn)方式進行優(yōu)化,因為數(shù)組通過內(nèi)容查詢元素的效率實在是太低了,所以將b從棧改成字典,字典一般是使用hash表實現(xiàn)的,在根據(jù)查找方面比數(shù)組要快
const unique3 = (array) => { if(!Array.isArray(array)) return []; const a = [...array]; const b = new Map(); while(a.length){ const item = a.pop(); // const item = a.shift(); b.set(item,1); } return [...b.keys()]; } console.log(unique3([1,1,1,1,2,3,4,345,345]));
到此這篇關(guān)于JavaScript常考手寫題之柯里化與數(shù)組扁平化的實現(xiàn)的文章就介紹到這了,更多相關(guān)JavaScript手寫題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
分離式j(luò)avascript取當前element值的代碼
比較不錯的分離式j(luò)s代碼,獲取element的值,大家注意下,運行后的效果是32之類的值,其實主要是沒有強制轉(zhuǎn)換成數(shù)字,所以大家可以加上2008-05-05JavaScript?對象新增方法defineProperty與keys的使用說明
這篇文章主要介紹了JavaScript對象新增方法defineProperty與keys的使用說明,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-09-09javascript中的try catch異常捕獲機制用法分析
這篇文章主要介紹了javascript中的try catch異常捕獲機制,簡單分析了try catch異常捕獲機制的基本定義與使用方法,需要的朋友可以參考下2016-12-12javascript字母大小寫轉(zhuǎn)換的4個函數(shù)詳解
這篇文章主要介紹了javascript字母大小寫轉(zhuǎn)換的4個函數(shù)詳解,需要的朋友可以參考下2014-05-05微信小程序數(shù)據(jù)分析之自定義分析的實現(xiàn)
這篇文章主要介紹了微信小程序數(shù)據(jù)分析之自定義分析的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08html的DOM中document對象anchors集合用法實例
這篇文章主要介紹了html的DOM中document對象anchors集合用法,實例分析了anchors集合的功能及使用技巧,需要的朋友可以參考下2015-01-01