JavaScript食譜

JavaScript食譜包含許多有用的教學文章,解釋如何在JavaScript中執行常見的操作。 注意:此文檔將不斷更新。隨著時間的推移,此文章將填滿大量有用的教學內容。 字串 如何將JavaScript字串中的首個字母轉成大寫 如何在JavaScript中檢查字串是否包含子字串 如何在JavaScript中替換字串的所有出現 如何將字串轉換為數字 如何在JavaScript中創建多行字串 如何在JavaScript中檢查字串是否以另一個字串開頭 數字 如何去掉JavaScript數字中的前導零 如何將數字格式化為貨幣值 如何在JavaScript中生成兩個數字之間的隨機數 日期 如何在JavaScript中獲取當前的時間戳記 物件 如何從JavaScript物件中刪除屬性 如何檢查JavaScript物件 如何深度克隆JavaScript物件 如何檢查JavaScript物件屬性是否為未定義 如何合併兩個JavaScript物件 如何在JavaScript中動態訪問物件的方法 如何使用解構語法處理數組和物件 如何計算JavaScript物件中的屬性數量 如何列出JavaScript物件的所有方法 數組 如何從JavaScript數組中刪除項目 如何在JavaScript數組中追加項目 如何在JavaScript中使用值初始化新數組 如何在Array.map()中使用Async和Await 如何清空JavaScript數組 如何按屬性值對JavaScript物件數組進行排序 如何從JavaScript數組中獲取一組物件的唯一屬性 函數 如何在JavaScript中設置默認參數值 循環 如何在JavaScript的for-of循環中獲取迭代的索引

JavaScript原型繼承

JavaScript因為使用原型繼承而在流行的程式語言中相當獨特。讓我們來看看這意味著什麼。 JavaScript因為使用原型繼承模型而在流行的程式語言中相當獨特。 這是什麼意思呢? 每個JavaScript物件都有一個被稱為prototype的屬性,指向另一個物件。 這個不同的物件就是物件原型。 我們的物件使用這個物件原型來繼承屬性和方法。 假設你使用物件字面語法來創建物件: const car = {} 或者使用new Object語法創建: const car = new Object() 無論哪種方式,car的原型都是Object: 如果你初始化一個陣列(也就是一個物件): const list = [] //或 const list = new Array() 它的原型就是Array。 你可以通過使用Object.getPrototypeOf()和Object.prototype.isPrototypeOf()方法來驗證: const car = {} const list = [] Object.getPrototypeOf(car) === Object.prototype Object.prototype.isPrototypeOf(car) Object.getPrototypeOf(list) === Array.prototype Array.prototype.isPrototypeOf(list) 原型的所有屬性和方法都可以在具有該原型的物件中使用: Object.prototype是所有物件的基本原型: Object.getPrototypeOf(Array.prototype) == Object.prototype 如果你想知道Object.prototype的原型是什麼,它是沒有原型的:它是null。這是個特別的存在 ❄️。 你所看到的例子是原型鏈的一個示例。 我可以創建一個擴展Array的物件,使用它實例化的任何物件都會在原型鏈中具有Array和Object,並繼承所有祖先的屬性和方法。 除了使用new操作符來創建物件,或者使用物件和陣列的字面語法,你還可以使用Object.create()來實例化物件。 傳遞的第一個參數是用作原型的物件: const car = Object.create({}) const list = Object.create(Array) 請注意,你可以使用以下方式來創建一個陣列: const list = Object....

JavaScript國際化

了解如何在JavaScript中使用國際化 Intl是一個強大的物件,它公開了JavaScript國際化API。 它提供以下屬性: Intl.Collator:允許您進行語言敏感的字符串比較 Intl.DateTimeFormat:允許您進行語言敏感的日期和時間格式設定 Intl.NumberFormat:允許您進行語言敏感的數字格式設定 Intl.PluralRules:允許您進行語言敏感的複數格式設定和複數規則設定 Intl.RelativeTimeFormat:允許您進行語言敏感的相對時間格式設定 它還提供一個方法:Intl.getCanonicalLocales()。 Intl.getCanonicalLocales()讓您可以檢查區域設定是否有效,並返回其正確格式。它可以接受字符串或數組: Intl.getCanonicalLocales('it-it') //[ 'it-IT' ] Intl.getCanonicalLocales(['en-us', 'en-gb']) //[ 'en-US', 'en-GB' ] 如果區域設定無效,則會產生錯誤: Intl.getCanonicalLocales('it_it') //RangeError: Invalid language tag: it_it 您可以使用try/catch區塊捕獲此錯誤。 不同類型可以根據其特定需求與Intl API進行交互。特別是我們可以提到: String.prototype.localeCompare() Number.prototype.toLocaleString() Date.prototype.toLocaleString() Date.prototype.toLocaleDateString() Date.prototype.toLocaleTimeString() 讓我們來看看如何使用上述Intl屬性: Intl.Collator 此屬性允許您進行語言敏感的字符串比較。 您可以使用new Intl.Collator()初始化Collator物件,傳遞區域設定,並使用其compare()方法,該方法在第一個參數之後返回正值。如果是反向則返回負值,如果是相同值則返回零。 例如: const collator = new Intl.Collator('it-IT') collator.compare('a', 'c') //返回一個負值 collator.compare('c', 'b') //返回一個正值 我們可以使用它來排序字符數組,例如。 Intl.DateTimeFormat 此屬性允許您進行語言敏感的日期和時間格式設定。 您可以使用new Intl.DateTimeFormat()初始化DateTimeFormat物件,傳遞區域設定,然後將日期傳遞給它以按照該區域設置進行格式設定。 例如: const date = new Date() let dateTimeFormatter = new Intl.DateTimeFormat('it-IT') dateTimeFormatter.format(date) //27/1/2019 dateTimeFormatter = new Intl....

JavaScript異常

當代碼遇到意外問題時,JavaScript的慣用方式是通過異常處理這種情況。 創建異常 使用throw關鍵字創建異常: throw value 其中value可以是任何JavaScript值,包括字符串、數字或對象。 當JavaScript執行這行代碼時,正常的程序流程被停止,控制權回到最近的異常處理器處。 處理異常 異常處理器是一個try/catch語句。 在try塊中的代碼行中引發的任何異常都在相應的catch塊中處理: try { // 代碼行 } catch (e) { } 這個例子中的e是異常值。 您可以添加多個處理器,捕獲不同類型的錯誤。 finally 要完成此語句,JavaScript還有另一個語句叫作finally,其中包含的代碼無論程序流程如何,無論是否處理了異常,無論是否發生了異常,都會被執行: try { // 代碼行 } catch (e) { } finally { } 您可以在沒有catch塊的情況下使用finally,作為在try塊中清理可能打開的任何資源(如文件或網絡請求)的一種方式: try { // 代碼行 } finally { } 嵌套的try塊 try塊可以嵌套,異常始終在最近的catch塊中處理: try { // 代碼行 try { // 其他代碼行 } finally { // 其他代碼行 } } catch (e) { } 如果在內部try中引發異常,則在外部catch塊中處理。

JavaScript術語彙集

前端開發中使用的一些術語指南,這些術語可能對您來說很陌生。 異步 代碼塊 塊級作用域 回調函數 聲明式 回退 函數作用域 不可變性 詞法作用域 兼容性填充 純函數 重新分配 作用域 作用域規則 填充 副作用 狀態 有狀態 無狀態 嚴格模式 樹搖 異步 當您啟動某些操作並忘記它時,代碼被稱為異步。在結果準備好之後,您無需等待即可獲取結果。典型的例子是AJAX調用,可能需要幾秒鐘的時間,而在此期間,您可以完成其他工作,當響應準備好時,調用回調函數。Promise和async/await是處理異步操作的現代方法。 代碼塊 在JavaScript中,一個代碼塊由大括號({})括起來。if語句或for循環中可以包含代碼塊。 塊級作用域 使用塊級作用域,定義在代碼塊內的變量在整個代碼塊內是可見且可訪問的,但在外部則不可訪問。 回調函數 回調函數是在某些事件發生時調用的函數。舉例來說,與元素關聯的點擊事件有一個回調函數,在用戶點擊元素時調用該函數。fetch請求具有當資源下載完畢後調用的回調函數。 聲明式 聲明式是指您告訴計算機您需要做什麼,並讓它解決細節。React被認為是聲明式的,因為您是通過抽象來理解問題,而不是直接編輯DOM。每一個高級編程語言相對於低級編程語言(如組合語言)都更具聲明性。JavaScript相對於C語言也更具聲明性。HTML是聲明式的。 回退 回退是在用戶無法訪問特定功能時提供良好體驗的方式。例如,禁用JavaScript的瀏覽器用戶應該能夠回退到頁面的純HTML版本。或者對於未實現某些API的瀏覽器,應該提供回退來避免完全破壞用戶體驗。 函數作用域 使用函數作用域,在函數內定義的變量在整個函數內是可見且可訪問的。 不可變性 當變量創建後其值無法更改時,該變量被稱為不可變。可變變量可以更改其值。對象和數組也適用相同的規則。 詞法作用域 詞法作用域是一種特殊類型的作用域,它意味著變量的值是由該變量的位置在編寫時確定的,而不是在被調用時確定,這是另一種替代方式,稱作動態作用域(在其他一些編程語言中使用)。 兼容性填充 兼容性填充是一種方法,用於為舊的瀏覽器提供現代JavaScript或現代瀏覽器API中提供的新功能。兼容性填充是一種特殊類型的填充。 純函數 純函數沒有任何副作用(不修改外部資源),其輸出僅由參數決定。您可以將此函數調用1M次,並且在給定相同集合的參數的情況下,輸出始終相同。 重新分配 使用var和let聲明的JavaScript變量允許您無限次重新分配變量。使用const聲明時,您有效地為字符串、整數、布林值和無法重新分配的對象聲明不可變的值(但仍可以通過其方法修改)。 作用域 作用域是指變量在程序的哪一部分可見。let和const使用塊級作用域,而使用var聲明的變量使用函數作用域。 作用域規則 作用域規則是一門編程語言如何確定變量和函數的作用域的方式。例如,我們可以使用塊級作用域、函數作用域、詞法作用域等。 填充 填充是對功能或API的一個小型封裝。通常用於抽象某些內容,預先填充參數或為不支持某些功能的瀏覽器添加兼容性填充。您可以將其視為兼容性層。 副作用 當一個函數與其外部的其他函數或對象交互時,這被稱為副作用。與網絡、文件系統或UI的交互都屬於副作用。 狀態 狀態通常與組件相關。如果一個組件管理自己的數據,則它可以是有狀態的;如果不管理數據,則是無狀態的。 有狀態 有狀態的組件、函數或類管理自己的狀態(數據)。它可以存儲數組、計數器或任何其他內容。 無狀態 無狀態的組件、函數或類也被稱為“愚蠢”的,因為它無法擁有自己的數據來做決策,因此它的輸出或表示完全基於其參數。這意味著純函數是無狀態的。注意:在React中,我們曾經稱之為無狀態組件,現在則稱之為函數組件,因為使用hooks使其能夠使用狀態。 嚴格模式 嚴格模式是ECMAScript 5.1的一個新特性,它使JavaScript運行時能夠捕獲更多錯誤,並通過拒絕未聲明的變量和其他可能導致忽視的問題(如重複對象屬性和其他細微問題)來幫助您改進JavaScript代碼。提示:請使用它。替代方法是“寬鬆模式”,即使看著我們給它取的名字也不好。 樹搖(Tree Shaking) 樹搖是從您發送給用戶的捆綁包中刪除“死代碼”的過程。如果您在引入語句中添加一些您從不使用的代碼,該代碼將不會發送給您的應用程序的用戶,以減小文件大小和加載時間。

JavaScript等號運算子

學習 JavaScript 等號運算子的基礎知識 這些運算子接受兩個值並返回布林值: == 檢查是否相等 != 檢查是否不相等 === 檢查是否嚴格相等 !== 檢查是否嚴格不相等 現在來談談我們所謂的“嚴格”。在非嚴格檢查中,第二個運算元在進行比較之前會被轉換為第一個運算元的類型。嚴格模式則會阻止這種轉換。 舉例如下: const a = true a == true // true a === true // true 1 == 1 // true 1 == '1' // true 1 === 1 // true 1 === '1' // false 無法檢查對象的相等性:兩個對象永遠不相等。唯一可能為真的情況是兩個變量引用了同一個對象。 還有一些需要注意的特殊情況:NaN 始終與 NaN 不相等。 NaN == NaN // false 在非嚴格模式下,null 和 undefined 的值是相等的: null == undefined // true null === undefined // false

JavaScript資料結構:佇列

佇列(Queue)和堆疊(Stack)相似,但插入點和移除點不同。 我們在佇列的一端新增項目,而在另一端移除項目。 這種結構被稱為「先進先出」(First In, First Out,FIFO)。 就像你可以想像的任何佇列,例如在餐廳、舞廳或者等待進入音樂會大廳時。 以下是使用JavaScript實現佇列的可能實作,使用私有類別欄位(Private Class Fields),內部儲存使用陣列: class Queue { #items = [] enqueue = (item) => this.#items.splice(0, 0, item) dequeue = () => this.#items.pop() isempty = () => this.#items.length === 0 empty = () => (this.#items.length = 0) size = () => this.#items.length } 以下是使用方式:首先從類別初始化一個物件,然後呼叫其方法: 使用 enqueue() 添加項目 使用 dequeue() 從佇列中取出項目 範例: const queue = new Queue() queue.enqueue(1) queue.enqueue(2) queue.enqueue(3) queue.size() //3 queue.dequeue() //1 queue.dequeue() //2 queue....

JavaScript資料結構:鏈結串列

鏈結串列是你可以學習到的最重要的資料結構之一。 在鏈結串列中,每個項目都包含對其後繼項目的引用。 我們可以從串列的開始處,即「頭部」,開始迭代遍歷所有項目,直到達到末尾(即「尾部」)。 相較於陣列,在低階程式語言中,項目並不相鄰於實際的記憶體位置,且沒有索引可供我們隨機訪問陣列中的項目。 我們無法在不從開始的情況下引用列表中的中間項目,因為我們不知道如何引用它。 JavaScript本身並沒有鏈結串列的實作,因此我們現在將創建一個。 首先,我們創建一個會成為鏈結串列中每個項目的容器的Item類別: class Item { next = null value = null constructor(value) { this.value = value } } 我們有一個指向鏈結串列中下一個項目的指標,以及該項目的值。 然後,我們定義一個LinkedList類別,該類別將擁有兩個私有值:head和tail。 我們定義了一個append()方法,用於將項目添加到串列中。如果它是第一個添加的項目,該項目同時是串列的頭部和尾部。否則,我們創建該項目並將其分配給尾部項目的next屬性: class LinkedList { #head = null #tail = null append = (value) => { const item = new Item(value) if (!this.#head) { this.#head = item this.#tail = item return } this.#tail.next = item this.#tail = item } size = () => { let count = 1 let item = this....

JavaScript演算法:二分搜尋

二分搜尋是假設要搜尋的陣列(或其他資料結構)已經排序完成。 我們從陣列和要搜尋的項目開始。 我們查看陣列的中間。我們將元素數量除以2,想像一下左邊有一部分陣列,右邊有另一部分。 如果我們的項目比正在尋找的項目小,那麼它一定在右邊的部分,因此我們可以完全捨棄右邊的部分。 然後我們執行相同的操作,將陣列的右半部分除以2,查看中間的項目,並且我們捨棄陣列的一部分。 最後,你將得到該項目(如果沒有找到該項目,將返回null)。 最後,如果陣列有8個項目,我們在最壞的情況下將在最多4步內找到該項目。 如果陣列有32個項目,在最壞的情況下我們最多需要6步。相較於線性搜尋的32步,這是一個巨大的優化! 二分搜尋的時間複雜度為O(log n)。 以下是一種可能的實現方式: const binarySearch = (list, item) => { let low = 0 let high = list.length - 1 while (low <= high) { const mid = Math.floor((low + high) / 2) const guess = list[mid] if (guess === item) { return mid } if (guess > item) { high = mid - 1 } else { low = mid + 1 } } return null //如果未找到 } 這如何運作?我們得到list陣列和要搜尋的項目值。然後我們最初將low值設置為0,並將high值設置為陣列的最後一個索引。我們首先查看中間項目,如果它就是我們正在尋找的項目,我們將返回它,並結束。如果不是,我們將low或high值設置為只查看陣列的左半部分或右半部分,並且重複這個過程直到找到該項目。...

JavaScript演算法:快速排序

快速排序是比選擇排序更有效率的搜尋演算法,它利用了遞迴的概念。 遞迴表示我們在同一函式中呼叫了該函式本身。這是一種非常有用的技巧,在某些情況下很適用,而這正是其中之一。 我說“在大多數情況下”,是因為正如我們將看到的,最壞的情況下,泡沫排序所需要的時間可能與選擇排序相同:O(n^2)。但在最佳情況下,它的運行時間會是O(n log n),落在O(n)和O(n^2)之間。 它是如何運作的呢?給定一個數組,我們選擇一個項目作為主軸。然後將比主軸小的項目和比主軸大的項目分開。 接著我們對組成比主軸小和比主軸大的項目的兩個數組進行相同的操作。 通過代碼來看會更容易理解: const quickSort = (originalList) => { const list = [...originalList] if (list.length < 2) { return list } const pivot = list[0] const smaller = list.filter((item) => item < pivot) const bigger = list.filter((item) => item > pivot) return [...quickSort(smaller), pivot, ...quickSort(bigger)] } 在這個例子中,我選擇將主軸設置為數組中的第一個項目,但也可以選擇中間的項目,例如: const pivot = list[Math.floor(list.length / 2)] 注意我們首先複製了數組,所以調用quickSort()不會修改原始數組,它只會返回一個新的排序過的數組: const a = [1, 6, 3, 4, 5, 1, 0, 4, 8] console....