JavaScript關(guān)于數(shù)組的四道面試題
已知后端返回一個(gè)對(duì)象數(shù)組,格式類(lèi)似這樣:
const arr = [
{ id: 1, name: 'a', birth: 896630400000 },
{ id: 2, name: 'b', birth: 725817600000 },
...,
]
按要求寫(xiě)代碼:
- 按照 name 屬性降序排序(字母順序從大到?。?/li>
- 去除 id 屬性相同的元素(如出現(xiàn)重復(fù),后出現(xiàn)的覆蓋先出現(xiàn)的,不要求保留原始順序)
- 過(guò)濾出所有的95后(birth >= 1995年1月1日)
- 如何做前端分頁(yè)
由于公司是大數(shù)據(jù)處理業(yè)務(wù),數(shù)組相關(guān)操作使用還是挺頻繁的。這是我們公司前端JS面試題中的編程題部分。雖然都是基礎(chǔ),但是答上來(lái)的似乎不多。下面我們依次分析。
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
- 在看答案前不自己先試試么
數(shù)組排序
按照 name 屬性降序排序(字母順序從大到?。?/p>
看到排序當(dāng)然可以聯(lián)想到 Array#sort 。大家都寫(xiě)過(guò) [1, 3, 2].sort((a, b) => a - b) ,但是這個(gè)數(shù)組有點(diǎn)特殊,它是對(duì)象數(shù)組。排序規(guī)則也有些特殊:是按照字符串排序,而且是降序排序。
考點(diǎn):
Array#sort 這個(gè)這個(gè)毫無(wú)疑問(wèn)。手寫(xiě)排序算法的人會(huì)被一概刷掉。難點(diǎn)在于在 sort 的回調(diào)函數(shù)中如何比較字符串的大小。首先字符串相減是不對(duì)的,對(duì)于 'a'-'b' 這個(gè)表達(dá)式,JS 引擎會(huì)首先把字符串 'a' 和 'b' 轉(zhuǎn)換為數(shù)字,因?yàn)?JS 標(biāo)準(zhǔn)規(guī)定只有數(shù)字才能相減。于是:
+'a' // => NaN +'b' // => NaN 'a' - 'b' = NaN - NaN = NaN
有些同學(xué)會(huì)提出挨個(gè)比較字符編碼的方法,此法雖然可行,但是你要知道字符串長(zhǎng)度是不固定的,你必須判斷前一位相等后比下一位,于是不得不引入循環(huán)。這并不是面試官想要的答案。
雖然字符串不可相減,但是字符串卻可以用大于小于號(hào)比較大小,而且比較的方式就是字典序依次比較。
'a' < 'b' // true 'a' < 'a' // false 'aa' < 'ab' // true
使用比較運(yùn)算符比較字符串的問(wèn)題就是你無(wú)法一次性得到他們的準(zhǔn)確關(guān)系。如果 a < b 返回 false ,還有兩種可能,一種是 a 等于 b,另一種是 a 大于 b。所以如果使用比較運(yùn)算符,你就必須在 sort 的回調(diào)函數(shù)中判斷兩次。
arr.sort((a, b) => a.name < b.name ? 1 : a.name > b.name ? -1 : 0); // 記得是逆序
最優(yōu)方案是使用 String#localeCompare ,這個(gè)函數(shù)可以一次性返回正負(fù)零,完美適用于 Array#sort
arr.sort((a, b) => b.name.localeCompare(a.name)); // 逆序,所以 b 在 a 前面
數(shù)組去重
去除 id 屬性相同的元素(如出現(xiàn)重復(fù),后出現(xiàn)的覆蓋先出現(xiàn)的,不要求保留原始順序)
網(wǎng)上看過(guò)一些面試題的同學(xué),看到數(shù)組去重肯定馬上會(huì)聯(lián)想到 Set ,這個(gè)玩意用來(lái)做數(shù)組去重簡(jiǎn)直是帥到?jīng)]朋友
[...new Set([1, 1, 2, 3, 3, 1])] // => [1, 2, 3]
然而這道題卻不按套路出牌:它要去重的是對(duì)象數(shù)組,不是簡(jiǎn)單的數(shù)字?jǐn)?shù)組。
遇到這道題時(shí)可以按照這樣的思路來(lái):題目說(shuō)需要按照字段 id 去重,那么 id 是必需拿出來(lái)單獨(dú)處理的。但是 id 去重卻不是去 id 本身,而是去 id 所關(guān)聯(lián)的對(duì)象,那么肯定需要一個(gè) id 到對(duì)象的映射。想到映射這一層,那么很容易聯(lián)想到對(duì)象和 Map 。
考點(diǎn):
- 對(duì)象 key 的唯一性
- Map
如果使用對(duì)象,笨一點(diǎn)的話(huà)可以這樣:
const map = {};
const resultArr = [];
arr.forEach(x => {
if (!map[x]) {
map[x] = true;
resultArr.push(x);
}
}
這種寫(xiě)法不完全符合題設(shè)要求,它總會(huì)保留最先出現(xiàn)的值。如果要保留后出現(xiàn)的值,可以把數(shù)組先反轉(zhuǎn)再遍歷。
arr.concat().reverse().forEach(...) // reverse 會(huì)改變數(shù)組的值,用之前需先克隆原始數(shù)組
這里可能有同學(xué)會(huì)提到 reduceRight,這里建議如果你不能保證回調(diào)函數(shù)為純函數(shù),請(qǐng)不要使用 map 或 reduce。
另外一個(gè)方式是始終用后面的對(duì)象覆蓋前面的。
const map = {};
arr.forEach(x => {
map[x] = x;
}
const resultArr = [];
for (let key in map) {
// 嚴(yán)謹(jǐn)?shù)脑?huà),這里要用 hasOwnProperty 去除父級(jí)對(duì)象上的 key
resultArr.push(map[key]);
}
分為兩步,前一步有些類(lèi)似把數(shù)組轉(zhuǎn)換為對(duì)象,后一步就是取一個(gè)對(duì)象里的所有值。前者可以用 Object#assign 或 Object#fromEntries 代替,后者就是 Object#values 。所以簡(jiǎn)潔的寫(xiě)法是這樣:
Object.values(Object.assign(...arr.map(x => ({ [x.id]: x }))));
對(duì)象其實(shí)不是一個(gè)完美的解決方案,因?yàn)閷?duì)象的 key 都會(huì)被強(qiáng)制轉(zhuǎn)換為字符串,雖然題設(shè)中的 id 都是數(shù)字類(lèi)型,但是難保后面會(huì)出現(xiàn)字符串的數(shù)字。完美的解決方案是 Set 的同胞兄弟 Map
[...new Map(arr.map(x => [x.id, x])).values()] // 注意 Map#values 返回的不是數(shù)組而是一個(gè)迭代器,需要手工再轉(zhuǎn)為數(shù)組
數(shù)組過(guò)濾
過(guò)濾出所有的95后(birth >= 1995年1月1日)
考點(diǎn):
此題明顯比前面兩題簡(jiǎn)單不少,但此題卻很少有人完全答對(duì),問(wèn)題就出在日期對(duì)象的使用上
我在之前的博文 說(shuō)過(guò) Date 對(duì)象的坑:當(dāng)你使用數(shù)字年月日構(gòu)造 Date 對(duì)象時(shí)記得月份是從 0 開(kāi)始的;當(dāng)你使用字符串構(gòu)造 Date 對(duì)象時(shí)請(qǐng)使用斜杠( / )避免出現(xiàn)時(shí)區(qū)問(wèn)題。
arr.filter(x => x.birth >= new Date(1995, 0, 1);
前端分頁(yè)
如何做前端分頁(yè)
考點(diǎn):
- Array#slice
- 分頁(yè)的基本概念
所謂“分頁(yè)”就是從數(shù)組中截取要顯示的部分放到頁(yè)面上顯示,截取就是 slice,但似乎好多人把 slice 和 splice 搞混。
slice 是截取數(shù)組的一部分,但不改變?cè)瓟?shù)組,兩個(gè)參數(shù)都是下標(biāo)。splice 雖然也可以作為截取數(shù)組使用,但 splice 會(huì)改變?cè)瓟?shù)組,而且 splice 要求的第二個(gè)參數(shù)是截取項(xiàng)的長(zhǎng)度。slice 就是截取數(shù)組,而 splice 通常用作數(shù)組中部的插入刪除操作。
slice 和 s p lice,中間差了一個(gè)字母 p ,用法含義大不相同。
const from = (頁(yè)碼 - 1) * 每頁(yè)條數(shù); arr.slice(from, from + 每頁(yè)條數(shù));
完
數(shù)組對(duì)象有很多的原生方法 ,數(shù)組操作是 JS 數(shù)據(jù)操作中最常用的操作,經(jīng)常溫習(xí)一下沒(méi)錯(cuò)的。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
新手怎么學(xué)JS?JavaScript基礎(chǔ)語(yǔ)法入門(mén)要學(xué)什么?
這篇文章主要介紹了新手怎么學(xué)JS?JavaScript基礎(chǔ)語(yǔ)法入門(mén)要學(xué)什么?本文給大家介紹一個(gè)大致的學(xué)習(xí)路線(xiàn)和方向,需要的朋友趕緊一起來(lái)看看吧2020-03-19
這篇文章主要介紹了javascript作用域,作用域鏈,閉包的面試題,在一些前端面試中經(jīng)常會(huì)問(wèn)題,今天小編特此整理分享到腳本之家平臺(tái),需要的朋友可以參考下2020-02-212020年12道高頻JavaScript手寫(xiě)面試題及答案
這篇文章主要介紹了2020年12道高頻JavaScript手寫(xiě)面試題及答案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編2020-01-06
11道JS選擇題(聽(tīng)說(shuō)第一題就難倒80%的人)
這篇文章主要介紹了11道JS選擇題(聽(tīng)說(shuō)第一題就難倒80%的人),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-12-18
JS 初學(xué)者總是對(duì)this關(guān)鍵字感到困惑,因?yàn)榕c其他現(xiàn)代編程語(yǔ)言相比,JS 中的這this關(guān)鍵字有點(diǎn)棘手。今天小編給大家?guī)?lái)10個(gè)比較流行的JavaScript面試題 ,感興趣的朋友一起2019-07-12- 這篇文章主要介紹了10個(gè)JavaScript筆試題解析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2020-06-02




