JavaScript演算法:線性搜索

線性搜索,也被稱為順序搜索或簡單搜索,是最基本的搜索演算法。給定一個資料結構,例如一個數組,我們通過查看所有元素來搜索某個項目,直到找到為止。 它的實現非常簡單: const linearSearch = (list, item) => { for (const [i, element] of list.entries()) { if (element === item) { return i; } } }; 這會返回我們要查找的項目的索引。例如: linearSearch(['a', 'b', 'c', 'd'], 'd'); //3(索引從0開始) 如果我們查找的是’a’,該演算法只會查看第一個元素並返回,所以速度非常快。 但是如果我們查找的是最後一個元素,該演算法需要遍歷整個數組。計算大O值時,我們始終考慮最壞情況。 因此,該演算法的時間複雜度(演算法複雜度)為O(n)。

JavaScript物件屬性

專案需要了解關於JavaScript物件屬性的所有資訊。 JavaScript物件 擁有屬性,結構是由標籤和數值所組成的。 我們所見到的物件文字語法: const car = { } 讓我們能夠像這樣定義屬性: const car = { color: '藍色' } 這裡我們有一個名為car的物件,擁有一個名為color,具有數值藍色的屬性。 標籤可以是任何字串。注意到我在color周圍沒有使用引號,但是如果我想要在屬性名稱中包含無法當作變數名稱的字元,我必須這樣寫: const car = { color: '藍色', 'the color': '藍色' } 這意味著空格、連字號和其他特殊字元。 就像你看到的,我們用逗號分隔每個屬性。 檢索屬性的數值 我們可以使用2種不同的語法檢索屬性的數值。 第一種是點表示法: car.color //'藍色' 第二種,適用於具有無效名稱的屬性,是使用方括號: car['the color'] //'藍色' 如果您存取一個不存在的屬性,您將得到 undefined: car.brand //undefined 檢查屬性值但預設為預定義值的一個好方法是使用 || 運算子: const brand = car.brand || '福特' 正如前面所述,物件可以擁有嵌套的物件作為屬性: const car = { brand: { name: '福特' }, color: '藍色' } 您可以使用以下方法來訪問品牌名: car.brand.name 或 car['brand']['name'] 甚至可以混合使用:...

JavaScript的堆疊資料結構

堆疊是一種資料結構,相較於陣列具有更多限制。 我們只能將項目加入堆疊頂部,並且只能移除堆疊頂部的項目。 想像一下一堆書。你只能從頂部添加書,並且只能從頂部移除書。 因此,如果你添加了一堆書,然後想要存取第一本添加的書,你需要先移除所有書,直到到達第一本書。 這個概念被稱為「先進後出」(First In, Last Out,FILO)。 雖然JavaScript的陣列是內建的,不需要自己建立,但我們必須自己實現堆疊。 我們將創建一個封裝我們資料的資料結構,使其無法從外部訪問,只允許使用push()方法將資料添加到堆疊中,並使用pop()方法從堆疊中移除資料。 我們可以用多種不同的方式實現這一點。其中一種方式是使用類別,尤其是我要使用私有類別欄位。私有類別欄位尚不是JavaScript標準的一部分,但自版本12起在Chrome、Edge、Safari和Node.js中可用。但在Firefox中尚不可用,希望能夠早日支援。 為什麼我使用它們?因為它們使我們能夠非常容易地封裝類別的內部狀態並保護它免受外界的訪問。 class Stack { #items = [] push = (element) => this.#items.push(element) pop = () => this.#items.pop() isempty = () => this.#items.length === 0 empty = () => (this.#items.length = 0) size = () => this.#items.length } 我們有5個公共方法:push和pop用於將項目添加/移除堆疊,isempty用於檢查堆疊是否為空,empty用於清空堆疊,size用於獲取堆疊的大小。 現在,我們可以從這個類別建立堆疊物件並進行操作: const stack = new Stack() stack.push(1) stack.push(2) stack.push(3) console.log(stack.size()) //3 console.log(stack.pop()) //[ 3 ] console.log(stack.size()) //2 如果使用公共屬性,一切都會以相同的方式運作: class Stack { items = [] push = (element) => this....

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算法:選擇排序

假設我們有一個數字陣列,我們想要按照元素大小對其進行排序。 你可以有一個物件的陣列,並且可以比較物件的屬性,例如按年齡排序或按姓氏的字母順序排序。細節並沒有改變。 我們的做法是:我們選擇第一個項目。然後我們將其與第二個項目進行比較。如果第二個項目比較小,我們將其與第一個項目交換位置。然後,我們將這個第一個項目與陣列中的每個項目進行比較。 一旦我們知道我們有最小的項目,我們將切換到第二個元素,並將其與陣列中的每個項目進行比較,忽略索引為0,因為我們已經知道那是最小值。以此類推,直到陣列的結尾。 正如你所見,這個演算法非常昂貴。它不僅在陣列的每個項目上進行迭代:對於每個項目,它還會再次迭代陣列。 它的時間複雜度是O(n^2)。請注意,嚴格來說,我們比較的項目數量不斷變小,但這在複雜度的大O表示法中並不意味著任何事情。 以下是我們實現的選擇排序算法。 const selectionSort = (originalList) => { //首先我們將陣列複製一份,以避免修改原始陣列,因為在JS中,物件是按引用傳遞的 const list = [...originalList] const len = list.length for (let i = 0; i < len; i++) { let min = i for (let j = i + 1; j < len; j++) { if (list[min] > list[j]) { min = j } } if (min !== i) { //找到了一個新的最小值。與當前元素交換位置 ;[list[i], list[min]] = [list[min], list[i]] } } return list } const listOfNumbers = [1, 6, 3, 4, 5] console....

JavaScript算術運算子

在任何編程語言中,進行數學運算和計算是一個非常常見的操作。JavaScript提供了幾個運算子來幫助我們處理數字。 加法 (+) 減法 (-) 除法 (/) 餘數 (%) 乘法 (*) 指數運算 (**) 遞增運算子 (++) 遞減運算子 (--) 一元否定運算 (-) 一元正運算 (+) 加法 (+) const three = 1 + 2 const four = three + 1 如果使用字符串,+ 運算子也可以用於字符串拼接,所以要注意: const three = 1 + 2 three + 1 // 4 'three' + 1 // three1 減法 (-) const two = 4 - 2 除法 (/) 返回第一個運算元和第二個運算元的商: const result = 20 / 5 //result === 4 const result = 20 / 7 //result === 2....

JavaScript範圍

學習JavaScript範圍的基礎知識 範圍是一組定義在編程語言中以確定變量值的規則。 JavaScript使用詞法範圍,這意味著變量的值由其在被寫入時的位置所定義,而不是在其被調用時,這是與另一種替代方式動態範圍不同的事情。 範圍是對程序的部分可見的變量集合。 我們有全局範圍,區塊範圍和函數範圍。如果一個變量在函數或區塊外部定義,它將附加到全局對象並具有全局範圍,這意味著它在程序的每個部分都可用。 var,let和const聲明之間有一個非常重要的區別。 在函數內部定義為var的變量只在該函數內部可見,就像函數參數一樣。 另一方面,在其所在的塊內定義為const或let的變量只在該塊內部可見。 重要的是要理解,塊(由一對花括號標識)不為var定義新的範圍,但對於let和const則有。只有在創建函數時,才為var創建新的範圍,因為var沒有塊範圍,而是函數範圍。 在函數內部,任何在其中定義的var變量在所有函數代碼中都可見,即使該變量在函數結束時聲明,它仍然可以在開頭引用,因為JavaScript在執行代碼之前實際上會將所有變量聲明移動到頂部(這被稱為提升)。為避免混淆,始終在函數開頭聲明var變量。 這就是我的意思。即使你在函數結尾聲明了一個var變量,它的聲明也會被移到頂部: function run() { console.log(`${name}`) var name = 'Flavio' } run() 這將打印出“undefined”,因為實際上發生的是: function run() { var name; console.log(`${name}`) name = 'Flavio' } run() let和const不會“受到”提升的影響。如果在上面的示例中使用它們之一,則會出現錯誤:ReferenceError: name is not defined。 在JavaScript中,父函數的變量也可以在內部函數中使用。內部函數的範圍還包括父函數的範圍,這稱為閉包(我們將在後面更詳細地談論這一點)。 你需要注意一點。在非嚴格模式下,如果你使用未聲明的變量,無論你在哪裡使用,該變量都會附加到全局範圍。這可能是錯誤的根源。所以,在使用變量之前,請確保始終聲明變量。只是要意識到這一點,但這只是預設情況下使用嚴格模式的另一個原因,嚴格模式可以解決這個問題。我們之後再談論嚴格模式。 記住:在具有與全局變量同名的函數(或塊)中定義的任何變量優先於全局變量,遮蔽它。 這將打印undefined: var name = 'Roger' function run() { console.log(`${name}`) var name = 'Flavio' } run() 而這將引發錯誤ReferenceError: name is not defined: let name = 'Roger' function run() { console.log(`${name}`) let name = 'Flavio' } run()

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還是Python?

我寫了一本關於JavaScript的書,還寫了一本關於Python的書,人們經常問我一個問題,該從哪個開始? 它們都非常適合初學者,並且非常受歡迎。 它們的區別在於你可以用它們做什麼。 它們都是動態且通用的程式語言,但JavaScript在瀏覽器中運行的優勢巨大,所以它在前端開發中被廣泛使用。 Python在數據科學和機器學習的應用中表現出色,有許多針對該領域開發的套件,所以你可以根據這一點來做出決定。 如果你猶豫不決無法做出決定,我建議你學校教授的那種語言,或者是你想要開發的項目所使用的語言。或者是你想要工作的公司所使用的語言。 如果你還是猶豫不決,那就由我來幫你選擇。我會推薦JavaScript,因為我認為它更加靈活,而且可以在瀏覽器中運行這一事實是一個巨大的優勢。