天天看點

提高代碼品質的 11 個 JavaScript 核心函數

作者:啟辰8
提高代碼品質的 11 個 JavaScript 核心函數

它不在乎你是使用後端還是前端(甚至是宇宙飛船!),JavaScript可以在任何地方使用,因為它是一種非常靈活的語言。它具有核心的函數式程式設計模式以及類,它與其他“類c”語言的相似性使每個開發人員都可以輕松地過渡。

如果你想提升你的JavaScript技能,我建議你學習、練習和掌握這門語言中以下非常重要的核心函數。你不需要每個函數來解決大多數問題,但在某些情況下,它們可以幫助你避免繁重的工作,而在其他情況下,它們将減少你必須編寫的代碼量。

1. map()

map()是JavaScript中最重要的函數之一!此外,它也是給學習JavaScript的人帶來最大麻煩的一個函數。之是以會這樣,是因為這個函數的工作方式來自于大多數開發人員不熟悉的函數式程式設計。在我們有偏見的大腦看來,這似乎很奇怪,甚至是錯誤的。

函數map()非常簡單。它将自己附加到一個數組,并将每個元素轉換為其他元素,進而得到一個新數組。這種轉換是通過map括号中提供的匿名函數完成的。

這就是地圖所做的一切!

一開始,map()的文法可能需要一些時間來适應,但掌握它之後,你将成為使用JavaScript的最好朋友。

為什麼要使用map()?

例如,假設我們記錄了上周每一天噴泉中的水量并将其存儲在一個數組中。 在周末,您被告知測量工具不夠準确,水量比應有的少了 3.2 升。

使用 map() 函數,您可以通過以下方式輕松解決此問題:

const dailyReadings = [34.2, 35.4, 40.1, 35.2, 33.5, 36.5, 38.7];

const correctedDailyReadings = dailyReadings.map(day => day + 3.2);

console.log(correctedDailyReadings); //gives [37.4, 38.6, 43.3, 38.4, 36.7, 39.7, 41.9]
           

當您從數組建立 DOM 元素清單時,您可以在 React 的世界中找到另一個非常實用的示例。 這是 React 中的常見模式,将通過這段代碼實作:

export default({articles}) => {
    return links.map(article => {
        return (
            <div className="link" key={article.id}>
                <div className="article-name">{article.name}</div>
                <div className="article-desc">{article.description}</div>
            </div>
        );
    });
};
           

現在你可以争辯說 map() 隻不過是 for 循環的另一種實作,你是對的,但請注意,也許這是你受過面向對象訓練的頭腦提出了這個論點。

2. filter()

filter() 是一個非常有用的 JavaScript 函數,您可以在許多情況下使用它,因為它根據給定的規則/邏輯過濾數組。 此規則/邏輯将作為匿名函數提供。

為了展示 filter() 是如何工作的,我們可以重用之前的噴泉示例。 假設數組包含噴泉中存儲的水量(這次測量工具按預期工作)。 現在,我們想知道該量低于 36 升的頻率。 這可以使用 filter() 函數來實作:

const dailyReadings = [34.2, 35.4, 40.1, 35.2, 33.5, 36.5, 38.7];

const daysWithLowAmount = dailyReadings.filter(day => {
    return day < 36
});

console.log("Days with low amount of water: " + daysWithLowAmount.length); // 4
console.log(daysWithLowAmount); // [34.2, 35.4, 35.2, 33.5]
           

重要的是,您傳遞給 filter() 的匿名函數必須傳回一個布爾值:true 或 false。 filter() 函數使用布爾表達式來确定是否應将值插入新生成的數組中。

在匿名函數中,您可以實作任意數量的複雜邏輯來過濾資料; 您可以讀取使用者輸入、進行任何 API 調用等,隻要最後傳回一個布爾值即可。

注意:請記住 filter() 總是傳回一個數組。 如果過濾後的資料為空,也是如此。 這通常會導緻代碼片段中出現細微的錯誤,因為 filter() 是這樣使用的:

const dailyReadings = [34.2, 35.4, 40.1, 35.2, 33.5, 36.5, 38.7];

const daysWithCriticalAmount = dailyReadings.filter(day => {
    return day < 30
});

if(daysWithCriticalAmount) {
    console.log("The amount of water was critical");
} else {
    console.log("The amount of water was normal");
}
           

你注意到什麼了嗎? 最後的 if 條件檢查 daysWithCriticalAmount 這實際上是一個空數組,因為沒有一天的水少于 30。

令人驚訝的是,如果您正趕在截止日期之前并且隻想快速實作一個過濾器方法,那麼這種錯誤就經常發生。 這段代碼的問題在于,尤其是 JavaScript(是的,JavaScript 很奇怪)在很多方面都是一種不一緻的語言。 有時事物的“真實性”就是其中之一。

正如您可能知道在 JavaScript [] == true 中傳回 false 并且您可能認為上面的代碼是正确的。

不幸的是,在 if 條件下,[] 的計算結果為真! 換句話說,永遠不會執行 else 塊。

解決這個問題非常簡單,因為您隻需檢查結果數組的長度是否大于或等于 1。

3. reduce()

與本文中的所有其他函數相比,reduce() 正在争奪“令人困惑、怪異和複雜的 JavaScript 函數”的第一名。 盡管此功能非常重要并且在許多情況下會産生優雅的代碼,但許多 JavaScript 開發人員都避免使用它。 他們更喜歡在沒有 reduce() 幫助的情況下編寫代碼。

原因之一是 reduce() 的複雜性。 很難了解這個函數的概念和執行。 此外,如果你閱讀它的描述,你必須重新閱讀它幾次,而且,如果你讀錯了,你會懷疑自己(發生在我身上,直到我看到它在行動)。

reduce() 函數用于将給定數組減少(很明顯不是嗎?)為單個值。 這可以是數字、字元串、函數、對象或其他任何東西。

如果你想使用 reduce() 函數來減少數組,你需要通過提供一個函數來提供所需的邏輯。 通常,此函數将稱為将第一個參數轉換為 reduce() 的 reducer 函數。 此外,它還包含第二個參數,它是一個起始值,可以是數字、字元串等。函數本身如下所示:

array.reduce(reducerFunction, startValue)
           

startValue:傳遞給 reduce() 函數的 startValue 是您要使用 reducerFunction 處理的計算的起始值(顯而易見...)。 例如,如果要執行加法,則可以從 0 開始;如果要執行乘法,則應使用值 1。

reducerFunction:如前所述,reducer 函數用于将數組轉換為單個值。 它有兩個參數:一個累加器和一個存儲目前值的變量。

累加器隻是一個奇特的名稱,描述了包含計算結果的變量(就像使用 total 來求和數組中的所有項)。 在 reducer 函數中,累加器将被初始設定為起始值,然後計算将逐漸周遊數組,同時每一步的結果儲存在累加器中。

reducer 函數的第二個參數是 currentValue,它将包含數組中特定步驟中給定位置的值。 例如,在步驟 2 中執行 reducer 函數時,變量 currentValue 将包含輸入數組中的第二個值。

有了所有這些資訊,我們應該看看下面的示例,它将在 reducer 函數中添加輸入數組中的每個值:

const input = [1, 2, 3, 4];
const result = input.reduce((acc, currentValue) => acc + currentValue, 0);
console.log(result); // 10
           

在第一行中,我們定義了包含我們要添加的所有數字的輸入數組。 下一行将包含 input.reduce() 調用,它将 acc 的起始值定義為 0,因為另外我們應該從 0 開始以不影響結果。 reducer 函數 body (acc, currentValue) => acc + currentValue 對目前值和存儲在累加器中的值進行簡單相加。

如果你用 for 循環做這個加法,它看起來像這樣:

const input = [1, 2, 3, 4];
let result = 0;
for (let i = 0; i < input.length; i++) {
    result += input[i]
}
console.log(total)
           

如您所見,簡單的 for 循環示例要長得多,而且不如使用 reduce 優雅。

4. some()

假設您有一組對象,其中包含學生及其在考試中的分數。 現在,您想知道班上是否有學生的分數高于 90%,而不關心是否有一名或多名學生以超過 90% 的成績通過了該考試。

如果您想在 JavaScript 中執行此操作,您可以使用循環和在找到得分大于 90% 的第一個人後設定為 true 的變量來解決問題:

const students = [{
    name: "Stud 1",
    score: 78,
}, {
    name: "Stud 2",
    score: 92
}, {
    name: "Stud 3",
    score: 90
}]

let over90 = false;

for(let i = 0; i < students.length; i++) {
    if(students[i].score > 90) {
        over90 = true;
        break;
    }
}

if(over90) {
    console.log("There are students with exceptional score!")
} else {
    console.log("Unfortunately, nothing is exceptional")
}
           

對我來說,這段代碼看起來非常“醜陋”、“冗長”或“可怕”!

可以使用前面描述的 map() 函數對其進行優化,但解決方案仍然有點笨拙。

幸運的是,JavaScript 有一個名為 some() 的相當簡潔的函數,它在核心語言中可用,可以處理數組,并傳回一個布爾值。 在提供匿名函數的同時,它将過濾輸入數組以優雅地解決問題:

const students = [{
    name: "Stud 1",
    score: 78,
}, {
    name: "Stud 2",
    score: 92
}, {
    name: "Stud 3",
    score: 90
}]

if(students.some(student => {
    return student.score > 90
})) {
    console.log("There are students with exceptional score!")
} else {
    console.log("Unfortunately, nothing is exceptional")
}
           

您可以看到它獲得相同的輸入并以更優雅的方式産生相同的結果。 此外,代碼量減少了,可讀性也比以前高了很多。

5. every()

JavaScript 核心語言中已經存在的另一個函數是 every()。 此函數将傳回一個布爾值(如 some()),但将測試輸入數組中的所有項目。 為此,您必須(再次)提供一個匿名函數。 例如,我們将通過考試成績達到 70 分或以上來測試是否每個學生都通過了考試:

const students = [{
    name: "Stud 1",
    score: 78,
}, {
    name: "Stud 2",
    score: 92
}, {
    name: "Stud 3",
    score: 90
}]

if(students.every(student => {
    return student.score > 70
})) {
    console.log("All students passed the exam!")
} else {
    console.log("Unfortunately, not all students did well")
}
           

與 some() 一樣,此函數建立簡潔的優雅、可讀和可維護的代碼。

6. includes()

通常,如果我想檢查一個數組是否存在子字元串,我會使用 indexOf()。 不幸的是,我必須查閱文檔才能了解它們的傳回值。

幸運的是,JavaScript 中有一個很好的替代方法可以用來實作這一點:includes()。 用法非常簡單,并且區分大小寫(我猜你無論如何都希望如此)。 有關示例,請參見以下代碼片段:

const numbers = [6, 5, 13, 26, 48, 1];
console.log(numbers.includes(5)); // true

const name = "Paul Knulst";
console.log(name.includes('paul')); // false, because first letter is in small
console.log(name.includes('Paul')); // true, as expected
           

但是,includes 隻能比較簡單的值而不能比較對象:

const user = {a: 6, b: 5, c: 26};
console.log(user.includes('b')); // does not work because objects does not have an "includes" method
           

7. shift()

如果你想删除數組的第一個元素 shift() 是你應該使用的方法,因為它易于記憶且直覺。 請注意,您也可以使用 splice(稍後檢視)來執行此操作,但 shift() 更容易:

const input = [1, 2, 3, 4];
const first = input.shift();
console.log(input); // gives: Array [2, 3, 4]
console.log(first); // gives: 1
           

正如您在此處看到的那樣,shift 改變了調用它的數組并傳回删除的元素。

注意:shift 效率極低,如果您正在使用大型數組,則應避免使用。 在大型數組上過多調用 shift() 可能會破壞您的應用程式!

8. unshift()

與删除一個元素的 shift() 相比,此函數用于在數組的開頭添加一個新元素:

const input = [1, 2, 3, 4];
input.unshift(0);
console.log(input); // expected output: Array [0, 1, 2, 3, 4]
           

注意:與 shift 一樣,unshift 效率極低,如果您正在處理大型數組,則應避免使用。 在大型數組上調用太多 unshift() 可能會破壞您的應用程式!

9. slice()

在 JavaScript 中存在一個稱為切片的概念,它是一種通過提供起始索引和結束索引來建立包含原始字元串的一部分的新字元串的函數。 現在,借助 indexOf 函數,您可以對輸入字元串進行切片以檢索搜尋到的子字元串:

const input = "This is a cool article about mandatory JavaScript functions that every developer shoud know";
const start = input.indexOf("cool");
const end = input.indexOf("that");
const headline = input.slice(start, end);
console.log(headline); // "cool article about mandatory JavaScript functions"
           

請注意,開始索引包含在結果數組中,但結束索引不包含。 此外,您還可以看到“functions”和“that”之間的空格也沒有被分割。

此外,切片也可以用于數組:

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2)); // ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4)); // Array ["camel", "duck"]
           

10. splice()

splice() 聽起來像 slice() 并且可以與它進行比較,因為這兩個函數都從原始數組或字元串建立新的數組或字元串。 主要的小但非常重要的差別是 splice() 删除、更改或添加元素但修改原始數組。 如果您不完全了解深拷貝和引用在 JavaScript 中的工作原理,原始數組的這種“解構”可能會導緻巨大的問題!

以下示例将展示如何使用 splice() :

const months = ['Jan', 'March', 'April', 'June'];
const feb = months.splice(1, 0, 'Feb'); // inserts at index 1
console.log(months); // ["Jan", "Feb", "March", "April", "June"]
console.log(feb); // []

const may = months.splice(4, 1, 'May'); // replaces 1 element at index 4
console.log(months); // ["Jan", "Feb", "March", "April", "May"]
console.log(may); // ["June"]
           

你可以在這裡看到 splice() 操作原始數組。 如果您删除一個項目,它也會傳回删除的條目,但如果您添加一個條目,則傳回數組将為空。

11. fill()

最後一個 JavaScript 函數是 fill(),用于将多個項目更改為單個值,甚至将整個數組重置為其初始值。 如果你需要這個 fill() 可以幫助你避免循環來重置數組的值。 此外,該函數可用于用給定值替換數組中的部分或全部條目。

您可以在以下示例中看到它是如何工作的:

const input = [1, 2, 3, 4, 5, 6];
console.log(input.fill(0, 2, 4)); // [1, 2, 0, 0, 0, 0]
console.log(input.fill(5, 1)); // [1, 5, 5, 5, 5, 5]
console.log(input.fill(6)); // [6, 6, 6, 6, 6, 6]
           

結論

此清單包含大多數 JavaScript 開發人員在其職業生涯中遇到和使用的函數。 雖然很長,但絕不是完整的,因為 JavaScript 中還有許多次要但非常有用的函數:reverse()、sort()、find()、flat()、entries()。 我建議您閱讀這些函數,因為您随時都會在 JavaScript 項目中使用它們。

此外,隻要有可能,你都應該探索核心語言或著名的實用程式庫,如 lodash,以加深你的 JavaScript 知識。 它将帶來巨大的生産力,您将學會建立更清晰、緊湊、可讀、可維護和可用的代碼!

繼續閱讀