14 個快速簡潔的單行 JavaScript 代碼解決方案

英文 | https://javascript.plainenglish.io/javascript-one-liners-3fe0b0155311
const sum = (a, b) => { const s1 = a * a; const s2 = b * b; return s1 + s2; }你會稱之為單行代碼嗎?在大多數(shù)情況下,這只會作為格式錯誤的代碼通過。Prettier 之類的工具可以輕松地將這三個語句自動拆分為多行。
獲得兩個平方和的真正單行方法是這樣的:
const sum = (a, b) => a * a + b * b;一個簡短、簡潔的陳述可以同樣清晰地完成同樣的工作。
另一方面,此方法跨越多行代碼以提高可讀性,但它仍然可以作為一行代碼通過:
const capitalizeWithoutSpaces = (str) =>str.split('').filter((char) => char.trim()).map((char) => char.toUpperCase()).join('');
因此,盡管名稱如此,“單行”并不一定意味著是一行代碼。
2). “……特定的編程語言……”
這與每個高級語言程序在執(zhí)行前都必須翻譯成低級語言這一事實有關。一個非常簡單的程序最終可能會占用數(shù)十或數(shù)百行匯編代碼和機器代碼。
例如,這里是另一個也添加兩個平方和的單行代碼,這次是在 C++ 中:
int sum(int a, int b) {return a * a + b * b;}
讓我們看看編譯成匯編語言后的樣子:
int):push rbpmov rbp, rspmov DWORD PTR [rbp-4], edimov DWORD PTR [rbp-8], esimov eax, DWORD PTR [rbp-4]imul eax, eaxmov edx, eaxmov eax, DWORD PTR [rbp-8]imul eax, eaxadd eax, edxpop rbpret
這個匯編程序顯然不止一行或一行代碼。 想象一下等效的機器語言程序會有多少。 所以這個函數(shù)可以說是僅在 C++ 上下文中的單行函數(shù)。
3). “……沒有任何第三方實用程序”
對于單行代碼,它不應該引用編程語言本身不可用的任何方法或函數(shù),記住我們之前看過的單行代碼:
const capitalizeWithoutSpaces = (str) =>str.split('').filter((char) => char.trim()).map((char) => char.toUpperCase()).join('');
這里使用的所有方法都是內置的 JavaScript 方法。 它不包括來自 NPM 或其他地方的第三方代碼。
但是,如果我們決定實現(xiàn)自己的 filter() 方法來替換 Array filter(),則該方法將不再符合單行方法的條件。
// Not a one-linerconst capitalizeWithoutSpaces = (str) =>filter(str.split(''), (char) => char.trim()).map((char) => char.toUpperCase()).join('');function filter(arr, callback) {// Look at all these linesconst result = [];for (const item of arr) {if (callback(item)) {result.push(item);}}return result;}
拋開定義,現(xiàn)在讓我們看一些聰明的 JavaScript 單行代碼以及它們解決方案。
1. 獲取數(shù)組的最小元素
要獲得數(shù)組中的最小項,我們可以采用這種使用 for 循環(huán)和 if 語句的命令式方法。
const getSmallest = (arr) => {let smallest = Number.POSITIVE_INFINITY;for (const num of arr) {if (num < smallest) {smallest = num;}}return smallest;};const arr = [13, 7, 11, 3, 9, 15, 17];console.log(getSmallest(arr)); // 3
這沒關系,但有一個簡潔且聲明性的單行替代方案同樣有效:
const getSmallest = (arr) =>arr.reduce((smallest, num) => Math.min(smallest, num));const arr = [13, 7, 11, 3, 9, 15, 17];console.log(getSmallest(arr)); // 3
2. 獲取數(shù)組的最大元素
這是獲取數(shù)組中最大元素的可接受方法。
const getLargest = (arr) => {let largest = Number.NEGATIVE_INFINITY;for (const num of arr) {if (num > largest) {largest = num;}}return largest;};const arr = [13, 7, 11, 3, 9, 15, 17];console.log(getLargest(arr)); // 17
但就像我們看到的獲取最小數(shù)組元素一樣,有一種更短、更簡潔的方法。
const getLargest = (arr) =>arr.reduce((largest, num) => Math.max(largest, num));const arr = [13, 7, 11, 3, 9, 15, 17];console.log(getLargest(arr)); // 17
您可以看到,此函數(shù)與單行 getSmallest() 函數(shù)之間的唯一區(qū)別是 Math.min() 已替換為 Math.max()。
3. 打亂數(shù)組
數(shù)組/列表洗牌的一個常見用途是在紙牌游戲中,其中牌組中的牌必須隨機排序。
Fisher-Yates 洗牌是一種著名的洗牌算法。 查看它在 JavaScript 中的可能實現(xiàn):
const shuffleArray = (arr) => {for (let i = arr.length - 1; i > 0; i--) {const j = Math.floor(Math.random() * (i + 1));let temp = arr[i];arr[i] = arr[j];arr[j] = temp;}return arr;};const arr = [1, 2, 3, 4, 5];shuffleArray(arr);// [ 2, 3, 5, 1, 4 ] (varies)console.log(arr);
用一些函數(shù)式編程魔法重構它,我們有:
const shuffleArray = (arr) =>[...Array(arr.length)].map((_, i) => Math.floor(Math.random() * (i + 1))).reduce((shuffled, r, i) =>shuffled.map((num, j) =>j === i ? shuffled[r] : j === r ? shuffled[i] : num),arr);// [ 2, 4, 1, 3, 5 ] (varies)console.log(shuffleArray([1, 2, 3, 4, 5]));
這以 O(n2) 時間復雜度(二次)運行,并且可能會導致大型數(shù)組出現(xiàn)性能問題,但它是一種優(yōu)雅的解決方案。 此外,與第一種方法不同,它不會改變原始數(shù)組。
另一種函數(shù)式方法利用 Array sort() 方法的實現(xiàn)方式來隨機排列數(shù)組。
const shuffleArray = (arr) => arr.sort(() => Math.random() - 0.5);const arr = [1, 2, 3, 4, 5];// [ 5, 2, 4, 1, 3 ] (varies)console.log(shuffleArray(arr));
由于它使用了 sort(),因此,它的運行時間復雜度為 O(n log n),并且比前面的方法具有更好的性能。
4. 按對象屬性對數(shù)組進行分組
有時我們需要使用它們都具有的特定屬性對一組對象進行分組,例如,按國家/地區(qū)對用戶進行分組,按出版年份對書籍進行分組,按顏色對汽車進行分組等。
在下面的示例中,我們根據(jù)姓名的長度將人物對象分組到一個數(shù)組中。
const groupBy = (arr, groupFn) => {const grouped = {};for (const obj of arr) {const groupName = groupFn(obj);if (!grouped[groupName]) {grouped[groupName] = [];}grouped[groupName].push(obj);}return grouped;};const people = [{ name: 'Matt' },{ name: 'Sam' },{ name: 'John' },{ name: 'Mac' },];const groupedByNameLength = groupBy(people, (person) => person.name.length);/**{'3': [ { name: 'Sam' }, { name: 'Mac' } ],'4': [ { name: 'Matt' }, { name: 'John' } ]}*/console.log(groupedByNameLength);
這是單行代碼的解決方案:
const groupBy = (arr, groupFn) =>arr.reduce((grouped, obj) => ({...grouped,[groupFn(obj)]: [...(grouped[groupFn(obj)] || []), obj],}),{});const people = [{ name: 'Matt' },{ name: 'Sam' },{ name: 'John' },{ name: 'Mac' },];const groupedByNameLength = groupBy(people, (person) => person.name.length);/**{'3': [ { name: 'Sam' }, { name: 'Mac' } ],'4': [ { name: 'Matt' }, { name: 'John' } ]}*/console.log(groupedByNameLength);
5.反轉字符串
我們可以在 JavaScript 中使用反向 for 循環(huán)來反轉字符串,如下所示:
const reverseString = (str) => {let reversed = '';for (let i = str.length - 1; i >= 0; i--) {const ch = str[i];reversed += ch;}return reversed;};const reverse = reverseString('javascript');console.log(reverse); // tpircsavaj
但是再一次,我們可以利用強大的內置數(shù)組方法,如 reverse() 和 join() 來創(chuàng)建一個做同樣事情的單行代碼。
const reverseString = (str) => str.split('').reverse().join('');const reverse = reverseString('javascript');console.log(reverse); // tpircsavaj
6. 生成隨機的十六進制顏色
十六進制顏色代碼是指定 RGB 顏色的一種方式。 它們具有#RRGGBB 格式,其中 RR 代表紅色,GG 代表綠色,BB 代表藍色。 每種顏色的值范圍從 0 到 255,并以十六進制格式表示 - 0 到 FF。
這個單行生成一個隨機的十六進制顏色并返回結果。
const randomHexColor = () =>`#${Math.random().toString(16).slice(2, 8).padEnd(6, '0')}`;console.log(randomHexColor()); // #7a10ba (varies)console.log(randomHexColor()); // #65abdc (varies)
7. 獲取數(shù)組的平均值
這是眾多問題中的另一個問題,其中涉及循環(huán)的解決方案可以使用一種或多種 Array 方法來縮短。
因此,雖然我們可以像這樣獲得數(shù)組中數(shù)字的平均值:
const getAverage = (arr) => {let sum = 0;for (const num of arr) {sum += num;}return sum / arr.length;};const arr = [5, 13, 9, 11, 10, 15, 7];const average = getAverage(arr);console.log(average); // 10
Array reduce() 方法讓我們創(chuàng)建了這個緊湊的單行替代方案:
const getAverage = (arr) => arr.reduce((sum, num) => sum + num, 0) / arr.length;const arr = [5, 13, 9, 11, 10, 15, 7];const average = getAverage(arr);console.log(average); // 10
const areEqual = (arr1, arr2) => {if (arr1.length === arr2.length) {for (const num of arr1) {if (!arr2.includes(num)) {return false;}}return true;}return false;};const arr1 = [1, 2, 3, 4];const arr2 = [3, 4, 1, 2];const arr3 = [1, 2, 3];console.log(areEqual(arr1, arr2)); // trueconsole.log(areEqual(arr1, arr3)); // false
使用 Array sort() 和 join() 方法,我們可以創(chuàng)建這個單行替代方案:
const areEqual = (arr1, arr2) =>arr1.sort().join(',') === arr2.sort().join(',');const arr1 = [1, 2, 3, 4];const arr2 = [3, 4, 1, 2];const arr3 = [1, 2, 3];console.log(areEqual(arr1, arr2)); // trueconsole.log(areEqual(arr1, arr3)); // false
9. 從數(shù)組中刪除重復項
我們可以像這樣從數(shù)組中刪除重復項:
const removeDuplicates = (arr) => {const result = [];for (const num of arr) {if (!result.includes(num)) {result.push(num);}}return result;};const arr = [1, 2, 3, 4, 5, 3, 1, 2, 5];const distinct = removeDuplicates(arr);console.log(distinct); // [1, 2, 3, 4, 5]
但是我們可以利用 Set() 構造函數(shù)在短短一行中刪除重復項:
const removeDuplicates = (arr) => [...new Set(arr)];const arr = [1, 2, 3, 4, 5, 3, 1, 2, 5];const distinct = removeDuplicates(arr);console.log(distinct); // [1, 2, 3, 4, 5]
10. 將Map轉換為 JSON
這個簡短的函數(shù)讓我們可以快速將 Map 對象轉換為 JSON 字符串而不會丟失任何信息:
const mapToJson = (map) => JSON.stringify(Object.fromEntries(map));const map = new Map([['user1', 'John'],['user2', 'Kate'],['user3', 'Peter'],]);const json = mapToJson(map);// {"user1":"John","user2":"Kate","user3":"Peter"}console.log(json);
11. 將 JSON 轉換為Map
另一個一行可以反轉上面的轉換。 以下函數(shù)會將 JSON 字符串轉換為 Map 對象。
const jsonToMap = (json) => new Map(Object.entries(JSON.parse(json)));const json = '{"user1":"John","user2":"Kate","user3":"Peter"}';const map = jsonToMap(json);// Kateconsole.log(map.get('user2'));// Map(3) { 'user1' => 'John', 'user2' => 'Kate', 'user3' => 'Peter' }console.log(map);
12. 將蛇形字符串轉換為駝峰大小寫
在蛇形字符串中,每個單詞由下劃線 (_) 分隔并以小寫字母開頭,例如:variable_name、bread_and_eggs 等。
但是,對于駝峰式字符串,第一個單詞以小寫字母開頭,后面的單詞均以大寫字母開頭。 單詞之間沒有空格或標點符號。 駝峰式字符串的示例有:variableName、breadAndEggs 等。
使用這個簡潔的函數(shù),我們可以將任何蛇形大小寫的字符串轉換為駝峰大小寫。
const snakeToCamelCase = (s) =>s.toLowerCase().replace(/(_\w)/g, (w) => w.toUpperCase().substr(1));const str1 = 'learn_javascript';const str2 = 'coding_beauty';console.log(snakeToCamelCase(str1)); // learnJavaScriptconsole.log(snakeToCamelCase(str2)); // codingBeauty
13.生成隨機UUID
“UUID”是大學唯一標識符的首字母縮寫詞。 UUID 是一個 128 位的值,可唯一標識 Internet 上的對象或實體。
這個單行生成一個隨機 UUID:
const generateRandomUUID = (a) =>a? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16): ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g,generateRandomUUID);console.log(generateRandomUUID()); // f138f635-acbd-4f78-9be5-ca3198c4cf34console.log(generateRandomUUID()); // 8935bb0d-6503-441f-bb25-7bc685b5b5bc
14.條件流控制
我們可以使用嵌套的三元運算符將 if...else 或 switch 語句轉換為單行語句。 考慮一個返回特定范圍內數(shù)字的英文單詞形式的函數(shù)。
使用 if...else 語句,這樣的函數(shù)可以這樣實現(xiàn):
const getNumWord = (num) => {if (num === 1) {return 'one';} else if (num === 2) {return 'two';} else if (num === 3) {return 'three';} else if (num === 4) {return 'four';} else return 'unknown';};console.log(getNumWord(1)); // oneconsole.log(getNumWord(3)); // threeconsole.log(getNumWord(7)); // unknown
使用 switch...case 語句:
const getNumWord = (num) => {switch (num) {case 1:return 'one';case 2:return 'two';case 3:return 'three';case 4:return 'four';default:return 'unknown';}};console.log(getNumWord(1)); // oneconsole.log(getNumWord(3)); // threeconsole.log(getNumWord(7)); // unknown
現(xiàn)在使用嵌套的三元組來創(chuàng)建單行代碼:
const getNumWord = (num) =>num === 1? 'one': num === 2? 'two': num === 3? 'three': num === 4? 'four': 'unknown';console.log(getNumWord(1)); // oneconsole.log(getNumWord(3)); // threeconsole.log(getNumWord(7)); // unknown
結論
我們已經了解了針對常見JavaScript編程問題的簡明解決方案。 我們看到許多實例,其中包含多個語句的命令式解決方案被轉換為使用各種內置方法和語言結構的聲明式單行代碼。
這些緊湊的解決方案有時性能和可讀性較低,但使用它們可以證明您的編程能力和對語言的掌握程度。使用任何一種方法,我們都是需要根據(jù)具體的情況來使用。
感謝您的閱讀,也期待您的關注,以便獲取更多優(yōu)質內容。
學習更多技能
請點擊下方公眾號
![]()

