🔍 搜尋結果:研

🔍 搜尋結果:研

😻建立您自己的 CLI 版本的 MonkeyType 🙈

長話短說 ---- 在這個易於理解的教程中,您將學習如何在幾分鐘內建立自己的 MonkeyType CLI 版本。 😎 **您將學到什麼:✨** - 使用 Pythoncurses 模組建立具有**WPM**和**Accuracy**支援的強大打字 CLI 應用程式。 您準備好成為 CLI MonkeyTyper 了嗎? 😉 無論這是您的第一個 CLI 應用程式還是第 n 個應用程式。請隨意跟隨。 ![猴子在筆記型電腦上打字](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unzjcx4ues1ot7m4h4hu.gif) --- 設定環境🙈 ----- > ℹ️不需要設定虛擬環境,我們不會使用任何外部相依性。 建立一個資料夾來保存專案的所有原始程式碼: ``` mkdir cli-monkeytype-python cd cli-monkeytype-python ``` 建立兩個新文件,我們將在其中編寫程式: ``` touch main.py typing_test.py ``` `main.py`檔案將作為我們應用程式的起點,而`typing_test.py`檔案將保存程式的所有邏輯。 > ℹ️對於Linux或Mac用戶,您不需要下載任何依賴項,我們將主要使用**curses** 、 **time**和**random**模組,這些模組都包含在Python標準庫中。 ⚠️**注意** > Windows 使用者可能必須安裝curses,因為它不包含在Windows 的Python 標準庫中。在繼續下一步之前,請確保已安裝它。 --- 讓我們來寫程式吧🐵 --------- > 💡 我們將在本節中研究應用程式的方法、大綱和實際編碼部分。 😵‍💫 ### 方法和概要👀 我們將在這裡採取不同的方法,而不是將所有程式碼都塞在`main`文件中。我們將把程式碼分成不同文件中的類別。 將有一個單獨的文件,其中包含一個負責封裝與打字測試相關的所有邏輯的類別。在主文件中,我們將呼叫此類的方法。聽起來,對吧?讓我們開始吧。 🚀 這是我們類別的骨架以及我們將要處理的所有方法。 ``` class TypingTest: def __init__(self, stdscr): pass def get_line_to_type(self): pass def display_wpm(self): pass def display_accuracy(self): pass def display_typed_chars(self): pass def display_details(self): pass def test_accuracy(self): pass def test_wpm(self): pass ``` 所有函數名稱都應該是不言自明的。如果您需要協助理解每個函數的作用,即使在查看了此大綱之後,為什麼還要閱讀這篇文章?只是開玩笑\*不是真的\*。 😏 > 🥱 這是一個適合初學者的應用程式。別擔心,一起編碼吧。 ### 真正的樂趣開始了! ![表演時間 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i0r36i2t9mrygd14wtop.gif) 我們將從導入模組並編寫`__init__`方法開始。這將初始化程式執行所需的所有術語。 ``` import curses import random import time class TypingTest: def __init__(self, stdscr): self.stdscr = stdscr self.to_type_text = self.get_line_to_type() self.user_typed_text = [] self.wpm = 0 self.start_time = time.time() # Initialize color pairs curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLACK) curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) # --SNIP-- ``` `stdscr`用於控制終端螢幕,對於建立使用者可以看到其擊鍵的基於文字的使用者介面至關重要。 ⌨️ `get_line_to_type`方法取得一行文字供使用者鍵入。該文字儲存在`self.to_type_text`變數中。當他們鍵入時,他們輸入的字元將保存在`self.user_typed_text`清單中。我們使用列表是因為當使用者更正錯誤輸入的字元時,彈出最後一項會更容易。 初始每分鐘字數 (WPM) 分數設定為 0,我們記錄測驗的開始時間。我們也初始化了一些**顏色對**,根據它們是否正確來指示字元上的顏色。稍後,我們將根據使用者打字所需的時間來計算**WPM** 。 現在,新增以下功能的程式碼 > ℹ️ 確保在專案根目錄中建立一個名為`typing_texts.txt`的新文件,其中包含幾行文字。參考:[點這裡](https://github.com/shricodev/blogs/blob/main/cli-monkeytype-python/typing_texts.txt)。 ``` # --SNIP-- def get_line_to_type(self): with open("typing_texts.txt", "r", encoding="utf-8") as file: lines = file.readlines() return random.choice(lines).strip() def display_wpm(self): self.stdscr.addstr(1, 0, f"WPM: {self.wpm}", curses.color_pair(3)) def display_accuracy(self): self.stdscr.addstr( 2, 0, f"Accuracy: {self.test_accuracy()}%", curses.color_pair(3), ) def display_typed_chars(self): for i, char in enumerate(self.user_typed_text): correct_character = self.to_type_text[i] # Use color pair 1 if correct, else color pair 2. color = 1 if char == correct_character else 2 self.stdscr.addstr(0, i, char, curses.color_pair(color)) def display_details(self): self.stdscr.addstr(self.to_type_text) self.display_wpm() self.display_accuracy() self.display_typed_chars() # --SNIP-- ``` 讓我總結一下這些方法,它們非常簡單: 🎯 `get_line_to_type(self)` :從名為「typing\_texts.txt」的檔案中擷取刪除了尾隨空格的隨機行。 🎯 `display_wpm(self)` :當使用者鍵入時在螢幕上的第一行顯示 WPM。 🎯 `display_accuracy(self)` :在螢幕上第 2 行顯示**準確率百分比。**準確率由我們即將編寫的`test_accuracy()`方法計算。 🎯 `display_typed_chars(self)` :顯示使用者在螢幕上輸入的字符,突出顯示一個顏色對(顏色 1)中的正確字符和另一個顏色對(顏色 2)中的錯誤字符。 🎯 `display_details(self)` :它本質上是一個輔助函數,幫助顯示上面所有顯示函數的內容。 好的,現在我們已經編寫了這些顯示方法,讓我們實現實際的邏輯來測試準確性和 WPM 本身。 新增以下程式碼行: ``` # --SNIP-- def test_accuracy(self): total_characters = min(len(self.user_typed_text), len(self.to_type_text)) # If there are no typed chars, show accuracy 0. if total_characters == 0: return 0.0 matching_characters = 0 for current_char, target_char in zip(self.user_typed_text, self.to_type_text): if current_char == target_char: matching_characters += 1 matching_percentage = (matching_characters / total_characters) * 100 return matching_percentage def test_wpm(self): # getkey method by default is blocking. # We do not want to wait until the user types each char to check WPM. # Else the entire logic will be faulty. self.stdscr.nodelay(True) while True: # Since we have nodelay = True, if not using max(), # users might end up with time.time() equal to start_time, # resulting in 0 and potentially causing a zero-divisible error in the below line. time_elapsed = max(time.time() - self.start_time, 1) # Considering the average word length in English is 5 characters self.wpm = round((len(self.user_typed_text) / (time_elapsed / 60)) / 5) self.stdscr.clear() self.display_details() self.stdscr.refresh() # Exit the loop when the user types in the total length of the text. if len(self.user_typed_text) == len(self.to_type_text): self.stdscr.nodelay(False) break # We have `nodelay = True`, so we don't want to wait for the keystroke. # If we do not get a key, it will throw an exception # in the below lines when accessing the key. try: key = self.stdscr.getkey() except Exception: continue # Check if the key is a single character before using ord() if isinstance(key, str) and len(key) == 1: if ord(key) == 27: # ASCII value for ESC break # If the user has not typed anything reset to the current time if not self.user_typed_text: self.start_time = time.time() if key in ("KEY_BACKSPACE", "\b", "\x7f"): if len(self.user_typed_text) > 0: self.user_typed_text.pop() elif len(self.user_typed_text) < len(self.to_type_text): self.user_typed_text.append(key) ``` 🎯 `test_accuracy(self)` :透過將使用者輸入的字元與目標文字進行比較,計算並返回打字準確度(以百分比形式)。如果字元匹配,則將匹配字元的計數加1。最後,計算匹配的百分比。 🎯 `test_wpm(self)` :計算每分鐘字數(WPM)並即時更新顯示。我們用一個**公式**來計算WPM,這不是我想出來的,我從網路複製的。它追蹤使用者輸入的內容,處理退格鍵,並在使用者完成輸入目標文字或按**ESC**時停止。 偉大的!這就是我們的**TypingTest**類別。 🎉 > ✅ 我們編寫程式碼的方式可以幫助我們輕鬆地將程式碼匯入到任何未來的專案中,並使維護變得更加容易。 是時候測試我們的實作了。 🙈 在`main.py`檔案中,加入以下程式碼行: ``` from curses import wrapper from typing_test import TypingTest def main(stdscr): stdscr.clear() stdscr.addstr("Welcome to the typing speed test") stdscr.addstr("\nPress any key to continue!") while True: typing_test = TypingTest(stdscr) stdscr.getkey() typing_test.test_wpm() stdscr.addstr( 3, 0, "Congratulations! You have completed the test! Press any key to continue...", ) stdscr.nodelay(False) key = stdscr.getkey() # Check if the key is a single character before using ord() if isinstance(key, str) and len(key) == 1: if ord(key) == 27: # ASCII value for ESC break if __name__ == "__main__": wrapper(main) ``` > 💡 注意:我們從curses `wrapper`方法內的main 函數,該函數處理curses 模組的初始化和清理。 在 main 中,我們建立**TypingTest**類別的實例並在無限循環中執行測試,這讓使用者可以繼續執行測試,直到他們決定按**ESC**退出。 讓我們看看它的實際效果。 🔥 ![打字測試演示](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0eregzw35f8yq66blja.gif) > 🫵 如果你已經做到了這一步,我想指派一個小任務給你。目前,我們正在從文件中隨機選擇文字進行輸入。我希望您從網路上**抓取**輸入文字並使用該內容。請隨意在我的儲存庫中開啟包含您的變更的拉取請求。 > 如果您需要幫助,我已經參與了一個類似的 Python 抓取專案。請隨意[檢查](https://github.com/shricodev/IPO-Monitor-NEPSE)一下。 --- **包起來!** 🐒 ---------- 到目前為止,您已經建立了一個 Python CLI 應用程式來測試您在終端機中的打字速度。 本文的記錄原始碼可在此處取得: https://github.com/shricodev/blogs/tree/main/cli-monkeytype-python 非常感謝您的閱讀! 🎉🫡 > 在下面的評論部分寫下你的想法。 👇 {% cta https://twitter.com/shricodev %} 在 Twitter 上追蹤我 🐥 {% endcta %} {% 嵌入 https://dev.to/shricodev %} --- 原文出處:https://dev.to/shricodev/build-your-own-cli-version-of-monkeytype-bm7

70 個 JavaScript 面試問題

嗨大家好,新年快樂:煙火::煙火::煙火:! ---------------------- 這是一篇很長的文章,所以請耐心聽我一秒鐘或一個小時。每個問題的每個答案都有一個向上箭頭**↑**連結,可讓您返回到問題列表,這樣您就不會浪費時間上下滾動。 ### 問題 - [1. `undefined`和`null`有什麼差別?](#1-whats-the-difference-between-undefined-and-null) - [2. &amp;&amp; 運算子的作用是什麼?](#2-what-does-the-ampamp-operator-do) - [3. || 是什麼意思?運營商做什麼?](#3-what-does-the-operator-do) - [4. 使用 + 或一元加運算子是將字串轉換為數字的最快方法嗎?](#4-is-using-the-or-unary-plus-operator-the-fastest-way-in-converting-a-string-to-a-number) - [5.什麼是DOM?](#5-what-is-the-dom) - [6.什麼是事件傳播?](#6-what-is-event-propagation) - [7.什麼是事件冒泡?](#7-whats-event-bubbling) - [8. 什麼是事件擷取?](#8-whats-event-capturing) - [9. `event.preventDefault()`和`event.stopPropagation()`方法有什麼差別?](#9-whats-the-difference-between-eventpreventdefault-and-eventstoppropagation-methods) - [10. 如何知道元素中是否使用了`event.preventDefault()`方法?](#10-how-to-know-if-the-eventpreventdefault-method-was-used-in-an-element) - [11. 為什麼這段程式碼 obj.someprop.x 會拋出錯誤?](#11-why-does-this-code-objsomepropx-throw-an-error) - \[12.什麼是`event.target` ?\](#12-什麼是 eventtarget- ) - [13.什麼是`event.currentTarget` ?](#13-what-is-eventcurrenttarget) - [14. `==`和`===`有什麼差別?](#14-whats-the-difference-between-and-) - [15. 為什麼在 JavaScript 中比較兩個相似的物件時回傳 false?](#15-why-does-it-return-false-when-comparing-two-similar-objects-in-javascript) - [16. `!!`是什麼意思?運營商做什麼?](#16-what-does-the-operator-do) - [17. 如何計算一行中的多個表達式?](#17-how-to-evaluate-multiple-expressions-in-one-line) - [18.什麼是吊裝?](#18-what-is-hoisting) - [19.什麼是範圍?](#19-what-is-scope) - [20.什麼是閉包?](#20-what-are-closures) - [21. JavaScript 中的假值是什麼?](#21-what-are-the-falsy-values-in-javascript) - [22. 如何檢查一個值是否為假值?](#22-how-to-check-if-a-value-is-falsy) - [23. `"use strict"`有什麼作用?](#23-what-does-use-strict-do) - [24. JavaScript 中`this`的值是什麼?](#24-whats-the-value-of-this-in-javascript) - [25. 物件的`prototype`是什麼?](#25-what-is-the-prototype-of-an-object) - \[26.什麼是 IIFE,它有什麼用?\](#26-what-is-an-iife-what-is-the-use-of-it ) - [27. `Function.prototype.apply`方法有什麼用?](#27-what-is-the-use-functionprototypeapply-method) - [28. `Function.prototype.call`方法有什麼用?](#28-what-is-the-use-functionprototypecall-method) - [29. `Function.prototype.apply`和`Function.prototype.call`有什麼差別?](#29-whats-the-difference-between-functionprototypeapply-and-functionprototypecall) - [30. `Function.prototype.bind`的用法是什麼?](#30-what-is-the-usage-of-functionprototypebind) - \[31.什麼是函數式程式設計以及 JavaScript 的哪些特性使其成為函數式語言的候選者?\](#31-什麼是函數式程式設計和 javascript 的特性是什麼-使其成為函數式語言的候選者 ) - [32.什麼是高階函數?](#32-what-are-higher-order-functions) - [33.為什麼函數被稱為First-class Objects?](#33-why-are-functions-called-firstclass-objects) - \[34.手動實作`Array.prototype.map`方法。\](#34-手動實作 arrayprototypemap-method ) - [35. 手動實作`Array.prototype.filter`方法。](#35-implement-the-arrayprototypefilter-method-by-hand) - [36. 手動實作`Array.prototype.reduce`方法。](#36-implement-the-arrayprototypereduce-method-by-hand) - [37.什麼是`arguments`物件?](#37-what-is-the-arguments-object) - [38. 如何創造沒有**原型的**物件?](#38-how-to-create-an-object-without-a-prototype) - [39. 為什麼當你呼叫這個函數時,這段程式碼中的`b`會變成全域變數?](#39-why-does-b-in-this-code-become-a-global-variable-when-you-call-this-function) - [40.什麼是**ECMAScript** ?](#40-what-is-ecmascript) - [41. **ES6**或**ECMAScript 2015**有哪些新功能?](#41-what-are-the-new-features-in-es6-or-ecmascript-2015) - [42. `var` 、 `let`和`const`關鍵字有什麼差別?](#42-whats-the-difference-between-var-let-and-const-keywords) - [43. 什麼是**箭頭函數**?](#43-what-are-arrow-functions) - [44.什麼是**類別**?](#44-what-are-classes) - [45.什麼是**模板文字**?](#45-what-are-template-literals) - [46.什麼是**物件解構**?](#46-what-is-object-destructuring) - [47.什麼是`ES6 Modules` ?](#47-what-are-es6-modules) - [48.什麼是`Set`物件以及它如何運作?](#48-what-is-the-set-object-and-how-does-it-work) - [49. 什麼是回呼函數?](#49-what-is-a-callback-function) - [50. 什麼是**Promise** ?](#50-what-are-promises) - [51. 什麼是*async/await*以及它是如何運作的?](#51-what-is-asyncawait-and-how-does-it-work) - [52. **Spread 運算子**和**Rest 運算**子有什麼差別?](#52-whats-the-difference-between-spread-operator-and-rest-operator) - [53. 什麼是**預設參數**?](#53-what-are-default-parameters) - [54.什麼是**包裝物件**?](#54-what-are-wrapper-objects) - [55.**隱性強制**和**顯性**強制有什麼差別?](#55-what-is-the-difference-between-implicit-and-explicit-coercion) - [56. 什麼是`NaN` ?以及如何檢查值是否為`NaN` ?](#56-what-is-nan-and-how-to-check-if-a-value-is-nan) - [57. 如何檢查一個值是否為一個**陣列**?](#57-how-to-check-if-a-value-is-an-array) - [58. 如何在不使用`%`或模運算子的情況下檢查數字是否為偶數?](#58-how-to-check-if-a-number-is-even-without-using-the-or-modulo-operator) - [59. 如何檢查物件中是否存在某個屬性?](#59-how-to-check-if-a-certain-property-exists-in-an-object) - [60.什麼是**AJAX** ?](#60-what-is-ajax) - [61. JavaScript 中建立物件的方式有哪些?](#61-what-are-the-ways-of-making-objects-in-javascript) - [62. `Object.seal`和`Object.freeze`方法有什麼不同?](#62-whats-the-difference-between-objectseal-and-objectfreeze-methods) - [63. `in`運算子和物件中的`hasOwnProperty`方法有什麼差別?](#63-whats-the-difference-between-the-in-operator-and-the-hasownproperty-method-in-objects) - [64. JavaScript中處理**非同步程式碼的**方法有哪些?](#64-what-are-the-ways-to-deal-with-asynchronous-code-in-javasscript) - [65.**函數表達式**和**函數宣告**有什麼不同?](#65-whats-the-difference-between-a-function-expression-and-function-declaration) - \[66.一個函數有多少種*呼叫*方式?\]( 66-函數可以有多少種方式被呼叫) ================= - [67. 什麼是*記憶*,它有什麼用?](#67-what-is-memoization-and-whats-the-use-it) - [68. 實現記憶輔助功能。](#68-implement-a-memoization-helper-function) - [69. 為什麼`typeof null`回傳`object` ?如何檢查一個值是否為`null` ?](#69-why-does-typeof-null-return-object-how-to-check-if-a-value-is-null) - [`new`關鍵字有什麼作用?](#70-what-does-the-new-keyword-do) ### 1. `undefined`和`null`有什麼差別? [^](#the-questions "返回問題")在了解`undefined`和`null`之間的差異之前,我們必須先了解它們之間的相似之處。 - 它們屬於**JavaScript 的**7 種基本型別。 ``` let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint']; ``` - 它們是**虛假的**價值觀。使用`Boolean(value)`或`!!value`將其轉換為布林值時計算結果為 false 的值。 ``` console.log(!!null); //logs false console.log(!!undefined); //logs false console.log(Boolean(null)); //logs false console.log(Boolean(undefined)); //logs false ``` 好吧,我們來談談差異。 - `undefined`是尚未指派特定值的變數的預設值。或一個沒有**明確**回傳值的函數。 `console.log(1)` 。或物件中不存在的屬性。 JavaScript 引擎為我們完成了**指派**`undefined`值的任務。 ``` let _thisIsUndefined; const doNothing = () => {}; const someObj = { a : "ay", b : "bee", c : "si" }; console.log(_thisIsUndefined); //logs undefined console.log(doNothing()); //logs undefined console.log(someObj["d"]); //logs undefined ``` - `null`是**「代表無值的值」** 。 `null`是已**明確**定義給變數的值。在此範例中,當`fs.readFile`方法未引發錯誤時,我們得到`null`值。 ``` fs.readFile('path/to/file', (e,data) => { console.log(e); //it logs null when no error occurred if(e){ console.log(e); } console.log(data); }); ``` 當比較`null`和`undefined`時,使用`==`時我們得到`true` ,使用`===`時得到`false` 。您可以[在此處](#14-whats-the-difference-between-and-)閱讀原因。 ``` console.log(null == undefined); // logs true console.log(null === undefined); // logs false ``` ### 2. `&&`運算子的作用是什麼? [^](#the-questions "返回問題") `&&`或**邏輯 AND**運算子在其運算元中尋找第一個*假*表達式並傳回它,如果沒有找到任何*假*表達式,則傳回最後一個表達式。它採用短路來防止不必要的工作。在我的一個專案中關閉資料庫連線時,我在`catch`區塊中使用了它。 ``` console.log(false && 1 && []); //logs false console.log(" " && true && 5); //logs 5 ``` 使用**if**語句。 ``` const router: Router = Router(); router.get('/endpoint', (req: Request, res: Response) => { let conMobile: PoolConnection; try { //do some db operations } catch (e) { if (conMobile) { conMobile.release(); } } }); ``` 使用**&amp;&amp;**運算子。 ``` const router: Router = Router(); router.get('/endpoint', (req: Request, res: Response) => { let conMobile: PoolConnection; try { //do some db operations } catch (e) { conMobile && conMobile.release() } }); ``` ### 3. `||`是什麼意思?運營商做什麼? [↑](#the-questions "返回問題") `||` or**邏輯 OR**運算子尋找其運算元中的第一個*真值*表達式並傳回它。這也採用短路來防止不必要的工作。在**ES6預設函數參數**被支援之前,它被用來初始化函數中的預設參數值。 ``` console.log(null || 1 || undefined); //logs 1 function logName(name) { var n = name || "Mark"; console.log(n); } logName(); //logs "Mark" ``` ### 4. 使用**+**或一元加運算子是將字串轉換為數字的最快方法嗎? [^](#the-questions "返回問題")根據[MDN 文件,](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus) `+`是將字串轉換為數字的最快方法,因為如果該值已經是數字,它不會對該值執行任何操作。 ### 5.什麼是**DOM** ? [^](#the-questions "返回問題") **DOM**代表**文件物件模型,**是 HTML 和 XML 文件的介面 ( **API** )。當瀏覽器第一次讀取(*解析*)我們的 HTML 文件時,它會建立一個大物件,一個基於 HTML 文件的非常大的物件,這就是**DOM** 。它是根據 HTML 文件建模的樹狀結構。 **DOM**用於互動和修改**DOM 結構**或特定元素或節點。 想像一下,如果我們有這樣的 HTML 結構。 ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document Object Model</title> </head> <body> <div> <p> <span></span> </p> <label></label> <input> </div> </body> </html> ``` 等效的**DOM**應該是這樣的。 ![DOM 等效項](https://thepracticaldev.s3.amazonaws.com/i/mbqphfbjfie45ynj0teo.png) **JavaScript**中的`document`物件代表**DOM** 。它為我們提供了許多方法,我們可以用來選擇元素來更新元素內容等等。 ### 6.什麼是**事件傳播**? [↑](#the-questions "返回問題")當某個**事件**發生在**DOM**元素上時,該**事件**並非完全發生在該元素上。在**冒泡階段**,**事件**向上冒泡,或到達其父級、祖父母、祖父母的父級,直到一直到達`window` ,而在**捕獲階段**,事件從`window`開始向下到達觸發的元素事件或`<a href="#12-what-is-eventtarget-">event.target</a>` 。 **事件傳播**分為**三個**階段。 1. [捕獲階段](#8-whats-event-capturing)-事件從`window`開始,然後向下到達每個元素,直到到達目標元素。 2. [目標階段](#12-what-is-eventtarget-)– 事件已到達目標元素。 3. [冒泡階段](#7-whats-event-bubbling)-事件從目標元素冒起,然後向上移動到每個元素,直到到達`window` 。 ![事件傳播](https://thepracticaldev.s3.amazonaws.com/i/hjayqa99iejfhbsujlqd.png) ### 7.什麼是**事件冒泡**? [↑](#the-questions "返回問題")當某個**事件**發生在**DOM**元素上時,該**事件**並非完全發生在該元素上。在**冒泡階段**,**事件**向上冒泡,或到達其父級、祖父母、祖父母的父級,直到一直到達`window` 。 如果我們有一個像這樣的範例標記。 ``` <div class="grandparent"> <div class="parent"> <div class="child">1</div> </div> </div> ``` 還有我們的js程式碼。 ``` function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); } addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent'); addEvent(child, 'click', function (e) { console.log('child'); }); addEvent(parent, 'click', function (e) { console.log('parent'); }); addEvent(grandparent, 'click', function (e) { console.log('grandparent'); }); addEvent(document, 'click', function (e) { console.log('document'); }); addEvent('html', 'click', function (e) { console.log('html'); }) addEvent(window, 'click', function (e) { console.log('window'); }) }); ``` `addEventListener`方法有第三個可選參數**useCapture ,**預設值為`false`事件將在**冒泡階段**發生,如果為`true` ,事件將在**捕獲階段**發生。如果我們點擊`child`元素,它會分別在**控制台**上記錄`child` 、 `parent`元素、 `grandparent` 、 `html` 、 `document`和`window` 。這就是**事件冒泡**。 ### 8. 什麼是**事件擷取**? [↑](#the-questions "返回問題")當某個**事件**發生在**DOM**元素上時,該**事件**並非完全發生在該元素上。在**捕獲階段**,事件從`window`開始一直到觸發事件的元素。 如果我們有一個像這樣的範例標記。 ``` <div class="grandparent"> <div class="parent"> <div class="child">1</div> </div> </div> ``` 還有我們的js程式碼。 ``` function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); } addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent'); addEvent(child, 'click', function (e) { console.log('child'); }, true); addEvent(parent, 'click', function (e) { console.log('parent'); }, true); addEvent(grandparent, 'click', function (e) { console.log('grandparent'); }, true); addEvent(document, 'click', function (e) { console.log('document'); }, true); addEvent('html', 'click', function (e) { console.log('html'); }, true) addEvent(window, 'click', function (e) { console.log('window'); }, true) }); ``` `addEventListener`方法有第三個可選參數**useCapture ,**預設值為`false`事件將在**冒泡階段**發生,如果為`true` ,事件將在**捕獲階段**發生。如果我們點擊`child`元素,它會分別在**控制台**上記錄`window` 、 `document` 、 `html` 、 `grandparent` 、 `parent`和`child` 。這就是**事件捕獲**。 ### 9. `event.preventDefault()`和`event.stopPropagation()`方法有什麼差別? [↑](#the-questions "返回問題") `event.preventDefault()`方法**阻止**元素的預設行為。如果在`form`元素中使用,它**會阻止**其提交。如果在`anchor`元素中使用,它**會阻止**其導航。如果在`contextmenu`中使用,它**會阻止**其顯示或顯示。而`event.stopPropagation()`方法會停止事件的傳播或停止事件在[冒泡](#7-whats-event-bubbling)或[捕獲](#8-whats-event-capturing)階段發生。 ### 10. 如何知道元素中是否使用了`event.preventDefault()`方法? [↑](#the-questions "返回問題")我們可以使用事件物件中的`event.defaultPrevented`屬性。它傳回一個`boolean` ,指示是否在特定元素中呼叫了`event.preventDefault()` 。 ### 11. 為什麼這段程式碼`obj.someprop.x`會拋出錯誤? ``` const obj = {}; console.log(obj.someprop.x); ``` [^](#the-questions "返回問題")顯然,由於我們嘗試存取 a 的原因,這會引發錯誤 `someprop`屬性中的`x`屬性具有`undefined`值。請記住,物件中的**屬性**本身並不存在,且其**原型**具有預設值`undefined`且`undefined`沒有屬性`x` 。 ### 12.什麼是**event.target** ? [↑](#the-questions "返回問題")最簡單來說, **event.target**是**發生**事件的元素或**觸發**事件的元素。 HTML 標記範例。 ``` <div onclick="clickFunc(event)" style="text-align: center;margin:15px; border:1px solid red;border-radius:3px;"> <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;"> <div style="margin:25px;border:1px solid skyblue;border-radius:3px;"> <button style="margin:10px"> Button </button> </div> </div> </div> ``` JavaScript 範例。 ``` function clickFunc(event) { console.log(event.target); } ``` 如果您單擊按鈕,它會記錄**按鈕**標記,即使我們將事件附加在最外部的`div`上,它也會始終記錄**按鈕**,因此我們可以得出結論, **event.target**是觸發事件的元素。 ### 13.什麼是**event.currentTarget** ? [↑](#the-questions "返回問題") **event.currentTarget**是我們**明確**附加事件處理程序的元素。 複製**問題 12**中的標記。 HTML 標記範例。 ``` <div onclick="clickFunc(event)" style="text-align: center;margin:15px; border:1px solid red;border-radius:3px;"> <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;"> <div style="margin:25px;border:1px solid skyblue;border-radius:3px;"> <button style="margin:10px"> Button </button> </div> </div> </div> ``` 並且稍微改變我們的**JS** 。 ``` function clickFunc(event) { console.log(event.currentTarget); } ``` 如果您按一下該按鈕,即使我們按一下該按鈕,它也會記錄最外層的**div**標記。在此範例中,我們可以得出結論, **event.currentTarget**是我們附加事件處理程序的元素。 ### 14. `==`和`===`有什麼差別? [^](#the-questions "返回問題") `==` \_\_(抽象相等)\_\_ 和`===` \_\_(嚴格相等)\_\_ 之間的區別在於`==`在*強制轉換*後按**值**進行比較,而`===`在不進行*強制轉換的*情況下按**值**和**類型**進行比較。 讓我們更深入地研究`==` 。那麼首先我們來談談*強制*。 *強制轉換*是將一個值轉換為另一種類型的過程。在本例中, `==`進行*隱式強制轉換*。在比較兩個值之前, `==`需要執行一些條件。 假設我們必須比較`x == y`值。 1. 如果`x`和`y`具有相同的類型。 然後將它們與`===`運算子進行比較。 2. 如果`x`為`null`且`y` `undefined` ,則傳回`true` 。 3. 如果`x` `undefined`且`y`為`null`則傳回`true` 。 4. 如果`x`是`number`類型, `y`是`string`類型 然後回傳`x == toNumber(y)` 。 5. 如果`x`是`string`類型, `y`是`number`類型 然後返回`toNumber(x) == y` 。 6. 如果`x`是`boolean`類型 然後返回`toNumber(x) == y` 。 7. 如果`y`是`boolean`類型 然後回傳`x == toNumber(y)` 。 8. 如果`x`是`string` 、 `symbol`或`number`且`y`是 type `object` 然後回傳`x == toPrimitive(y)` 。 9. 如果`x`是`object`且`x`是`string` 、 `symbol` 然後返回`toPrimitive(x) == y` 。 10. 返回`false` 。 **注意:** `toPrimitive`首先使用物件中的`valueOf`方法,然後使用`toString`方法來取得該物件的原始值。 讓我們舉個例子。 | `x` | `y` | `x == y` | | ------------- |:-------------:| ----------------: | | `5` | `5` | `true` | | `1` | `'1'` | `true` | | `null` | `undefined` | `true` | | `0` | `false` | `true` | | `'1,2'` | `[1,2]` | `true` | | `'[object Object]'` | `{}` | `true` | 這些範例都傳回`true` 。 **第一個範例**屬於**條件一**,因為`x`和`y`具有相同的類型和值。 **第二個範例**轉到**條件四,**在比較之前將`y`轉換為`number` 。 **第三個例子**涉及**條件二**。 **第四個範例**轉到**條件七,**因為`y`是`boolean` 。 **第五個範例**適用於**條件八**。使用`toString()`方法將陣列轉換為`string` ,該方法傳回`1,2` 。 **最後一個例子**適用於**條件十**。使用傳回`[object Object]`的`toString()`方法將該物件轉換為`string` 。 | `x` | `y` | `x === y` | | ------------- |:-------------:| ----------------: | | `5` | `5` | `true` | | `1` | `'1'` | `false` | | `null` | `undefined` | `false` | | `0` | `false` | `false` | | `'1,2'` | `[1,2]` | `false` | | `'[object Object]'` | `{}` | `false` | 如果我們使用`===`運算符,則除第一個範例之外的所有比較都將傳回`false` ,因為它們不具有相同的類型,而第一個範例將傳回`true` ,因為兩者俱有相同的類型和值。 ### 15. 為什麼在 JavaScript 中比較兩個相似的物件時回傳**false** ? [^](#the-questions "返回問題")假設我們有下面的例子。 ``` let a = { a: 1 }; let b = { a: 1 }; let c = a; console.log(a === b); // logs false even though they have the same property console.log(a === c); // logs true hmm ``` **JavaScript**以不同的方式比較*物件*和*基元*。在*基元*中,它透過**值**來比較它們,而在*物件*中,它透過**引用**或**儲存變數的記憶體位址**來比較它們。這就是為什麼第一個`console.log`語句回傳`false`而第二個`console.log`語句回傳`true`的原因。 `a`和`c`有相同的引用,而`a`和`b`則不同。 ### 16. **!!**是什麼意思?運營商做什麼? [↑](#the-questions "返回問題")**雙非**運算子或**!!**將右側的值強制轉換為布林值。基本上,這是一種將值轉換為布林值的奇特方法。 ``` console.log(!!null); //logs false console.log(!!undefined); //logs false console.log(!!''); //logs false console.log(!!0); //logs false console.log(!!NaN); //logs false console.log(!!' '); //logs true console.log(!!{}); //logs true console.log(!![]); //logs true console.log(!!1); //logs true console.log(!![].length); //logs false ``` ### 17. 如何計算一行中的多個表達式? [↑](#the-questions "返回問題")我們可以使用`,`或逗號運算子來計算一行中的多個表達式。它從左到右計算並傳回右側最後一項或最後一個操作數的值。 ``` let x = 5; x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10); function addFive(num) { return num + 5; } ``` 如果記錄`x`的值,它將是**27** 。首先,我們**增加**x 的值,它將是**6** ,然後我們呼叫函數`addFive(6)`並將 6 作為參數傳遞,並將結果分配給`x` , `x`的新值將是**11** 。之後,我們將`x`的當前值乘以**2**並將其分配給`x` , `x`的更新值將是**22** 。然後,我們將`x`的當前值減去 5 並將結果指派給`x` ,更新後的值將是**17** 。最後,我們將`x`的值增加 10 並將更新後的值指派給`x` ,現在`x`的值將是**27** 。 ### 18.什麼是**吊裝**? [^](#the-questions "返回問題")**提升**是一個術語,用於描述將*變數*和*函數*移動到其*(全域或函數)*作用域的頂部(即我們定義該變數或函數的位置)。 要理解**提升**,我必須解釋*執行上下文*。 **執行上下文**是目前正在執行的「程式碼環境」。**執行上下文**有兩個階段*:編譯*和*執行*。 **編譯**- 在此階段,它獲取所有*函數聲明*並將它們*提升*到作用域的頂部,以便我們稍後可以引用它們並獲取所有*變數聲明***(使用 var 關鍵字聲明)** ,並將它們*提升*並給它們一個默認值*未定義*的 . **執行**- 在此階段,它將值指派給先前*提升的*變數,並*執行*或*呼叫*函數**(物件中的方法)** 。 **注意:**只有使用*var*關鍵字宣告的**函數宣告**和變數才會*被提升*,而不是**函數表達式**或**箭頭函數**、 `let`和`const`關鍵字。 好吧,假設我們在下面的*全域範圍*內有一個範例程式碼。 ``` console.log(y); y = 1; console.log(y); console.log(greet("Mark")); function greet(name){ return 'Hello ' + name + '!'; } var y; ``` 此程式碼記錄`undefined` , `1` , `Hello Mark!`分別。 所以*編譯*階段看起來像這樣。 ``` function greet(name) { return 'Hello ' + name + '!'; } var y; //implicit "undefined" assignment //waiting for "compilation" phase to finish //then start "execution" phase /* console.log(y); y = 1; console.log(y); console.log(greet("Mark")); */ ``` 出於範例目的,我對變數和*函數呼叫*的*賦值*進行了評論。 *編譯*階段完成後,它開始*執行*階段,呼叫方法並向變數賦值。 ``` function greet(name) { return 'Hello ' + name + '!'; } var y; //start "execution" phase console.log(y); y = 1; console.log(y); console.log(greet("Mark")); ``` ### 19.什麼是**範圍**? [↑](#the-questions "返回問題") JavaScript 中的**作用域**是我們可以有效存取變數或函數的**區域**。 JavaScript 有三種類型的作用域。**全域作用域**、**函數作用域**和**區塊作用域(ES6)** 。 - **全域作用域**- 在全域命名空間中宣告的變數或函數位於全域作用域中,因此可以在程式碼中的任何位置存取。 ``` //global namespace var g = "global"; function globalFunc(){ function innerFunc(){ console.log(g); // can access "g" because "g" is a global variable } innerFunc(); } ``` - **函數作用域**- 函數內聲明的變數、函數和參數可以在該函數內部存取,但不能在函數外部存取。 ``` function myFavoriteFunc(a) { if (true) { var b = "Hello " + a; } return b; } myFavoriteFunc("World"); console.log(a); // Throws a ReferenceError "a" is not defined console.log(b); // does not continue here ``` - **區塊作用域**- 在區塊`{}`內宣告的變數**( `let` 、 `const` )**只能在區塊內存取。 ``` function testBlock(){ if(true){ let z = 5; } return z; } testBlock(); // Throws a ReferenceError "z" is not defined ``` **範圍**也是一組查找變數的規則。如果一個變數在**當前作用域中**不存在,它會在**外部作用域中查找**並蒐索該變數,如果不存在,它會再次**查找,**直到到達**全域作用域。**如果該變數存在,那麼我們可以使用它,如果不存在,我們可以使用它來拋出錯誤。它搜尋**最近的**變數,一旦找到它就停止**搜尋**或**尋找**。這稱為**作用域鏈**。 ``` /* Scope Chain Inside inner function perspective inner's scope -> outer's scope -> global's scope */ //Global Scope var variable1 = "Comrades"; var variable2 = "Sayonara"; function outer(){ //outer's scope var variable1 = "World"; function inner(){ //inner's scope var variable2 = "Hello"; console.log(variable2 + " " + variable1); } inner(); } outer(); // logs Hello World // because (variable2 = "Hello") and (variable1 = "World") are the nearest // variables inside inner's scope. ``` ![範圍](https://thepracticaldev.s3.amazonaws.com/i/l81b3nmdonimex0qsgyr.png) ### 20.什麼是**閉包**? [^](#the-questions "返回問題")這可能是所有這些問題中最難的問題,因為**閉包**是一個有爭議的話題。那我就從我的理解來解釋。 **閉包**只是函數在宣告時記住其當前作用域、其父函數作用域、其父函數的父函數作用域上的變數和參數的引用的能力,直到在**作用域鏈**的幫助下到達全域作用域。基本上它是聲明函數時建立的**作用域**。 例子是解釋閉包的好方法。 ``` //Global's Scope var globalVar = "abc"; function a(){ //testClosures's Scope console.log(globalVar); } a(); //logs "abc" /* Scope Chain Inside a function perspective a's scope -> global's scope */ ``` 在此範例中,當我們宣告`a`函數時**,全域**作用域是`a's`*閉包*的一部分。 ![a的閉包](https://thepracticaldev.s3.amazonaws.com/i/teatokuw4xvgtlzbzhn8.png) 變數`globalVar`在影像中沒有值的原因是該變數的值可以根據我們呼叫`a`**位置**和**時間**而改變。 但在上面的範例中, `globalVar`變數的值為**abc** 。 好吧,讓我們來看一個複雜的例子。 ``` var globalVar = "global"; var outerVar = "outer" function outerFunc(outerParam) { function innerFunc(innerParam) { console.log(globalVar, outerParam, innerParam); } return innerFunc; } const x = outerFunc(outerVar); outerVar = "outer-2"; globalVar = "guess" x("inner"); ``` ![複雜的](https://thepracticaldev.s3.amazonaws.com/i/e4hxm7zvz8eun2ppenwp.png) 這將列印“猜測外部內部”。對此的解釋是,當我們呼叫`outerFunc`函數並將`innerFunc`函數的回傳值指派給變數`x`時,即使我們將新值**outer-2**指派給`outerVar`變數, `outerParam`也會具有**outer**值,因為 重新分配發生在呼叫`outer`函數之後,當我們呼叫`outerFunc`函數時,它會在**作用域鏈**中尋找`outerVar`的值,而`outerVar`的值為**「outer」** 。現在,當我們呼叫引用了`innerFunc`的`x`變數時, `innerParam`的值為**inner,**因為這是我們在呼叫中傳遞的值,而`globalVar`變數的值為**猜測**,因為在呼叫`x`變數之前,我們為`globalVar`分配了一個新值,並且在呼叫`x`時**作用域鏈**中`globalVar`的值是**猜測**。 我們有一個例子來示範沒有正確理解閉包的問題。 ``` const arrFuncs = []; for(var i = 0; i < 5; i++){ arrFuncs.push(function (){ return i; }); } console.log(i); // i is 5 for (let i = 0; i < arrFuncs.length; i++) { console.log(arrFuncs[i]()); // all logs "5" } ``` 由於**Closures**的原因,此程式碼無法按我們的預期工作。 `var`關鍵字建立一個全域變數,當我們推送一個函數時 我們返回全域變數`i` 。因此,當我們在循環之後呼叫該陣列中的其中一個函數時,它會記錄`5` ,因為我們得到 `i`的目前值為`5` ,我們可以存取它,因為它是全域變數。因為**閉包**保留該變數的**引用,**而不是其建立時的**值**。我們可以使用**IIFES**或將`var`關鍵字變更為`let`來解決此問題,以實現區塊作用域。 ### 21. **JavaScript**中的**假**值是什麼? [↑](#the-questions "返回問題") ``` const falsyValues = ['', 0, null, undefined, NaN, false]; ``` **假**值是轉換為布林值時變成**false 的**值。 ### 22. 如何檢查一個值是否為**假值**? [↑](#the-questions "返回問題")使用**布林**函數或雙非運算符**[!!](#16-what-does-the-operator-do)** ### 23. `"use strict"`有什麼作用? [^](#the-questions "返回問題") `"use strict"`是**JavaScript**中的 ES5 功能,它使我們的程式碼在*函數*或*整個腳本*中處於**嚴格模式**。**嚴格模式**幫助我們避免程式碼早期出現**錯誤**並為其加入限制。 **嚴格模式**給我們的限制。 - 分配或存取未宣告的變數。 ``` function returnY(){ "use strict"; y = 123; return y; } ``` - 為唯讀或不可寫的全域變數賦值; ``` "use strict"; var NaN = NaN; var undefined = undefined; var Infinity = "and beyond"; ``` - 刪除不可刪除的屬性。 ``` "use strict"; const obj = {}; Object.defineProperty(obj, 'x', { value : '1' }); delete obj.x; ``` - 參數名稱重複。 ``` "use strict"; function someFunc(a, b, b, c){ } ``` - 使用**eval**函數建立變數。 ``` "use strict"; eval("var x = 1;"); console.log(x); //Throws a Reference Error x is not defined ``` - **該**值的預設值是`undefined` 。 ``` "use strict"; function showMeThis(){ return this; } showMeThis(); //returns undefined ``` **嚴格模式**的限制遠不止這些。 ### 24. JavaScript 中`this`的值是什麼? [↑](#the-questions "返回問題")基本上, `this`是指目前正在執行或呼叫函數的物件的值。我說**目前**是因為**它**的值會根據我們使用它的上下文和使用它的位置而改變。 ``` const carDetails = { name: "Ford Mustang", yearBought: 2005, getName(){ return this.name; }, isRegistered: true }; console.log(carDetails.getName()); // logs Ford Mustang ``` 這是我們通常所期望的,因為在**getName**方法中我們傳回`this.name` ,在此上下文中`this`指的是`carDetails`物件,該物件目前是正在執行的函數的「擁有者」物件。 好吧,讓我們加入一些程式碼讓它變得奇怪。在`console.log`語句下面加入這三行程式碼 ``` var name = "Ford Ranger"; var getCarName = carDetails.getName; console.log(getCarName()); // logs Ford Ranger ``` 第二個`console.log`語句印製了**「Ford Ranger」**一詞,這很奇怪,因為在我們的第一個`console.log`語句中它印了**「Ford Mustang」** 。原因是`getCarName`方法有一個不同的「擁有者」物件,即`window`物件。在全域作用域中使用`var`關鍵字聲明變數會在`window`物件中附加與變數同名的屬性。請記住,當未使用`"use strict"`時,全域範圍內的`this`指的是`window`物件。 ``` console.log(getCarName === window.getCarName); //logs true console.log(getCarName === this.getCarName); // logs true ``` 本例中的`this`和`window`指的是同一個物件。 解決此問題的一種方法是使用函數中的`<a href="#27-what-is-the-use-functionprototypeapply-method">apply</a>`和`<a href="#28-what-is-the-use-functionprototypecall-method">call</a>`方法。 ``` console.log(getCarName.apply(carDetails)); //logs Ford Mustang console.log(getCarName.call(carDetails)); //logs Ford Mustang ``` `apply`和`call`方法期望第一個參數是一個物件,該物件將是該函數內`this`的值。 **IIFE** (即**立即呼叫函數表達式)** 、在全域作用域中宣告的函數、物件內部方法中的**匿名函數**和內部函數都有一個指向**window**物件的預設**值**。 ``` (function (){ console.log(this); })(); //logs the "window" object function iHateThis(){ console.log(this); } iHateThis(); //logs the "window" object const myFavoriteObj = { guessThis(){ function getThis(){ console.log(this); } getThis(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); } }; myFavoriteObj.guessThis(); //logs the "window" object myFavoriteObj.thisIsAnnoying(function (){ console.log(this); //logs the "window" object }); ``` 如果我們想要取得`myFavoriteObj`物件中的`name`屬性**(Marko Polo)**的值,有兩種方法可以解決這個問題。 首先,我們將`this`的值保存在變數中。 ``` const myFavoriteObj = { guessThis(){ const self = this; //saves the this value to the "self" variable function getName(){ console.log(self.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); } }; ``` 在此圖像中,我們保存`this`的值,該值將是`myFavoriteObj`物件。所以我們可以在`getName`內部函數中存取它。 其次,我們使用**ES6[箭頭函數](#43-what-are-arrow-functions)**。 ``` const myFavoriteObj = { guessThis(){ const getName = () => { //copies the value of "this" outside of this arrow function console.log(this.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); } }; ``` [箭頭函數](#43-what-are-arrow-functions)沒有自己的`this` 。它複製封閉詞法範圍的`this`值,或複製`getName`內部函數外部的`this`值(即`myFavoriteObj`物件)。我們也可以根據[函數的呼叫方式](#66-how-many-ways-can-a-function-be-invoked)來決定`this`的值。 ### 25. 物件的`prototype`是什麼? [↑](#the-questions "返回問題")最簡單的`prototype`是一個物件的*藍圖*。如果目前物件中確實存在它,則將其用作**屬性**和**方法**的後備。這是在物件之間共享屬性和功能的方式。這是 JavaScript**原型繼承**的核心概念。 ``` const o = {}; console.log(o.toString()); // logs [object Object] ``` 即使`o.toString`方法不存在於`o`物件中,它也不會拋出錯誤,而是傳回字串`[object Object]` 。當物件中不存在屬性時,它會尋找其**原型**,如果仍然不存在,則會尋找**原型的原型**,依此類推,直到在**原型鏈**中找到具有相同屬性的屬性。**原型鏈**的末尾在**Object.prototype**之後為`null` 。 ``` console.log(o.toString === Object.prototype.toString); // logs true // which means we we're looking up the Prototype Chain and it reached // the Object.prototype and used the "toString" method. ``` ### 26. 什麼是**IIFE** ,它有什麼用? [^](#the-questions "返回問題") **IIFE**或**立即呼叫函數表達式**是在建立或宣告後將被呼叫或執行的函數。建立**IIFE**的語法是,我們將`function (){}`包裝在括號`()`或**分組運算**子內,以將函數視為表達式,然後用另一個括號`()`呼叫它。所以**IIFE**看起來像這樣`(function(){})()` 。 ``` (function () { }()); (function () { })(); (function named(params) { })(); (() => { })(); (function (global) { })(window); const utility = (function () { return { //utilities }; })(); ``` 這些範例都是有效的**IIFE** 。倒數第二個範例顯示我們可以將參數傳遞給**IIFE**函數。最後一個範例表明我們可以將**IIFE**的結果保存到變數中,以便稍後引用它。 **IIFE**的最佳用途是進行初始化設定功能,並避免與全域範圍內的其他變數**發生命名衝突**或污染全域名稱空間。讓我們舉個例子。 ``` <script src="https://cdnurl.com/somelibrary.js"></script> ``` 假設我們有一個指向庫`somelibrary.js`的連結,該庫公開了我們可以在程式碼中使用的一些全域函數,但該庫有兩個我們不使用`createGraph`和`drawGraph`方法,因為這些方法中有錯誤。我們想要實作我們自己的`createGraph`和`drawGraph`方法。 - 解決這個問題的一種方法是改變腳本的結構。 ``` <script src="https://cdnurl.com/somelibrary.js"></script> <script> function createGraph() { // createGraph logic here } function drawGraph() { // drawGraph logic here } </script> ``` 當我們使用這個解決方案時,我們將覆蓋庫為我們提供的這兩種方法。 - 解決這個問題的另一種方法是更改我們自己的輔助函數的名稱。 ``` <script src="https://cdnurl.com/somelibrary.js"></script> <script> function myCreateGraph() { // createGraph logic here } function myDrawGraph() { // drawGraph logic here } </script> ``` 當我們使用此解決方案時,我們還將這些函數呼叫更改為新函數名稱。 - 另一種方法是使用**IIFE** 。 ``` <script src="https://cdnurl.com/somelibrary.js"></script> <script> const graphUtility = (function () { function createGraph() { // createGraph logic here } function drawGraph() { // drawGraph logic here } return { createGraph, drawGraph } })(); </script> ``` 在此解決方案中,我們建立一個實用程式變數,它是**IIFE**的結果,它傳回一個包含`createGraph`和`drawGraph`兩個方法的物件。 **IIFE**解決的另一個問題就是這個例子。 ``` var li = document.querySelectorAll('.list-group > li'); for (var i = 0, len = li.length; i < len; i++) { li[i].addEventListener('click', function (e) { console.log(i); }) } ``` 假設我們有一個`ul`元素,其類別為**list-group** ,並且它有 5 個`li`子元素。當我們**點擊**單一`li`元素時,我們希望`console.log` `i`的值。 但我們想要的程式碼中的行為不起作用。相反,它會在對`li`元素的任何**點擊**中記錄`5` 。我們遇到的問題是由於**閉包的**工作方式造成的。**閉包**只是函數記住其當前作用域、其父函數作用域和全域作用域中的變數引用的能力。當我們在全域範圍內使用`var`關鍵字聲明變數時,顯然我們正在建立一個全域變數`i` 。因此,當我們單擊`li`元素時,它會記錄**5** ,因為這是我們稍後在回調函數中引用它時的`i`值。 - 解決這個問題的一種方法是**IIFE** 。 ``` var li = document.querySelectorAll('.list-group > li'); for (var i = 0, len = li.length; i < len; i++) { (function (currentIndex) { li[currentIndex].addEventListener('click', function (e) { console.log(currentIndex); }) })(i); } ``` 這個解決方案之所以有效,是因為**IIFE**為每次迭代建立一個新範圍,並且我們捕獲`i`的值並將其傳遞到`currentIndex`參數中,因此當我們呼叫**IIFE**時,每次迭代的`currentIndex`值都是不同的。 ### 27. `Function.prototype.apply`方法有什麼用? [^](#the-questions "返回問題") `apply`呼叫一個函數,在呼叫時指定`this`或該函數的「所有者」物件。 ``` const details = { message: 'Hello World!' }; function getMessage(){ return this.message; } getMessage.apply(details); // returns 'Hello World!' ``` 這個方法的工作方式類似於`<a href="#28-what-is-the-use-functionprototypecall-method">Function.prototype.call</a>`唯一的差異是我們傳遞參數的方式。在`apply`中,我們將參數作為陣列傳遞。 ``` const person = { name: "Marko Polo" }; function greeting(greetingMessage) { return `${greetingMessage} ${this.name}`; } greeting.apply(person, ['Hello']); // returns "Hello Marko Polo!" ``` ### 28. `Function.prototype.call`方法有什麼用? [^](#the-questions "返回問題")此`call`呼叫一個函數,指定呼叫時該函數的`this`或「擁有者」物件。 ``` const details = { message: 'Hello World!' }; function getMessage(){ return this.message; } getMessage.call(details); // returns 'Hello World!' ``` 這個方法的工作方式類似於`<a href="#27-what-is-the-use-functionprototypeapply-method">Function.prototype.apply</a>`唯一的差異是我們傳遞參數的方式。在`call`中,我們直接傳遞參數,對於每個參數`,`用逗號分隔它們。 ``` const person = { name: "Marko Polo" }; function greeting(greetingMessage) { return `${greetingMessage} ${this.name}`; } greeting.call(person, 'Hello'); // returns "Hello Marko Polo!" ``` ### 29. `Function.prototype.apply`和`Function.prototype.call`有什麼差別? [↑](#the-questions "返回問題") `apply`和`call`之間的唯一區別是我們如何在被呼叫的函數中傳遞**參數**。在`apply`中,我們將參數作為**陣列**傳遞,而在`call`中,我們直接在參數列表中傳遞參數。 ``` const obj1 = { result:0 }; const obj2 = { result:0 }; function reduceAdd(){ let result = 0; for(let i = 0, len = arguments.length; i < len; i++){ result += arguments[i]; } this.result = result; } reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // returns 15 reduceAdd.call(obj2, 1, 2, 3, 4, 5); // returns 15 ``` ### 30. `Function.prototype.bind`的用法是什麼? [↑](#the-questions "返回問題") `bind`方法傳回一個新*綁定的*函數 到特定的`this`值或“所有者”物件,因此我們可以稍後在程式碼中使用它。 `call` 、 `apply`方法立即呼叫函數,而不是像`bind`方法那樣傳回一個新函數。 ``` import React from 'react'; class MyComponent extends React.Component { constructor(props){ super(props); this.state = { value : "" } this.handleChange = this.handleChange.bind(this); // Binds the "handleChange" method to the "MyComponent" component } handleChange(e){ //do something amazing here } render(){ return ( <> <input type={this.props.type} value={this.state.value} onChange={this.handleChange} /> </> ) } } ``` ### 31.什麼是**函數式程式設計**? **JavaScript**的哪些特性使其成為**函數式語言**的候選者? [^](#the-questions "返回問題")**函數式程式設計**是一種**聲明式**程式設計範式或模式,它介紹如何**使用表達式來**計算值而不改變傳遞給它的參數的函數來建立應用程式。 JavaScript**陣列**具有**map** 、 **filter** 、 **reduce**方法,這些方法是函數式程式設計世界中最著名的函數,因為它們非常有用,而且它們不會改變或改變陣列,這使得這些函數變得**純粹**,並且JavaScript 支援**閉包**和**高階函數**,它們是**函數式程式語言**的一個特徵。 - **map**方法建立一個新陣列,其中包含對陣列中每個元素呼叫提供的回調函數的結果。 ``` const words = ["Functional", "Procedural", "Object-Oriented"]; const wordsLength = words.map(word => word.length); ``` - **filter**方法會建立一個新陣列,其中包含透過回調函數中測試的所有元素。 ``` const data = [ { name: 'Mark', isRegistered: true }, { name: 'Mary', isRegistered: false }, { name: 'Mae', isRegistered: true } ]; const registeredUsers = data.filter(user => user.isRegistered); ``` - **reduce**方法對累加器和陣列中的每個元素(從左到右)套用函數,將其減少為單一值。 ``` const strs = ["I", " ", "am", " ", "Iron", " ", "Man"]; const result = strs.reduce((acc, currentStr) => acc + currentStr, ""); ``` ### 32.什麼是**高階函數**? [^](#the-questions "返回問題")**高階函數**是可以傳回函數或接收具有函數值的一個或多個參數的函數。 ``` function higherOrderFunction(param,callback){ return callback(param); } ``` ### 33.為什麼函數被稱為**First-class Objects** ? [^](#the-questions "返回問題") JavaScript 中的 \_\_Functions\_\_ 是**一流物件**,因為它們被視為該語言中的任何其他值。它們可以分配給**變數**,可以是稱為**方法的物件的屬性**,可以是**陣列中的專案**,可以**作為參數傳遞給函數**,也可以**作為函數的值返回**。函數與**JavaScript**中任何其他值之間的唯一區別是**函數**可以被呼叫。 ### 34. 手動實作`Array.prototype.map`方法。 [↑](#the-questions "返回問題") ``` function map(arr, mapCallback) { // First, we check if the parameters passed are right. if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== 'function') { return []; } else { let result = []; // We're making a results array every time we call this function // because we don't want to mutate the original array. for (let i = 0, len = arr.length; i < len; i++) { result.push(mapCallback(arr[i], i, arr)); // push the result of the mapCallback in the 'result' array } return result; // return the result array } } ``` 正如`Array.prototype.map`方法的MDN描述。 **map() 方法建立一個新陣列,其中包含對呼叫陣列中的每個元素呼叫所提供函數的結果。** ### 35. 手動實作`Array.prototype.filter`方法。 [↑](#the-questions "返回問題") ``` function filter(arr, filterCallback) { // First, we check if the parameters passed are right. if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function') { return []; } else { let result = []; // We're making a results array every time we call this function // because we don't want to mutate the original array. for (let i = 0, len = arr.length; i < len; i++) { // check if the return value of the filterCallback is true or "truthy" if (filterCallback(arr[i], i, arr)) { // push the current item in the 'result' array if the condition is true result.push(arr[i]); } } return result; // return the result array } } ``` 正如`Array.prototype.filter`方法的 MDN 描述。 **filter() 方法建立一個新陣列,其中包含透過所提供函數實現的測試的所有元素。** ### 36. 手動實作`Array.prototype.reduce`方法。 [↑](#the-questions "返回問題") ``js 函數reduce(arr,reduceCallback,initialValue){ // 首先,我們檢查傳遞的參數是否正確。 if (!Array.isArray(arr) || !arr.length || typeof reduceCallback !== 'function') { ``` return []; ``` } 別的 { ``` // If no initialValue has been passed to the function we're gonna use the ``` ``` let hasInitialValue = initialValue !== undefined; ``` ``` let value = hasInitialValue ? initialValue : arr[0]; ``` ``` // first array item as the initialValue ``` ``` // Then we're gonna start looping at index 1 if there is no ``` ``` // initialValue has been passed to the function else we start at 0 if ``` ``` // there is an initialValue. ``` ``` for (let i = hasInitialValue ? 0 : 1, len = arr.length; i < len; i++) { ``` ``` // Then for every iteration we assign the result of the ``` ``` // reduceCallback to the variable value. ``` ``` value = reduceCallback(value, arr[i], i, arr); ``` ``` } ``` ``` return value; ``` } } ``` As the MDN description of the <code>Array.prototype.reduce</code> method. __The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.__ ###37. What is the __arguments__ object? [&uarr;](#the-questions "Back To Questions") The __arguments__ object is a collection of parameter values pass in a function. It's an __Array-like__ object because it has a __length__ property and we can access individual values using array indexing notation <code>arguments[1]</code> but it does not have the built-in methods in an array <code>forEach</code>,<code>reduce</code>,<code>filter</code> and <code>map</code>. It helps us know the number of arguments pass in a function. We can convert the <code>arguments</code> object into an array using the <code>Array.prototype.slice</code>. ``` 函數一(){ 返回 Array.prototype.slice.call(參數); } ``` Note: __the <code>arguments</code> object does not work on ES6 arrow functions.__ ``` 函數一(){ 返回參數; } 常數二 = 函數 () { 返回參數; } 常量三 = 函數三() { 返回參數; } const 四 = () =&gt; 參數; 四(); // 拋出錯誤 - 參數未定義 ``` When we invoke the function <code>four</code> it throws a <code>ReferenceError: arguments is not defined</code> error. We can solve this problem if your enviroment supports the __rest syntax__. ``` const 四 = (...args) =&gt; args; ``` This puts all parameter values in an array automatically. ###38. How to create an object without a __prototype__? [&uarr;](#the-questions "Back To Questions") We can create an object without a _prototype_ using the <code>Object.create</code> method. ``` 常數 o1 = {}; console.log(o1.toString()); // Logs \[object Object\] 取得此方法到Object.prototype const o2 = Object.create(null); // 第一個參數是物件「o2」的原型,在此 // case 將為 null 指定我們不需要任何原型 console.log(o2.toString()); // 拋出錯誤 o2.toString 不是函數 ``` ###39. Why does <code>b</code> in this code become a global variable when you call this function? [&uarr;](#the-questions "Back To Questions") ``` 函數 myFunc() { 令a = b = 0; } myFunc(); ``` The reason for this is that __assignment operator__ or __=__ has right-to-left __associativity__ or __evaluation__. What this means is that when multiple assignment operators appear in a single expression they evaluated from right to left. So our code becomes likes this. ``` 函數 myFunc() { 令 a = (b = 0); } myFunc(); ``` First, the expression <code>b = 0</code> evaluated and in this example <code>b</code> is not declared. So, The JS Engine makes a global variable <code>b</code> outside this function after that the return value of the expression <code>b = 0</code> would be 0 and it's assigned to the new local variable <code>a</code> with a <code>let</code> keyword. We can solve this problem by declaring the variables first before assigning them with value. ``` 函數 myFunc() { 令 a,b; a = b = 0; } myFunc(); ``` ###40. <div id="ecmascript">What is __ECMAScript__</div>? [&uarr;](#the-questions "Back To Questions") __ECMAScript__ is a standard for making scripting languages which means that __JavaScript__ follows the specification changes in __ECMAScript__ standard because it is the __blueprint__ of __JavaScript__. ###41. What are the new features in __ES6__ or __ECMAScript 2015__? [&uarr;](#the-questions "Back To Questions") * [Arrow Functions](#43-what-are-arrow-functions) * [Classes](#44-what-are-classes) * [Template Strings](#45-what-are-template-literals) * __Enhanced Object literals__ * [Object Destructuring](#46-what-is-object-destructuring) * [Promises](#50-what-are-promises) * __Generators__ * [Modules](#47-what-are-es6-modules) * Symbol * __Proxies__ * [Sets](#48-what-is-the-set-object-and-how-does-it-work) * [Default Function parameters](#53-what-are-default-parameters) * [Rest and Spread](#52-whats-the-difference-between-spread-operator-and-rest-operator) * [Block Scoping with <code>let</code> and <code>const</code>](#42-whats-the-difference-between-var-let-and-const-keywords) ###42. What's the difference between <code>var</code>, <code>let</code> and <code>const</code> keywords? [&uarr;](#the-questions "Back To Questions") Variables declared with <code>var</code> keyword are _function scoped_. What this means that variables can be accessed across that function even if we declare that variable inside a block. ``` 函數給MeX(showX) { 如果(顯示X){ ``` var x = 5; ``` } 返回x; } console.log(giveMeX(false)); console.log(giveMeX(true)); ``` The first <code>console.log</code> statement logs <code>undefined</code> and the second <code>5</code>. We can access the <code>x</code> variable due to the reason that it gets _hoisted_ at the top of the function scope. So our function code is intepreted like this. ``` 函數給MeX(showX) { 變數 x; // 有一個預設值未定義 如果(顯示X){ ``` x = 5; ``` } 返回x; } ``` If you are wondering why it logs <code>undefined</code> in the first <code>console.log</code> statement remember variables declared without an initial value has a default value of <code>undefined</code>. Variables declared with <code>let</code> and <code>const</code> keyword are _block scoped_. What this means that variable can only be accessed on that block <code>{}</code> on where we declare it. ``` 函數給MeX(showX) { 如果(顯示X){ ``` let x = 5; ``` } 返回x; } 函數給MeY(顯示Y){ 如果(顯示Y){ ``` let y = 5; ``` } 返回y; } ``` If we call this functions with an argument of <code>false</code> it throws a <code>Reference Error</code> because we can't access the <code>x</code> and <code>y</code> variables outside that block and those variables are not _hoisted_. There is also a difference between <code>let</code> and <code>const</code> we can assign new values using <code>let</code> but we can't in <code>const</code> but <code>const</code> are mutable meaning. What this means is if the value that we assign to a <code>const</code> is an object we can change the values of those properties but can't reassign a new value to that variable. ###43. What are __Arrow functions__? [&uarr;](#the-questions "Back To Questions") __Arrow Functions__ are a new way of making functions in JavaScript. __Arrow Functions__ takes a little time in making functions and has a cleaner syntax than a __function expression__ because we omit the <code>function</code> keyword in making them. ``` //ES5版本 var getCurrentDate = 函數 (){ 返回新日期(); } //ES6版本 const getCurrentDate = () =&gt; new Date(); ``` In this example, in the ES5 Version have <code>function(){}</code> declaration and <code>return</code> keyword needed to make a function and return a value respectively. In the __Arrow Function__ version we only need the <code>()</code> parentheses and we don't need a <code>return</code> statement because __Arrow Functions__ have a implicit return if we have only one expression or value to return. ``` //ES5版本 函數問候(名稱){ return '你好' + 名字 + '!'; } //ES6版本 const 問候 = (name) =&gt; `Hello ${name}` ; constgreet2 = 名稱 =&gt; `Hello ${name}` ; ``` We can also parameters in __Arrow functions__ the same as the __function expressions__ and __function declarations__. If we have one parameter in an __Arrow Function__ we can omit the parentheses it is also valid. ``` const getArgs = () =&gt; 參數 const getArgs2 = (...休息) =&gt; 休息 ``` __Arrow functions__ don't have access to the <code>arguments</code> object. So calling the first <code>getArgs</code> func will throw an Error. Instead we can use the __rest parameters__ to get all the arguments passed in an arrow function. ``` 常量資料 = { 結果:0, 數字:\[1,2,3,4,5\], 計算結果() { ``` // "this" here refers to the "data" object ``` ``` const addAll = () => { ``` ``` // arrow functions "copies" the "this" value of ``` ``` // the lexical enclosing function ``` ``` return this.nums.reduce((total, cur) => total + cur, 0) ``` ``` }; ``` ``` this.result = addAll(); ``` } }; ``` __Arrow functions__ don't have their own <code>this</code> value. It captures or gets the <code>this</code> value of lexically enclosing function or in this example, the <code>addAll</code> function copies the <code>this</code> value of the <code>computeResult</code> method and if we declare an arrow function in the global scope the value of <code>this</code> would be the <code>window</code> object. ###44. What are __Classes__? [&uarr;](#the-questions "Back To Questions") __Classes__ is the new way of writing _constructor functions_ in __JavaScript__. It is _syntactic sugar_ for using _constructor functions_, it still uses __prototypes__ and __Prototype-Based Inheritance__ under the hood. ``` //ES5版本 函數人(名字,姓氏,年齡,地址){ ``` this.firstName = firstName; ``` ``` this.lastName = lastName; ``` ``` this.age = age; ``` ``` this.address = address; ``` } Person.self = 函數(){ ``` return this; ``` } Person.prototype.toString = function(){ ``` return "[object Person]"; ``` } Person.prototype.getFullName = function (){ ``` return this.firstName + " " + this.lastName; ``` } //ES6版本 類人{ ``` constructor(firstName, lastName, age, address){ ``` ``` this.lastName = lastName; ``` ``` this.firstName = firstName; ``` ``` this.age = age; ``` ``` this.address = address; ``` ``` } ``` ``` static self() { ``` ``` return this; ``` ``` } ``` ``` toString(){ ``` ``` return "[object Person]"; ``` ``` } ``` ``` getFullName(){ ``` ``` return `${this.firstName} ${this.lastName}`; ``` ``` } ``` } ``` __Overriding Methods__ and __Inheriting from another class__. ``` //ES5版本 Employee.prototype = Object.create(Person.prototype); 函數 Employee(名字, 姓氏, 年齡, 地址, 職位名稱, 開始年份) { Person.call(this, 名字, 姓氏, 年齡, 地址); this.jobTitle = jobTitle; this.yearStarted = YearStarted; } Employee.prototype.describe = function () { return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}` ; } Employee.prototype.toString = function () { 返回“\[物件員工\]”; } //ES6版本 class Employee extends Person { //繼承自「Person」類 建構函數(名字,姓氏,年齡,地址,工作標題,開始年份){ ``` super(firstName, lastName, age, address); ``` ``` this.jobTitle = jobTitle; ``` ``` this.yearStarted = yearStarted; ``` } 描述() { ``` return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; ``` } toString() { // 重寫「Person」的「toString」方法 ``` return "[object Employee]"; ``` } } ``` So how do we know that it uses _prototypes_ under the hood? ``` 類別東西{ } 函數 AnotherSomething(){ } const as = new AnotherSomething(); const s = new Something(); console.log(typeof Something); // 記錄“函數” console.log(AnotherSomething 類型); // 記錄“函數” console.log(as.toString()); // 記錄“\[物件物件\]” console.log(as.toString()); // 記錄“\[物件物件\]” console.log(as.toString === Object.prototype.toString); console.log(s.toString === Object.prototype.toString); // 兩個日誌都回傳 true 表示我們仍在使用 // 底層原型,因為 Object.prototype 是 // 原型鏈的最後一部分和“Something” // 和「AnotherSomething」都繼承自Object.prototype ``` ###45. What are __Template Literals__? [&uarr;](#the-questions "Back To Questions") __Template Literals__ are a new way of making __strings__ in JavaScript. We can make __Template Literal__ by using the backtick or back-quote symbol. ``` //ES5版本 vargreet = '嗨,我是馬克'; //ES6版本 讓問候 = `Hi I'm Mark` ; ``` In the ES5 version, we need to escape the <code>'</code> using the <code>\\</code> to _escape_ the normal functionality of that symbol which in this case is to finish that string value. In Template Literals, we don't need to do that. ``` //ES5版本 var 最後一個字 = '\\n' - ' 在' - '我\\n' - '鋼鐵人\\n'; //ES6版本 讓最後一個單字=` ``` I ``` ``` Am ``` 鋼鐵人 `; ``` In the ES5 version, we need to add this <code>\n</code> to have a new line in our string. In Template Literals, we don't need to do that. ``` //ES5版本 函數問候(名稱){ return '你好' + 名字 + '!'; } //ES6版本 const 問候 = 名稱 =&gt; { 返回`Hello ${name} !` ; } ``` In the ES5 version, If we need to add an expression or value in a string we need to use the <code>+</code> or string concatenation operator. In Template Literals, we can embed an expression using <code>${expr}</code> which makes it cleaner than the ES5 version. ###46. What is __Object Destructuring__? [&uarr;](#the-questions "Back To Questions") __Object Destructuring__ is a new and cleaner way of __getting__ or __extracting__ values from an object or an array. Suppose we have an object that looks like this. ``` 常量僱員 = { 名字:“馬可”, 姓氏:“波羅”, 職位:“軟體開發人員”, 聘用年份:2017 }; ``` The old way of getting properties from an object is we make a variable t

我們透過 1 個月的地下室開發所取得的成就

管理社區是一項艱鉅的工作,但經過幾年的努力,它就變得容易了。這是我們社區的第一個月,我想向您展示我們迄今為止所取得的成就。 如果您打算經營一個社區甚至加入一個社區,本系列將以[地下室開發人員](https://discord.gg/basementdevs)為例向您展示如何衡量社區的健康狀況。 目錄 -- - [一、整體成就](#1-general-achievements) - [2. 人口統計](#1-demographics) ``` * [2.1 New Members](#21-new-members) ``` ``` * [2.2 Members Activation](#22-members-activation) ``` ``` * [2.3 Member Visits & Comunicators](#23-member-visits-amp-comunicators) ``` - [3. 活動](#3-events) - [4. 合作夥伴](#4-partnerships) - [5. 發佈內容](#5-published-content) - [6. 現在怎麼辦?](#6-what-now) 一、整體成就 ------ 首先,我要感謝加入社群的幾位讀者。現在我們有幾個波蘭人每天在那裡參與活動。 > 僅供參考:社群正在尋找像您這樣的成員,所以請盡快加入我們! :D ![每週會議最多有 71 名成員](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q0zly7fwr9rjijsuz832.jpg) 我們最新的每週例會人數達到了 71 人的高峰。 自從我們建立社群以來,我們的每週會議一直是討論新機會、專案和其他機會,並聽取成員意見的地方。 &lt; 視訊控制樣式=“高度:100%;”&gt; 您的瀏覽器不支援影片標籤。 說到社群回饋,我們的大多數成員都是想要習慣英語的巴西人,因此社群中製作的第一個專案是一個覆蓋層,用於將我們在每週會議中所說的所有內容從英語翻譯成巴西葡萄牙語!為[Pantotone](https://github.com/Pantotone)乾杯,這個神奇工具的創造者! ![Github組織](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yv2brtina8dtrd1ifqb0.png) 此外,由於我們開始建立專案,因此建立了一個新的 GitHub 組織來託管與我們社區相關的所有專案。不要忘記[關注我們的社區](https://github.com/basementdevs)以獲取最新的專案更新! 2. 人口統計 ------- 當我們談論成長時,我們談論的是數字!以下是**1 月 14 日至 2 月 12 日**的回顧。 ### 2.1 新成員 自 1 月 15 日起,我們的會員人數增加了一倍!目前我們的伺服器上有 2197 名活躍會員,其中許多人每天都在不同風格的語音頻道(小組或一對一)和文字頻道中練習英語。 ![2k 會員峰值圖表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w1dqorxb9zx3gl86iug7.png) ### 2.2 會員激活 我們本月將研究的指標之一是新成員的“激活”,即他們了解社區的含義以及為什麼它非常適合他們。 ![上個月新成員互動圖表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmjkzxh5d2te1gzmbl1y.png) 我們在第一個月做得很好,你可以看到圖表直接到底部,但這只是因為上週我們在巴西舉辦了**狂歡**節,所以這是預料之中的,我們的巴西開發商值得參加這個令人驚嘆的活動和一個愉快的假期。 ### 2.3 會員來訪及溝通 ![本月會員存取量圖表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xs7vtuw8fyd1h5ldfbq.png) 我們的平均溝通者數量或參與度是 8%。我們的目標是到 3 月底達到 15%。我們要怎麼做呢?我還不知道,但有了這份每週活動列表,這應該是個不錯的選擇。 3. 活動 ----- 活動是我們社區的核心,上個月舉辦了 16 場預先安排的活動,分為 5 個模式: - **地下室會議:**我們的每週會議於每週二晚上 07:00 BRT 舉行。其目的是分享我們社區的計劃、宣布新的合作夥伴關係、向成員通報最新訊息,當然還有練習英語。 - **和雷納託一起練習:**每週三,我們的社區都會聚在一起和雷納託一起練習英語。在這次練習中,我們的成員會得到一個主題,每個人都與雷納托就這個主題進行對話,總是引入新單字來擴大社群的詞彙量。 - **與JP一起旅行:**在本次會議中,我們的會員將與JP一起計劃他們的夢想旅行,討論費用、參觀地點、當地美食等等!快來和我們一起規劃您的旅程。 - **與李奧納多一起練習:**每週四早上,我們的社區都會與李奧納多一起參加英語練習課程。參與者被分配一個主題並與李奧納多對話,融入新單字建立詞彙量。 - **Coding Dojo:**二月初,我們推出了 Basement Coding Dojo,這是一項社群成員在模擬衝刺期間在開發團隊中扮演角色的活動。我們的第一個 Dojo 開發團隊由[Gabriel](https://github.com/gvieiragoulart) 、 [Lorena](https://github.com/Lorenalgm) 、 [Lucas](https://github.com/lucas-pace) 、 [Pedro](https://github.com/pedrovian4) 、 [Renato](https://github.com/reenatoteixeira)和[Yuri](https://github.com/yurastico)組成。在一個月的時間裡,團隊的目標是建立一個簡單但完整的應用程式,從事設計、後端和前端工作,參加每週會議並與開源專案互動。您可以在[此存儲庫](https://github.com/basementdevs/english-coding-dojo)中找到有關此事件的更多資訊。 4. 合作夥伴 ------- 現在我們最大的目標是找到HR公司甚至是正在積極招募開發人員的公司。 這個月,我們的目標是建立一個人口統計資料,提供更多有關有趣事物的訊息,為我們的會員帶來這些機會,例如:資歷、堆疊等。到目前為止,我們已經取得了一些成果,但還沒有什麼意義,因為這對我們來說是一種新方法。 ![使用者早期人口統計](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bxll9ud9we8y6uo1miry.png) 如果您的公司有空缺職位,請發送電子郵件至 [email protected],我會將其轉發給我們最好的會員進行申請! 5. 發佈內容 ------- 上個月,我們社群的成員在這個平台上發表的文章獲得了多項認可。我們想重點介紹以下文章,這些文章是其發布週中最相關的文章(前 7 名)。 {% 嵌入 https://dev.to/danielhe4rt/database-101-how-to-model-leaderboards-for-1m-players-game-2pfa %} 「在他的『Database 101』系列的最新一期中,@danielhe4rt 探索了為擁有100 萬玩家的遊戲排行榜建模的複雜藝術。本文借鑒開源節奏遊戲YARG 的個人經驗並利用ScyllaDB 的效率,深入研究了查詢驅動的資料建模和寬列資料庫概念,為製作高性能排行榜提供了全面的指南。” {% 嵌入 https://dev.to/reenatoteixeira/everything-that-you-need-to-know-about-git-2440 %} 「透過這份全面的初學者指南,探索GIT 的程式碼版本控制世界!這篇突破性文章由首次DEV 貢獻者@reenatoteixeira 撰寫,精心解開了GIT 的所有要點,確保學習之旅順利進行。具有清晰的解釋和詳細的步驟-通過逐步指導,您將掌握 GIT 的藝術,為您提供無縫的版本控制功能。” {% 嵌入 https://dev.to/kecbm/staircase-detail-112g %} 透過我們的貢獻者@kebcm 建立的這個精彩的分步教程,了解如何為初學者在編程中建立樓梯!樓梯是由一系列台階形成的視覺表示,每個台階都由 # 字元表示。探索如何建立列印自訂尺寸樓梯的函數。 {% 嵌入 https://dev.to/anthonyvii/be-a-better-developer-with-these-git-good-practices-2dim %} 如果您是開發人員,您可能會經常使用 Git。無論是單獨還是團隊開發,這對於應用程式開發都至關重要。但許多人都在與混亂的儲存庫和不清楚的提交訊息/分支名稱作鬥爭。學好 Git 並堅持最佳實踐是職業發展的關鍵之一。 6. 現在怎麼辦? --------- 到目前為止,我們的社區正在以一種我們意想不到的方式發展,但仍然以健康的方式發展。許多以前從未嘗試過**技術英語**的人已經邁出了練習的第一步,並開始**看到新的可能性**,這就是我們需要的燃料。 如果您想成為這一變革之旅的一部分,請加入我們的[Discord 伺服器](https://discord.gg/basementdevs),並且不要忘記喜歡和評論本文! 歡迎任何讓我們的社區變得更好的建議,好嗎?保持水分,下個月見! > 順便說一句,**雷納托**和**安東尼**在這份報告中幫助我乾杯:D --- 原文出處:https://dev.to/danielhe4rt/what-weve-achieved-with-1-month-of-basement-devs-3pec

Git 最佳實踐:成為更好的開發人員

如果您是開發人員,您可能每天都會使用名為 Git 的版本控制系統。無論是團隊工作還是個人工作,該工具的使用對於應用程式的開發過程都至關重要。然而,通常會遇到混亂的儲存庫、提交的訊息不明確、無法傳達有用資訊以及濫用分支等問題。對於想要在就業市場中脫穎而出的人來說,了解如何正確使用 Git 並遵循良好實踐至關重要。 --- 目錄 -- 1. [Git 分支的命名約定](#naming-conventions) 2. [分支名稱約定前綴](#branch-names) 3. [提交訊息](#commit-message) 4. [常規提交](#conventional-commits) --- Git 分支的命名約定<a id="naming-conventions"></a> ------------------------------------------ 當我們使用程式碼版本控制時,我們應該遵循的主要良好實踐之一是為分支、提交、拉取請求等使用清晰且描述性的名稱。確保所有團隊成員的簡潔工作流程至關重要。除了提高生產力之外,記錄專案的開發過程還可以簡化團隊合作。透過遵循這些做法,您很快就會看到好處。 基於此,社群建立了一個您可以在專案中遵循的分支命名約定。以下專案的使用是可選的,但它們可以幫助提高您的開發技能。 **1.小寫:**分支名稱不要使用大寫字母,堅持小寫; **2. 連字符分隔:**如果您的分支名稱由多個單字組成,請用連字符分隔它們。遵循烤肉串慣例。避免 PascalCase、camelCase 或 Snake\_case; **3. (az, 0-9):**分支名稱中僅使用字母數字字元和連字符。避免使用任何非字母數字字元; **4. 請不要使用連續的連字號(--)。**這種做法可能會令人困惑。例如,如果您有分支類型(例如功能、錯誤修復、修補程式等),請改用斜線 (/); **5. 避免以連字符結尾分支名稱**。這是沒有意義的,因為連字符分隔單詞,並且末尾沒有單詞可以分隔; **6. 這個做法最重要:**使用描述性的、簡潔的、清晰的名稱來解釋分支上做了什麼; **分支名稱錯誤** - `fixSidebar` - `feature-new-sidebar-` - `FeatureNewSidebar` - `feat_add_sidebar` **好聽的支行名字** - 功能/新側邊欄 - 新增側邊欄 - 修補程式/取得歷史資料上的間隔查詢參數 --- 分支名稱約定前綴<a id="branch-names"></a> --------------------------------- 有時分支的目的並不明確。它可以是新功能、錯誤修復、文件更新或其他任何內容。為了解決這個問題,通常的做法是在分支名稱上使用前綴來快速解釋分支的用途。 - **feature:**它傳達了將要開發的新功能。例如, `feature/add-filters` ; - **發布:**用於準備新版本。前綴`release/`通常用於在合併來自分支主伺服器的新更新以建立版本之前執行諸如上次觸及和修訂之類的任務。例如, `release/v3.3.1-beta` ; - **bugfix:**它表示您正在解決程式碼中的錯誤,並且它通常與問題相關。例如, `bugfix/sign-in-flow` ; - **hotfix:**與bugfix類似,但它與修復生產環境中存在的嚴重錯誤有關。例如, `hotfix/cors-error` ; - **docs:**寫一些文件。例如, `docs/quick-start` ; 如果您正在使用任務管理工作流程,例如 Jira、Trello、ClickUp 或任何可以建立使用者故事的類似工具,則每張卡片都有一個關聯的編號。因此,通常在分行名稱的前綴上使用這些卡號。例如: - `feature/T-531-add-sidebar` - `docs/T-789-update-readme` - `hotfix/T-142-security-path` --- 提交訊息<a id="commit-message"></a> ------------------------------- 讓我們來談談提交訊息。不幸的是,很容易找到帶有“加入了很多東西”或“皮卡丘,我選擇你”之類的提交訊息的專案......是的,我曾經發現一個專案,其中提交訊息與神奇寶貝戰鬥有關。 提交訊息在開發過程中非常重要。創造一段美好的歷史將在你的旅程中給你很多幫助。與分支一樣,提交也有社區建立的約定,您可以在下面了解: - 提交訊息包含三個重要部分:主題、說明和頁腳。提交的主題是必要的,它定義了提交的目的。描述(正文)用於為提交的目的提供額外的上下文和解釋。最後是頁腳,通常用於元資料,例如分配提交。雖然同時使用描述和頁腳被認為是一種很好的做法,但這不是必需的。 - **在主題行中使用祈使語氣。**例如: > `Add README.md` ✅; > `Added README.md` ❌; > `Adding README.md` ❌; - **主題行的第一個字母大寫。**例如: > `Add user authentication` ✅; > `add user authentication` ❌; - **不要以句號結束主題行。**例如: > `Update unit tests` ✅; > `Update unit tests.` ❌; - 主題行限制在**50個字元**以內,即清晰、簡潔; - 將正文包裹在**72 個字元**處,並將主題與**空白行**分隔開; - 如果您的提交正文有多個段落,請**使用空白行將它們分開**; - 如有必要,使用**要點**而不是僅使用段落; --- 常規提交<a id="conventional-commits"></a> ------------------------------------- > “常規提交規範是基於提交訊息的輕量級約定。它提供了一組簡單的規則來建立明確提交歷史記錄。” 以下引用來自Conventional Commit 的官方網站。該規範是社區中提交訊息最常使用的約定。 ### 結構 ``` <type>[optional scope]: <description> [optional body] [optional footer(s)] ``` ### 提交類型 我們要研究的第一個結構是提交類型。它提供了有關此提交中所做操作的清晰上下文。您可以在下面看到提交類型清單以及何時使用它們: - **feat:**引進新功能; - **fix:**修復軟體錯誤; - **refactor:**用於程式碼更改,保留其整體功能; - **chore:**不影響生產程式碼的更新,涉及工具、配置或程式庫調整; - **docs:**文件文件的新增或修改; - **perf:**程式碼更改提高效能; - **style:**與程式碼呈現相關的調整,例如格式和空白; - **test:**測試的包含或修正; - **build:**影響建置系統或外部依賴項的修改; - **ci:** CI 設定檔和腳本的更改; - **env:**描述 CI 流程中設定檔的調整或加入,例如容器配置參數。 ### 範圍 範圍是一種結構,可以在提交類型之後加入以提供額外的上下文資訊: - `fix(ui): resolve issue with button alignment` - `feat(auth): implement user authentication` ### 身體 提交訊息的正文提供了提交引入的更改的詳細說明。它通常會加入在主題行後面的空白行之後。 **例子:** ``` Add new functionality to handle user authentication. This commit introduces a new module to manage user authentication. It includes functions for user login, registration, and password recovery. ``` ### 頁尾 提交訊息的頁腳用於提供與提交相關的附加資訊。這可以包括諸如誰審查或批准了變更之類的詳細資訊。 **例子:** ``` Signed-off-by: John <[email protected]> Reviewed-by: Anthony <[email protected]> ``` ### 突破性變革 指示提交包含可能導致相容性問題或需要修改相關程式碼的重大變更。您可以在頁腳中新增`BREAKING CHANGE`或包含`!`在類型/範圍之後。 ### 使用常規提交的提交範例 ``` chore: add commitlint and husky chore(eslint): enforce the use of double quotes in JSX refactor: type refactoring feat: add axios and data handling feat(page/home): create next routing chore!: drop support for Node 18 ``` **包含主題、正文和頁尾:** ``` feat: add function to convert colors in hexadecimal to rgba Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s. Reviewed-by: 2 Refs: #345 ``` --- 參考 -- - <https://www.conventionalcommits.org> - <https://medium.com/@abhay.pixolo/naming-conventions-for-git-branches-a-cheatsheet-8549feca2534> - <https://se-education.org/guides/conventions/git.html> - <https://cbea.ms/git-commit/> https://blog.geekhunter.com.br/o-que-e-commit-e-como-usar-commits-semanticos/ --- 原文出處:https://dev.to/anthonyvii/be-a-better-developer-with-these-git-good-practices-2dim

只需 4 小時即可製作您的作品集?這是可能的。

你能在 4 小時內完成你的作品集嗎? 聽起來很瘋狂,對吧? > 您的作品集是一個展示您最好的作品、個性和才能的網站。您可以被雇用,人們可以更多地了解您。 建立一個好的投資組合需要遵循各種規則,而條件取決於您的職業。例如,使用者體驗設計師與軟體開發人員的情況可能完全不同。 ### 我認為一個好的作品集應該是什麼樣的。 對我來說,這三件事對於一個好的作品集是必不可少的。 應該很**簡單**。**在職的**。**專業的**。 - 存取作品集的人的體驗應該很好。 - 此人應該能夠與您聯繫(通常是聯絡表單)。 - 作品集應該有一個故事和一點個人風格。 - 它應該放在網域上以提高可信度。 - 它不應該有太多會破壞這一刻的花俏動畫。 ### 為什麼你應該製作一個投資組合? 擁有作品集是一種常見的做法,尤其是當您有多個東西要展示時。 > 並非每個人都有時間或資源來製作完全適合自己需求的獨特投資組合。 嗯,你不應該。 在這個不斷發展的世界中沒有必要。 沒有非常容易使用的程式碼工具。 但是你能在一天甚至一小時內製作出作品集嗎? 我們無法製作最好的作品集,但我們可以製作一個效果良好的體面作品集。 如果您不喜歡這個也沒關係,因為我知道製作具有自己獨特風格的作品集需要花費很多時間。 每個人都有自己的經歷,每個人都試圖根據我們多年來所學到的知識互相幫助。 一點注意 ---- 我是使用者體驗法則的忠實粉絲,知道如何才能做到優秀。 我不會介紹像 Bubble、Framer、Wix 和 Squarespace 這樣的無程式碼工具,因為它們已經很流行了。 --- 我管理多個社群檔案,因此我總是糾結於將觀眾引導至哪些社群媒體。 大多數人都在努力擁有多個配置文件,您一定聽說過`linkfree`或`bento` 。 您不僅僅是一系列關於您的連結。 你必須講述你的故事。這個故事很重要。 作品集是實現這一目標的最佳方式,因此這裡有一些工具,對於想要快速獲得具有良好使用者體驗的作品集的人來說將很有幫助。 您可以使用每個選項連接到您的網域。 我敢打賭這篇文章會讓你大吃一驚。 那我們就開始吧。 --- 1.[聚合工作](https://www.polywork.com/invite/anmol_baranwal-voltorb) ---------------------------------------------------------------- Polywork 是 2022 年最好的產品之一。 它可以在幾秒鐘內將您的 LinkedIn 個人資料轉換為個人網站。 我是 Polywork 的忠實粉絲,因為製作獨特風格的作品集是多麼容易。它有一個圖形編輯器,可以讓你建立部分,你也可以在後台使用人工智慧。 相信我,這就是您所需要的一切。 ![聚合工作](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z7gvnoaurlktbmk3gg11.png) 最棒的是它是免費的,您可以以大約 96 美元購買一年。考慮到您將透過高級版本解鎖所有新`fonts` 、 `layouts`和`colors` ,這是一個相當不錯的交易。 這是來自其中一個模板。酷吧 :D ![範本](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drzgta1xnkhg7qjntb6c.png) 在免費版本中,您將獲得一個按鈕來隨機化您的作品集(不同的主題和佈局)。一定要嘗試! 您可以加入這樣的個人化連結。 ![連結](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gyyjdpibakzqineuc2yw.png) 您可以建立亮點以及「關於我」、「社交連結」和個人化「標題」等部分。此外,還有超過 1,000 種針對不同個人資料量身定制的徽章供您選擇。 ![徽章](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bcidgo1nwlz5ztcecu36.png) 開箱即用的是,您可以控制您的`social card` 、 `metadata` ,甚至頁面`title` 。這使您可以完全控制,使您的投資組合看起來真實。 ![社群卡](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s3uqmx55nzui9arj3e36.png) 有很多話要說,但最方便的功能是有人可以多快與您聯繫。 就好像在短短幾秒鐘內,讓我們面對現實吧,這正是每個投資組合所需要的。 ![接觸](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1ei275dt79noxxvzx9b.png) 您可以查看我的[Polywork 個人資料](https://www.polywork.com/anmolbaranwal)作為樣本。 ![輪廓](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t209dwrmvsxjheiof1o5.png) 關於 Polywork 的最佳簡介之一來自 Craftwork 的共同創辦人[Mike Bifulco](https://www.polywork.com/irreverentmike) 。一探究竟! > 在 Polywork 上創造一個好的作品集甚至不需要超過 4 小時。 2.[來自珍珠](https://peerlist.io/anmolbaranwal/signup) -------------------------------------------------- 我加入 Peerlist 已經幾個月了。我也是他們的測試版行動用戶之一。 除了可以使用同行清單做的其他事情之外,您還可以在網域上製作良好的投資組合。 讓我們討論其中的一些。 ![來自珍珠](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k04zxgouxo1s9i2nbcl4.png) ![來自珍珠](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1doko89swvblfy6z736k.png) 您可以在一個設定檔中包含所有內容。 - GitHub 個人資料、貢獻和固定儲存庫 - DEV + Hashnode + Medium 部落格文章 - YouTube影片 - 子堆疊 + RSS 來源 - Codeforces 和其他編碼設定文件 - 您甚至可以從 Product Hunt 加入您的狩獵或製造商產品 基本上一切:D ![工作](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1gzcfg2leqfhywwab97.png) ![專案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w422mys01m11kpsjafy7.png) 對等列表上還有一個集合的概念。我在其他地方見過這些,但是將這些放在您的個人資料中確實很棒。 您可以在一個地方新增社交資料卡。 以及您推薦的影片、書籍、播客或自訂內容。 ![收藏品](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pzc67pxqkymprmtl3slr.png) 您甚至可以找到工作並通過您的簡歷和經驗進行驗證。 ![已驗證](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mvje9g9alac8lrfs3xdw.png) 您還可以做的另一件事是為某人提供擔保,這可以提高可信度並讓您在個人資料中具有明顯的優勢。它與LinkedIn上的推薦類似,但他們在卡片上做了一些創意。 ![擔保](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98y314zrn6vvlqhusyp2.png) 您可以免費將您的個人資料連接到您的自訂網域。所以,這就是你的投資組合的樣子。 ![自訂域](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/myy4f4xvayyccai07ea5.png) 順便說一句,如果您想知道 -&gt; 您的社交連結將位於底部。 您甚至可以讓您的專案在同行清單中受到關注:D 牽涉的事情很多,我無法一一列舉。 我將在後面的文章中介紹 Peerlist 中令人興奮的內容。 請注意! 3.[展示](https://www.showwcase.com/) ---------------------------------- Showwcase 的主要目標是建立一個強大的開發者社群。 Showwcase 是我幾個月前使用的第一個。 ![展示](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tt07du3co8831ltgj7cn.png) 一種簡單而強大的方式來展示您的故事。 最獨特的功能之一是您可以與 Stripe 連接,並且可以從付費追蹤者那裡賺錢。多麼酷啊? 這些是您可以在自訂部分之外製作的一些部分。 ![部分](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ka3xcr5xr6hrqqtuvyvu.png) 您可以輕鬆加入社交連結並查看一些很棒的社區,例如`Open Source` 、 `Hackathons` 、 `Internships` 、 `Portfolios`等等。 ![社群連結](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5vjm3quo7his881j768.png) 您可以獲得推薦,甚至可以加入合作者,這是一件很划算的事情。我從一開始就對此感到驚訝。 ![合作者](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mp5j7vc81r58kzap2tvu.png) 您可以使用您的個人連結產生並製作適合 ATS 的簡歷。 例如,您可以[在這裡](https://www.showwcase.com/anmol-baranwal/resume/ats)找到我的。它使用網站資訊。順便說一下,我的個人資料沒有更新:D 這個社群非常龐大,我已經加入 Showwcase 幾個月了。 ![輪廓](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jwovaoiz0dmghy701o2q.png) 您可以在[anmol-baranwal.showwcase.com](https://anmol-baranwal.showwcase.com/)查看我的展示個人資料 請參閱 Showwcase 執行長[Rong](https://www.showwcase.com/tianrongliew)的簡介。 您可以在 Showwcase 進行招募和受聘。 我不喜歡簡歷功能,該功能只是從個人資料中收集資料。有履歷會更有利。 但 Showwcase 已經提供了超出您所需的功能。 4.[閱讀](https://read.cv/) ------------------------ 這是製作作品集的另一種方式。我喜歡 Read 的使用者介面。 最好的事情是有人可以隨時隨地與您聯繫,並且很容易找到帶有甜蜜表情符號的聯繫按鈕。它實際上鼓勵人們使用該聯繫部分。 ![Read.cv 橫幅](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztq28e74gm2uthszqwzm.png) 您可以在 ReadCV 上查看[Edmundo Santos](https://read.cv/edmundo)的個人資料。非常棒。 ![輪廓](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gj2w3o4rdm3wc10vubo.png) 有各種各樣的部分,如社交聯繫、經驗、副專案、演講、寫作等等。 ![社群連結](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqykez5hsoao2d68zixl.png) 您可以加入的部分數量令人難以置信。它為您在各個部分提供了很大的靈活性。 ![部分](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ft1zlea3csz7rcwmh2rm.png) 當然,還有職位列表和自訂網域,您可以將您的個人資料連結到其中。 佈局是固定的,但足以讓您入門。 我見過很多偉大的人使用“閱讀”作為他們的首選個人資料! --- 這些是您可以使用的一些很棒的資源。 - [超過 25 個帶有程式碼的令人驚嘆的作品集](https://dev.to/anmolbaranwal/stunning-portfolios-that-will-blow-your-mind-fuel-your-creativity-226o) - [無需編碼即可建立令人驚嘆的網站的 20 個工具](https://dev.to/anmolbaranwal/20-game-changing-website-builders-to-build-classy-websites-without-coding-4ll7) - [開發人員的最小組合模板](https://github.com/cobiwave/simplefolio)- GitHub 上有 13k Stars --- 當您將個人資料連接到網域時,沒有人有時間查看您是否自己製作了作品集。只要它對你有用,那就太棒了。 你覺得有用嗎? 除了 ReadCV(新手)之外,我已經嘗試了這些方法好幾個月了,直到那時我才讓你知道。 順便說一句,這些都沒有贊助。我希望如此。哈哈! 如果你堅持使用那些簡單、無聊的工具,你就錯過了。在這個科技世界中,您可以毫無麻煩地建立您的投資組合。 程式設計師會否認建立這樣的作品集行不通,但這不是真的,如果它對你有用那就太好了。 我已經完成了 5000 多個小時的編程,我可以這麼說。 任何好的東西都比糟糕的投資組合好。 正如我在一開始所說的,如果您不想透過程式設計來建立原始作品集也沒關係,因為只有開發人員才應該使用程式碼來完成它。 您還需要什麼? 匆忙!建立您的作品集並向世界展示:D 你認為哪個最好?我喜歡 Polywork &amp; Read。兩者都是我在列表中使用最少的:D 我很高興我終於寫了這篇文章。 我透過深入研究並分享我的經驗來撰寫內容。您可以透過[在 GitHub 上贊助](https://github.com/sponsors/Anmol-Baranwal)我來支持我。 請在[GitHub](https://github.com/Anmol-Baranwal)和[Twitter](https://twitter.com/Anmol_Codes)上關注我:) > 如果您熱衷於贊助這篇文章,請給我發訊息 [email protected] 或在 Twitter 上聯繫我! 🚀 {% 嵌入 https://github.com/Anmol-Baranwal %} 多寫,多啟發。 ![結束 GIF 揮手告別](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ylsck6b9c7ei6makpqd.gif) --- 原文出處:https://dev.to/anmolbaranwal/make-your-portfolio-in-just-4-hours-its-possible-2p3

100 多個帶有原始程式碼的 JavaScript 專案

您是否正在尋找**最好的 JavaScript 專案**來透過原始程式碼增加您的 JavaScript 知識? 在這篇文章中,我分享了 100 個最佳 JavaScript 教學。有各種各樣的專案,例如初學者 JavaScript 專案、中級 JavaScript 專案和高級 JavaScript 專案。 因此,無論您對 JavaScript 有什麼樣的了解,這些專案都會對您有所幫助。 🥳🥳 JavaScript 專案 ------------- JavaScript 是用於 Web 開發的最受歡迎的程式語言之一。它用途廣泛、功能強大,可用於建立各種專案,從簡單的腳本到複雜的 Web 應用程式。 如果您希望提高您的 JavaScript 技能或向潛在雇主展示您的能力,那麼**使用原始程式碼開發 JavaScript 專案**是一個很好的方法。 這裡我給了每個專案的源碼連結。因此,您可以自己練習這些**JavaScript 專案**。 😇 ![成為 JS 專家](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u6gnnsmqtf4irq895e0s.jpg) 最佳 JavaScript 專案創意 ------------------ 讓我們來看看前 100 個 JavaScript 專案並討論如何建立它們。 ### 適合初學者的 JavaScript 專案 如果您是一位想要深入編碼世界或尋求擴展技能的初學者,那麼從**簡單的 JavaScript 專案**開始可能是寓教於樂的絕佳方式。這個初學者級 JavaScript 專案一定會對您有幫助。 #### 圖像顏色選擇器 Javascript ![圖像顏色選擇器 Javascript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zswnpz4eqwkbyzlvxsm0.jpg) JavaScript 中的圖像顏色選擇器是一個**簡單的 JavaScript 專案**,可讓使用者直接從圖像中選擇顏色。 它使用戶能夠以互動方式從網頁上顯示的圖像中選取顏色,從而簡化諸如顏色匹配、顏色採樣或從圖像中提取顏色資訊等任務。 [預覽和程式碼](https://codingartistweb.com/2022/11/image-color-picker-javascript/) #### 數字時鐘 JavaScript ![數字時鐘 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u9ychtonhcv3ccallsze.jpg) JavaScript 中的數位時鐘是一個基於 Web 的應用程式或 JavaScript 專案,它以數位格式在網頁上顯示當前時間。 這是一個常見且簡單的專案,展示如何使用 JavaScript 在網路上建立動態和互動式內容。 [預覽和程式碼](https://dev.to/nehasoni__/digital-clock-using-javascript-2648) #### 使用 JavaScript 的秒錶 ![使用 JavaScript 的秒錶](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3qac5fgivbu54ee4ngy7.jpg) 使用 JavaScript 的秒錶是一個基本的 JavaScript 專案,可讓使用者測量經過的時間。它通常由一個用於開始計時的開始按鈕、一個用於暫停計時器的停止按鈕以及一個用於清除已用時間並重新開始的重置按鈕組成。 [預覽和程式碼](https://dev.to/shantanu_jana/create-a-simple-stopwatch-using-javascript-3eoo) #### RGB 顏色滑桿 JavaScript ![RGB 顏色滑桿 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6pvy2tq5yz6owpj1jqgj.jpg) JavaScript 中的 RGB 顏色滑桿是一個**適合初學者的完美 JavaScript 專案**,它允許使用者透過調整顏色的紅色、綠色和藍色 (RGB) 分量的值來選擇顏色。 此互動式元件通常由三個滑桿或輸入欄位(每個顏色通道一個)以及一個預覽區域組成,該區域根據所選 RGB 值顯示結果顏色。 [預覽和程式碼](https://codingartistweb.com/2023/05/rgb-color-slider-javascript/) #### JavaScript 年齡計算器 ![JavaScript 年齡計算器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8nuylom621dansflni0.jpg) JavaScript 年齡計算器是適合初學者的簡單 JavaScript 專案,它根據出生日期和當前日期計算一個人的年齡。它通常以生日的形式獲取用戶的輸入,然後計算並顯示他們的年齡。 [預覽和程式碼](https://dev.to/code_mystery/javascript-age-calculator-calculate-age-from-date-of-birth-o9b) #### 懸停時影像縮放 ![懸停時影像縮放](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/llrsmmgwkwjo0feoslk5.jpg) JavaScript 中的懸停圖像縮放功能可讓使用者將遊標懸停在圖像上時放大圖像。 此效果可讓使用者更仔細地查看圖像中的細節,從而增強使用者體驗,而無需使用者點擊其他控製或與其他控制項進行互動。 [預覽和程式碼](https://dev.to/shantanu_jana/image-zoom-on-hover-using-javascript-code-demo-328g) #### OTP 生成器 JavaScript ![OTP 生成器 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ad6rb29svfif5b0zg39j.jpg) JavaScript 中的 OTP(一次性密碼)產生器是一種產生唯一程式碼的工具,該程式碼通常由數字或字母數字字元組成,該程式碼一次性使用或在有限時間內有效。 OTP 通常用於 Web 應用程式中的使用者驗證、雙重認證 (2FA) 和帳戶驗證流程。 [預覽和程式碼](https://codingartistweb.com/2023/12/otp-generator/) #### JavaScript 手電筒效果 ![JavaScript 手電筒效果](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4gyd41fpahtqfvc860h9.jpg) JavaScript 手電筒效果模擬手電筒或聚光燈在網頁上產生的照明。它是一種互動式視覺效果,透過將注意力集中在頁面的特定元素或區域來增強使用者體驗。 實現手電筒效果通常涉及在網頁上建立遮罩層,並允許使用者使用滑鼠或觸控輸入來移動手電筒。 [預覽和程式碼](https://groundtutorial.com/flashlight-effect-with-html-css-javascript/) #### 影像手風琴 ![影像手風琴](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ziojqmkvy1lbnzf1u7gx.jpg) JavaScript 中的圖像手風琴是一種使用者介面元素,它以垂直或水平堆疊的形式顯示一組圖像,允許用戶展開和折疊單個圖像以顯示與每個圖像相關的更多細節或資訊。 這種互動創造了一種視覺上吸引人的方式來呈現圖像集合,同時節省網頁空間。 [預覽和程式碼](https://groundtutorial.com/image-accordion-using-html-css-javascript/) #### 拖放元素 ![拖放元素](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iohtqrsk79qw7lva8ngx.jpg) JavaScript 拖放功能可讓使用者透過點擊網頁元素並將其拖曳到頁面上的不同位置來與它們互動。 此功能通常在 Web 應用程式中用於執行諸如重新排序清單、在容器之間移動元素或建立互動式使用者介面等任務。 [預覽和程式碼](https://groundtutorial.com/draggable-element-javascript/) #### 隨機數產生器 ![隨機數產生器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpezbhvuioe4hpd87yly.jpg) JavaScript 中的隨機數產生器(RNG)是一種產生指定範圍內或具有特定特徵的隨機數的工具。隨機數通常用於遊戲、模擬、密碼學和統計分析等應用。 JavaScript提供了用於生成隨機數的內建函數和方法,可以根據應用程式的要求進行自訂。 [預覽和程式碼](https://foolishdeveloper.com/random-password-generator-with-javascript/) #### 使用 JavaScript 的小費計算器 ![使用 HTML、CSS 的小費計算器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7mcqubvfib3v63y5vhlu.jpg) [預覽和程式碼](https://groundtutorial.com/tip-calculator-html-css-javascript/) #### HTML、CSS、JS 中的雙範圍滑桿 ![HTML、CSS 中的雙範圍滑桿](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6knk161ja08o9t3bsh3.jpg) [預覽和程式碼](https://groundtutorial.com/double-range-slider-in-html-css-javascript/) #### 使用 JavaScript 的倒數計時器 ![使用 JavaScript 的倒數計時器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wdi6x6fqxrv8q0o4acs3.jpg) [預覽和程式碼](https://dev.to/shantanu_jana/how-to-build-a-countdown-timer-using-javascript-4f4h) #### 使用 JavaScript 的漸層顏色產生器 ![使用 JavaScript 的漸層顏色產生器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pocfjwy56br7v0zg03kn.jpg) [預覽和程式碼](https://dev.to/shantanu_jana/gradient-color-generator-with-javascript-html-5e3p) #### 使用 Javascript 懸停時圖像縮放 ![使用 Javascript 懸停時圖像縮放](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p50dvkjpswitvvoglt26.jpg) [預覽和程式碼](https://dev.to/shantanu_jana/image-zoom-on-hover-using-javascript-code-demo-328g) ### 中階 JavaScript 專案 對於中級 JavaScript 開發人員來說,有許多專案提供了擴展技能、探索新技術和深入研究 Web 開發概念的機會。以下是為中級開發人員量身定制的 JavaScript 專案想法清單: #### 自訂遊標 ![自訂遊標](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3hg920h1fv61et73v6na.jpg) JavaScript 中的自訂遊標是指以自訂設計的圖形或 HTML 元素取代預設遊標外觀(例如箭頭或手形指標)的能力。這使得網頁開發人員能夠建立與網站主題或品牌相符的獨特且具有視覺吸引力的遊標效果。 [預覽和程式碼](https://foolishdeveloper.com/simple-mouse-cursor-effects-using-javascript-free-code/) #### 回文檢查器應用程式 ![回文檢查器應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eioy07s621eqjc1e5fi5.jpg) JavaScript 中的回文檢查器應用程式是一個簡單的 Web 應用程式,允許使用者輸入一串字元並檢查它是否是回文。 回文是單字、片語、數字或其他字元序列,無論空格、標點符號和大小寫,向前和向後讀起來都相同。 [預覽和程式碼](https://groundtutorial.com/how-to-check-palindrome-in-javascript/) #### 滑動圖像拼圖 Javascript ![滑動圖像拼圖 Javascript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t3gn4vl9mvapb5b3cvot.jpg) JavaScript 中的滑動圖像拼圖是一種經典遊戲,其中圖像被分成較小的圖塊,玩家的目標是透過滑動它們來重新排列圖塊以形成原始圖像。遊戲提供了娛樂性和挑戰性的體驗,同時也考驗玩家解決問題的能力和空間推理能力。 [預覽和程式碼](https://groundtutorial.com/image-puzzle-game-javascript/) #### 使用 Javascript 的貨幣轉換器 ![使用 Javascript 的貨幣轉換器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/41ncmzvsq5pj9a6vbjbn.jpg) 使用 JavaScript 的貨幣轉換器是一個 Web 應用程式,允許用戶根據當前匯率將價值從一種貨幣轉換為另一種貨幣。 用戶通常輸入他們想要轉換的金額,選擇來源貨幣,然後選擇目標貨幣。然後,應用程式從 API 檢索最新的匯率並相應地計算換算後的金額。 [預覽和程式碼](https://codingartistweb.com/2023/03/currency-converter-with-javascript/) #### 猜顏色遊戲Javascript ![猜顏色遊戲Javascript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wp4a678c6zsw05ttmd9i.jpg) JavaScript 中的顏色猜測遊戲是一種互動式 Web 應用程式,玩家會看到目標顏色,並且必須猜測該顏色的 RGB 或十六進位程式碼。遊戲通常會提供線索來幫助玩家做出有根據的猜測,例如在正方形中顯示顏色或提供有關顏色成分(紅色、綠色、藍色)或亮度的提示。 [預覽和程式碼](https://groundtutorial.com/color-guessing-game-javascript/) #### 拖放可排序列表 ![拖放可排序列表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fgyicbi03b7fac9cje89.jpg) JavaScript 中的拖放可排序清單是一個使用者介面元件,可讓使用者透過將清單中的專案拖曳到新位置來重新排序。 此功能通常在 Web 應用程式中用於執行諸如重新排列待辦事項清單中的專案、對圖庫中的圖像進行排序或在文件管理器中組織文件等任務。 [預覽和程式碼](https://codingartistweb.com/2023/02/drag-and-drop-sortable-list-javascript/) #### 觸碰並拖曳影像滑桿 ![觸碰並拖曳影像滑桿](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4idy4zthbl0v6wv4nf6.jpg) JavaScript 中的觸控和拖曳圖像滑桿是一個使用者介面元件,可讓使用者水平滑動或拖曳圖像以在圖像庫中導航。這種類型的滑桿針對智慧型手機和平板電腦等支援觸控的裝置進行了最佳化,但也可以與桌面瀏覽器上基於滑鼠的互動無縫協作。 [預覽和程式碼](https://groundtutorial.com/touch-image-slider-using-html-css-javascript/) #### 偵測網路速度 JavaScript ![偵測網路速度 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twmtmhtmia47dzd9mjr5.jpg) 在 JavaScript 中偵測網路速度涉及測量從伺服器下載已知大小的檔案所需的時間。有多種技術可以實現此目的,包括使用 XMLHttpRequest、fetch API 或 HTML5 功能(例如網路資訊 API)。 [預覽和程式碼](https://foolishdeveloper.com/detect-internet-speed-javascript/) #### JavaScript 模因應用程式 ![JavaScript 模因應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2q1nbc4ckpwemkok3hx.jpg) JavaScript Memes 應用程式是一個 Web 應用程式,允許使用者瀏覽、搜尋和查看 memes。它通常從 API 或資料庫中獲取模因,並將其顯示在用戶友好的介面中,通常具有分頁、排序、過濾和社交共享選項等功能。用戶可以與迷因互動,例如喜歡或分享它們,並且可以上傳自己的迷因。 [預覽和程式碼](https://codingartistweb.com/2022/10/memes-app-html-css-javascript/) #### 多個骰子滾軸 ![多個骰子滾軸](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tmfp7t045awkyniij91a.jpg) JavaScript 中的多個骰子滾輪是一個允許使用者滾動多個不同類型的骰子(例如,d4、d6、d8、d10、d12、d20)並顯示結果的工具。 它通常用於《龍與地下城》等桌上角色扮演遊戲 (RPG) 中,或用於各種遊戲或教育目的。 [預覽和程式碼](https://codingartistweb.com/2023/10/multiple-dice-roller/) #### 密碼強度背景 ![密碼強度背景](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8hkeyw0wr9bc3ajry59f.jpg) JavaScript 中的密碼強度背景是一項功能,當使用者在輸入欄位中鍵入密碼時,可以提供使用者有關密碼強度的視覺回饋。 此回饋通常是透過更改輸入欄位的背景顏色來提供的,以根據預先定義的標準指示密碼是弱、中等還是強。 [預覽和程式碼](https://codingartistweb.com/2023/10/password-strength-background/) #### 自訂滑鼠懸停效果 ![自訂滑鼠懸停效果](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lm53lriqk83p9qbaa8eg.jpg) JavaScript 中的自訂滑鼠懸停效果是一種視覺效果,當使用者將滑鼠懸停在網頁上的元素上時,效果會變更該元素的外觀或行為。 這種效果可以透過使用 CSS 過渡或動畫結合 JavaScript 事件監聽器來偵測滑鼠懸停事件並觸發所需的效果來實現。 [預覽和程式碼](https://codingartistweb.com/2023/12/custom-mouse-hover-effect-with-javascript/) #### 文字相似度檢查器 ![文字相似度檢查器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g4m8phfjm38cc0uug7tf.jpg) JavaScript 中的文字相似度檢查器是一種測量兩段文字或文件之間相似性的工具或應用程式。 文字相似度可以使用各種演算法和技術來計算,例如餘弦相似度、Jaccard 相似度、Levenshtein 距離或 TF-IDF(詞頻-逆文件頻率)。 [預覽和程式碼](https://codingartistweb.com/2023/09/text-similarity-checker/) #### 使用 JavaScript 的拋硬幣遊戲 ![使用 JavaScript 的拋硬幣遊戲](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtd74ui4i8ds0q6k3b6o.jpg) [預覽和程式碼](https://dev.to/shantanu_jana/coin-toss-game-using-javascript-css-1cf0) #### Javascript 剪刀石頭布遊戲 ![Javascript 剪刀石頭布遊戲](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/if9zccyex7o9n0sfgpt7.jpg) [預覽和程式碼](https://groundtutorial.com/rock-paper-scissor-game-javascript/) #### JavaScript 中的右鍵上下文選單 ![JavaScript 中的右鍵上下文選單](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ope2hkppwntnhnrgskf9.jpg) [預覽和程式碼](https://dev.to/shantanu_jana/custom-right-click-context-menu-in-javascript-4112) ### 高級 JavaScript 專案 高階 JavaScript 專案通常涉及建立複雜的 Web 應用程式或利用複雜框架、程式庫和 API 的軟體解決方案。 這些專案可能需要前端開發、後端開發或全端開發的專業知識。以下是高級 JavaScript 專案的一些範例: #### 帶有儲存的隨機報價產生器 ![帶有儲存的隨機報價產生器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/duvtugkuougrls6ylu6b.jpg) JavaScript 中帶有儲存功能的隨機報價產生器是一個 Web 應用程式,它向用戶顯示隨機報價,並允許他們保存自己喜歡的報價以供以後查看。 該應用程式通常從預先定義清單或外部 API 檢索報價,在網頁上動態顯示它們,並為使用者提供使用 localStorage 儲存和檢索所選報價的選項。 [預覽和程式碼](https://dev.to/nehasoni__/random-quote-generator-using-html-css-and-javascript-3gbp) #### 使用 JavaScript 的螢幕截圖應用程式 ![使用 JavaScript 的螢幕截圖應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8d0edi0hwddzum4k78ux.jpg) 使用 JavaScript 建立螢幕截圖擷取應用程式涉及利用瀏覽器功能來擷取目前網頁或頁面中特定元素的螢幕截圖。 雖然 JavaScript 本身無法直接截取螢幕截圖,但它可以與瀏覽器 API 互動以觸發螢幕截圖擷取功能。 [預覽和程式碼](https://codingartistweb.com/2023/05/screenshot-capture-app-using-javascript/) #### 警報應用程式 JavaScript ![警報應用程式 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwr8w5254xt70mzcmtvi.jpg) JavaScript 中的鬧鐘應用程式是一個簡單的應用程式,可讓用戶設定鬧鐘並在特定時間接收通知或警報。 它通常涉及用戶互動來設定所需的鬧鐘時間,然後應用程式在背景執行,在達到設定時間時觸發通知。 [預覽和程式碼](https://www.codingnepalweb.com/simple-alarm-clock-html-javascript/) #### 文字轉語音轉換器 ![文字轉語音轉換器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ogf39oucpxjiof9uipjt.jpg) JavaScript 中的文字轉語音 (TTS) 轉換器是一種將書面文字轉換為口語單字的工具或應用程式。它利用瀏覽器 API 或第三方庫將文字合成為語音,並透過裝置的揚聲器或耳機播放。以下是使用 HTML、CSS 和 JavaScript 的文字轉語音轉換器的基本實作: [預覽和程式碼](https://dev.to/shantanu_jana/text-to-speech-converter-with-javascript-30oo) #### QR 碼產生器 JavaScript ![QR 碼產生器 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m0vcmr2mqoy700z80fcc.jpg) JavaScript 中的 QR 程式碼產生器是一種允許使用者在 Web 應用程式中動態建立快速回應 (QR) 程式碼的工具。 QR 碼是二維條碼,可以包含各種類型的訊息,例如 URL、文字、聯絡資訊或 Wi-Fi 憑證。 [預覽和程式碼](https://dev.to/murtuzaalisurti/how-to-make-a-qr-code-generator-using-vanilla-javascript-3cla) #### 測驗應用程式 JavaScript ![測驗應用程式 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aj3aaque8i3myerfuvtn.jpg) JavaScript 中的測驗應用程式是一個互動式 Web 應用程式,它向使用者提出一系列問題並允許他們選擇答案。回答完所有問題後,應用程式會評估答案並提供回饋,例如總分和正確答案。 [預覽和程式碼](https://codingartistweb.com/2022/06/quiz-app-with-javascript/) #### 使用 Javascript 的天氣應用程式 ![使用 Javascript 的天氣應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u3wiz08coy82gig4xe6r.jpg) 使用 JavaScript 的天氣應用程式是一個 Web 應用程式,可為使用者提供特定位置的當前天氣資訊。它通常從天氣 API 檢索天氣資料、處理資料並將其顯示在使用者友好的介面中。 [預覽和程式碼](https://codingartistweb.com/2022/07/weather-app-with-javascript/) #### 自訂視訊播放器 ![自訂視訊播放器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xspo2vpcru8kjvpz6wye.jpg) JavaScript 中的自訂影片播放器是一個 Web JavaScript 專案,它提供用於播放影片內容的自訂使用者介面 (UI)。它通常包括播放、暫停、音量控制、播放速度調整、進度條、全螢幕模式和自訂樣式等功能。 [預覽和程式碼](https://codingartistweb.com/2022/07/custom-video-player-using-javascript/) #### 學生 JavaScript 專案 如果您是學生,那麼這些 JavaScript 專案將對您有很大幫助。 JavaScript 提供了適合不同技能水平的學生(從初學者到高級學習者)的各種專案。 這些專案不僅有助於強化基本概念,也提供 Web 開發的實務經驗。以下是一些**供學生使用的 javascript 專案想法**。 #### 星級評級 JavaScript ![星級評級 JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rm8udkic9kz59e4t528b.jpg) JavaScript 中的星級評級元件是一個學生導向的 JavaScript 專案,可讓使用者透過選擇代表不同滿意度或品質等級的星級來對專案進行評級。通常,它由一組水平排列的可點擊星形圖示組成,其中選定的星形突出顯示以指示使用者的評級。 [預覽和程式碼](https://dev.to/codingnepal/star-rating-system-in-html-css-javascript-97a) #### 五彩紙屑效果 Javascript ![五彩紙屑效果 Javascript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rd6ph3ag1fb4rfnrcgrl.jpg) JavaScript 中的五彩紙屑效果是指一種圖形效果,其中彩色「五彩紙屑」(小紙片或其他材料)在螢幕上散佈或投擲,通常以節日或慶祝的方式進行。 [預覽和程式碼](https://codingartistweb.com/2022/11/confetti-effect-javascript/) #### 刮刮卡Javascript ![刮刮卡Javascript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fsaou1alqoca7ks3swe8.jpg) JavaScript 中的刮刮卡是一個**最好的 js 專案**,它模仿刮掉隱藏區域以顯示下面內容的體驗,類似於彩票或促銷卡。在 Web 開發中,這種效果通常使用 HTML5 畫布元素和 JavaScript 來處理互動來實作。 [預覽和程式碼](https://codingartistweb.com/2022/08/scratch-card-with-javascript/) #### 用 Javascript 進行西蒙遊戲 ![用 Javascript 進行西蒙遊戲](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ob7ng3dcqnvhpbv5z7u2.jpg) 西蒙遊戲是一款經典的記憶技巧電子遊戲。它涉及一個播放一系列音調和燈光的設備,然後玩家必須重複該序列。 在 Simon 遊戲的 JavaScript 實作中,您通常會建立一個使用者介面,其中的按鈕代表每種顏色,遊戲邏輯將涉及產生和顯示一系列顏色供玩家模仿。 [預覽和程式碼](https://dev.to/nanythery/coding-my-first-game-with-javascript-simon-says-60d) #### 自訂音樂播放器 Javascript ![自訂音樂播放器 Javascript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yoexh51at6t9gbau64rb.jpg) 使用 JavaScript 建立自訂音樂播放器涉及建立允許使用者控制音訊播放的使用者介面。[預覽和程式碼](https://dev.to/codingnepal/create-custom-music-player-in-javascript-2367) #### 富文本編輯器 ![富文本編輯器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q7ajobdoysmcm3a8mok0.jpg) 富文本編輯器是一個元件,使用戶能夠使用類似於文字處理器的各種樣式和格式選項來編輯和格式化文字。這些編輯器通常提供粗體、斜體、底線、文字對齊、專案符號、編號清單等功能。 [預覽和程式碼](https://codingartistweb.com/2022/04/rich-text-editor-with-javascript/) > 如果您喜歡這些最佳 JavaScript 專案,那麼我將向此列表加入更多專案。請不要忘記喜歡分享和關注。 使用可用原始碼開始**JavaScript 專案**是增強程式設計技能和擴展知識的絕佳方法。透過剖析現有專案,您可以學習其他人的程式碼,了解不同的設計模式,並發現針對常見挑戰的創新解決方案。😊😊 希望您喜歡這些 JavaScript 專案。您將在我給出的源程式碼連結中獲得逐步說明。希望最佳 JavaScript 專案創意能幫助您增加 JavaScript 知識。 ![專案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/urerlcgx7v4wkjxqvtmk.jpg) 因此,捲起袖子,深入研究原始碼,開始建立一些令人驚奇的東西! 🥳🥳 --- 原文出處:https://dev.to/shantanu_jana/100-javascript-projects-with-source-code-59lo

6 個月內成為後端開發人員的技能(路線圖)

讓我給你一個簡單的🚦路線圖,讓你知道你現在在哪裡以及下一步應該去哪裡。 ![Shahan 在 6 個月內成為後端開發人員的技能](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3uek3ahjesssiakqs0xe.jpeg) 🔑關鍵概念 ----- 每個網站都有兩個部分。一個**前端**,一個**後端**。 前端是您在瀏覽器中看到它並與之互動的部分。**所有視覺方面**。 後端是為前端提供動力的部分。它*在幕後*,**主要是儲存資料和資料庫**並提供給前端。 🌐工作 --- 因此,網路開發工作分為`three categories` 。 - 👨‍💻前端開發 - 🛟後端開發 - 🚢以及全端開發(涉及前端和後端開發) 👷‍♂️後端開發人員到底是做什麼的? ------------------ 後端開發人員負責建立驅動用戶所使用的應用程式*功能*的**基礎系統**。 這包括設計架構、實施和維護這些關鍵系統等各種任務。 他們的職責通常涉及與: - 💾 資料庫,例如MySQL, - ✂️ 框架,例如 Laravel 或 Ruby on Rails,以及 - 🧨 API(應用程式介面)。 他們的專業知識確保後端基礎設施無縫執行,從而實現使用者介面與底層資料和流程之間的順暢互動。 如果您不知道的話,這是後端開發人員的`core`職責: |任務|描述| |---|---| |了解績效需求與目標 |了解網站的效能要求和目標 | | API的開發與管理|為網站建立和管理 API | |開發資料儲存與處理系統|建置系統以安全地儲存和處理支付處理等流程所需的資料| |編寫、測試和維護程式碼 |編寫程式碼、測試和開發編碼問題的解決方案,包括維護任務 | |設計網站架構|使用敏捷 Scrum 和框架等既定方法設計網站架構 | |組織系統邏輯|有效建構系統邏輯| |提供系統問題的解決方案|提供解決方案來解決與系統相關的問題和挑戰 | --- 🥷 六個月內成為後端開發人員的技能 ----------------- 成為熟練的後端開發人員需要在相對較短的時間內掌握各種技能和技術。 下面,我概述了一個**全面的路線圖**,以幫助您在六個月內實現這一目標: **第 1 個月:🦴後端開發基礎** - **第一週:**了解後端開發人員的角色和職責。熟悉資料庫、框架和 API。 - **第 2-3 週:**參加資料庫綜合課程。了解 SQL 和 MySQL 等關聯式資料庫。練習建立和管理資料庫。 - **第 4 週:**了解伺服器端程式語言。從 PHP 或 Python 開始。學習基本語法、控制結構和資料類型。 **第 2 個月:🍖高階後端概念** - **第 1-2 週:**加深對資料庫的理解。探索 MongoDB 等 NoSQL 資料庫。了解*資料建模和優化*。 - **第 3-4 週:**掌握伺服器端程式語言。深入研究 PHP 或 Python。了解函數、類別和物件導向程式設計。 - **最後 2 天:**使用框架進行實踐專案。選擇流行的框架,例如*適用於 PHP 的 Laravel 或適用於 Python 的 Django* 。建立簡單的應用程式以理解模型-視圖-控制器 (MVC) 架構。 **第 3 個月:🌦️API 開發和集成** - **第 1-2 週:**了解 API 及其在後端開發中的重要性。探索 RESTful API 設計原則。 - **第 3 週:**開始建立您自己的 API。使用`Postman`等工具來測試和偵錯 API 端點。了解身份驗證和安全性。 - **第 4 週:**關注*API 整合*。了解如何在 Web 和行動應用程式中使用 API。練習將第三方 API 整合到您的專案中。 **第 4 個月:🛸故障排除與最佳化** - **第 1-2 週:**掌握故障排除技術。了解如何有效診斷和除錯後端應用程式。 - **第 3 週:**進入效能優化階段。了解快取、負載平衡和資料庫索引。 - **第 4 週:**學習監控和分析工具。使用 New *Relic 或 Datadog*等工具來監控應用程式效能。了解如何產生和**分析**績效指標。 **第 5 個月:🌥️雲端基礎設施和部署** - **第 1 週:**了解雲端運算概念。了解 AWS 或 Azure 等流行的雲端供應商。 - **第 2-4 週:**學習後端開發雲端服務課程。了解無伺服器運算、容器化和微服務。 - **休息日:**練習將應用程式部署到雲端。了解 CI/CD 管道和自動化部署策略。 **第 6 個月:🏗️高級主題和專案** - **第 1-2 週:**在上個月,學習更多高階後端主題。選擇訊息佇列、事件驅動架構和即時通訊等主題。 - **第 3 週:**開展*頂點計畫*。選擇一個具有挑戰性的專案,整合各種後端技術和概念。 - **第 4 週:**最後,反思您的學習歷程。審查您的專案並確定需要改進的領域。透過練習**程式設計挑戰**來準備工作面試。 ⛏️後端開發:工具與軟體 ------------ 以下是後端開發中常用的工具和軟體的細分: **1. 📇資料庫框架:** - **MySQL:**用於儲存和檢索資料的關聯式資料庫管理系統。它廣泛用於 Web 應用程式,並提供可擴展性和可靠性。 - **MongoDB:**一種 NoSQL 資料庫程序,使用具有模式彈性的類似 JSON 的文件。它適用於資料模型快速變化或非結構化資料的應用程式。 **2. 🛝網路伺服器:** - **Apache HTTP Server 2:**一種開源 Web 伺服器軟體,可透過網際網路提供 Web 內容。它以其穩定性、安全性和靈活性而聞名,使其成為託管網站和 Web 應用程式的熱門選擇。 **3. 🔐安全協定:** - **SSL/TLS 憑證:**這些是透過電腦網路提供安全通訊的加密協定。 SSL(安全通訊端層)及其後繼者 TLS(傳輸層安全性)對伺服器和用戶端之間的資料進行加密,確保線上連線的機密性和完整性。 **4. 💫版本控制系統:** - 接下來,請熟悉版本控制系統。這些系統有助於追蹤專案歷史並實現與其他人的協作工作。 - 🔌 吉特: - Git 是使用最廣泛的版本控制系統,超過 70% 的軟體開發團隊都在使用。這是一個必須知道的工具,建議分配大約兩週的時間來學習 Git。 後端開發人員通常利用這些工具和軟體來建立強大、可擴展且安全的 Web 應用程式,用於處理資料儲存、伺服器託管和線上通訊加密。 如果您尋求有關後端開發的更多知識,請考慮查看此[深入的後端開發路線圖](https://roadmap.sh/backend)。 --- 👏結論 --- 透過遵循此時間表並持續努力學習,您可以在 6 個月內獲得寶貴的後端開發技能,並為找到後端開發工作做好充分準備。 如果您想在六個月內成為前端開發人員,您也可以閱讀這篇文章。 👇 [6 個月內成為前端開發人員的路線圖](https://dev.to/codewithshahan/must-have-frontend-development-skills-roadmap-2024-28jc) 最後,如果你想知道[前端開發的未來](https://dev.to/codewithshahan/the-future-of-frontend-development-1amd),你也可以看看這篇文章。 請關注更多有價值的內容,如果您覺得有幫助,您可能也會喜歡我的[YouTube 頻道](https://www.youtube.com/programmingwithshahan)。 感謝您花時間閱讀這篇文章。 🤳我的社交: [X](https://twitter.com/shahancd) --- 原文出處:https://dev.to/codewithshahan/skills-to-become-a-backend-developer-in-6-months-roadmap-4li3

為 Lambda 函數設定外觀的 5 種方法:DevTools 比較指南

長話短說 ---- 俗話說,給貓剝皮有多種方法…在科技界,給 Lambda 函數剝皮有 5 種方法 🤩 我們將比較 5 個開發工具 - ✅[翼](#1-wing) - ✅[刷子](#2-pulumi) - ✅ [AWS-CDK](#3-awscdk) - ✅ [Terraform 的 CDK](#4-cdk-for-terraform) - ✅[地形](#5-terraform) 介紹 -- 當開發人員試圖彌合開發和 DevOps 之間的差距時,我認為比較程式語言和 DevTools 會很有幫助。 讓我們從一個簡單函數的想法開始,該函數將文字檔案上傳到我們的雲端應用程式中的儲存桶。 下一步是展示實現這一目標的幾種方法。 **注意:**在雲端開發中,管理權限和儲存桶身分、打包執行時程式碼以及處理基礎架構和執行時的多個檔案會增加開發過程的複雜性。 ![讓我們開始吧](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6kd69m1hntlzy1icrlba.gif) 讓我們深入研究一些程式碼! --- 1.[翼](https://github.com/winglang/wing) --------------------------------------- > [安裝 Wing](https://www.winglang.io/docs)後,讓我們建立一個檔案: `main.w` > 如果您不熟悉 Wing 程式語言,請查看[此處的](https://github.com/winglang/wing)**開源儲存庫** ``` bring cloud; let bucket = new cloud.Bucket(); new cloud.Function(inflight () => { bucket.put("hello.txt", "world!"); }); ``` **讓我們詳細分析一下上面程式碼中發生的情況。** > `bring cloud`是 Wing 的導入語法 > **建立一個雲端儲存桶:** `let bucket = new cloud.Bucket();`初始化一個新的雲端儲存桶實例。 > 在後端,Wing 平台在您的雲端供應商環境中配置一個新儲存桶。此桶用於儲存和檢索資料。 > **建立雲端函數:** `new cloud.Function(inflight () => { ... });`語句定義了一個新的雲函數。 > 該函數被觸發後,將執行其主體內定義的操作。 > `bucket.put("hello.txt", "world!");`上傳一個名為 hello.txt 的文件,其中包含內容世界!到之前建立的雲端儲存桶。 編譯並部署到 AWS ---------- - `wing compile --platform tf-aws main.w` - `terraform apply` 就是這樣,Wing 負責處理複雜性(權限、在執行時程式碼中獲取存儲桶身份、將執行時程式碼打包到存儲桶中、必須編寫多個文件 - 用於基礎設施和執行時)等。 更不用說它會產生 IAC(TF 或 CF),以及可以使用現有工具部署的 Javascript。 但在開發時,您可以使用本機模擬器獲得即時回饋並縮短迭代周期 ![翼控制台](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yea3ozudbqxbxr0hh1t5.gif) Wing 甚至還有一個[遊樂場](https://www.winglang.io/play/?code=YgByAGkAbgBnACAAYwBsAG8AdQBkADsACgAKAGwAZQB0ACAAYgB1AGMAawBlAHQAIAA9ACAAbgBlAHcAIABjAGwAbwB1AGQALgBCAHUAYwBrAGUAdAAoACkAOwAKAAoAbgBlAHcAIABjAGwAbwB1AGQALgBGAHUAbgBjAHQAaQBvAG4AKABpAG4AZgBsAGkAZwBoAHQAIAAoACkAIAA9AD4AIAB7AAoAIAAgAGIAdQBjAGsAZQB0AC4AcAB1AHQAKAAiAGgAZQBsAGwAbwAuAHQAeAB0ACIALAAgACIAdwBvAHIAbABkACEAIgApADsACgB9ACkAOwA%3D),您可以在瀏覽器中試用! 2.[刷子](https://www.pulumi.com) ------------------------------ > 步驟1:初始化一個新的Pulumi專案 ``` mkdir pulumi-s3-lambda-ts cd pulumi-s3-lambda-ts pulumi new aws-typescript ``` > 步驟 2. 編寫程式碼以將文字檔案上傳到 S3。 這將是您的專案結構。 ``` pulumi-s3-lambda-ts/ ├─ src/ │ ├─ index.ts # Pulumi infrastructure code │ └─ lambda/ │ └─ index.ts # Lambda function code to upload a file to S3 ├─ tsconfig.json # TypeScript configuration └─ package.json # Node.js project file with dependencies ``` 讓我們將此程式碼加入**index.ts** ``` import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; // Create an AWS S3 bucket const bucket = new aws.s3.Bucket("myBucket", { acl: "private", }); // IAM role for the Lambda function const lambdaRole = new aws.iam.Role("lambdaRole", { assumeRolePolicy: JSON.stringify({ Version: "2023-10-17", Statement: [{ Action: "sts:AssumeRole", Principal: { Service: "lambda.amazonaws.com", }, Effect: "Allow", Sid: "", }], }), }); // Attach the AWSLambdaBasicExecutionRole policy new aws.iam.RolePolicyAttachment("lambdaExecutionRole", { role: lambdaRole, policyArn: aws.iam.ManagedPolicy.AWSLambdaBasicExecutionRole, }); // Policy to allow Lambda function to access the S3 bucket const lambdaS3Policy = new aws.iam.Policy("lambdaS3Policy", { policy: bucket.arn.apply(arn => JSON.stringify({ Version: "2023-10-17", Statement: [{ Action: ["s3:PutObject", "s3:GetObject"], Resource: `${arn}/*`, Effect: "Allow", }], })), }); // Attach policy to Lambda role new aws.iam.RolePolicyAttachment("lambdaS3PolicyAttachment", { role: lambdaRole, policyArn: lambdaS3Policy.arn, }); // Lambda function const lambda = new aws.lambda.Function("myLambda", { code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive("./src/lambda"), }), runtime: aws.lambda.Runtime.NodeJS12dX, role: lambdaRole.arn, handler: "index.handler", environment: { variables: { BUCKET_NAME: bucket.bucket, }, }, }); export const bucketName = bucket.id; export const lambdaArn = lambda.arn; ``` 接下來,為 Lambda 函數程式碼建立**lambda/index.ts**目錄: ``` import { S3 } from "aws-sdk"; const s3 = new S3(); export const handler = async (): Promise<void> => { const bucketName = process.env.BUCKET_NAME || ""; const fileName = "example.txt"; const content = "Hello, Pulumi!"; const params = { Bucket: bucketName, Key: fileName, Body: content, }; try { await s3.putObject(params).promise(); console.log(`File uploaded successfully at https://${bucketName}.s3.amazonaws.com/${fileName}`); } catch (err) { console.log(err); } }; ``` > 步驟 3:TypeScript 設定 (tsconfig.json) ``` { "compilerOptions": { "target": "ES2018", "module": "CommonJS", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*.ts"], "exclude": ["node_modules", "**/*.spec.ts"] } ``` **建立Pulumi專案後,會自動產生yaml檔案。** **pulumi.yaml** ``` name: s3-lambda-pulumi runtime: nodejs description: A simple example that uploads a file to an S3 bucket using a Lambda function template: config: aws:region: description: The AWS region to deploy into default: us-west-2 ``` 與 Pulumi 一起部署 ------------- 確保正確設定包含`index.js`檔案的`lambda`目錄。然後,執行以下命令來部署您的基礎架構: `pulumi up` --- 3. [AWS-CDK](https://aws.amazon.com/cdk) ---------------------------------------- > 步驟1:初始化一個新的CDK專案 ``` mkdir cdk-s3-lambda cd cdk-s3-lambda cdk init app --language=typescript ``` > 第 2 步:新增依賴項 ``` npm install @aws-cdk/aws-lambda @aws-cdk/aws-s3 ``` > 步驟 3:在 CDK 中定義 AWS 資源 文件: **index.js** ``` import * as cdk from '@aws-cdk/core'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; export class CdkS3LambdaStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Create the S3 bucket const bucket = new s3.Bucket(this, 'MyBucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, // NOT recommended for production code }); // Define the Lambda function const lambdaFunction = new lambda.Function(this, 'MyLambda', { runtime: lambda.Runtime.NODEJS_14_X, // Define the runtime handler: 'index.handler', // Specifies the entry point code: lambda.Code.fromAsset('lambda'), // Directory containing your Lambda code environment: { BUCKET_NAME: bucket.bucketName, }, }); // Grant the Lambda function permissions to write to the S3 bucket bucket.grantWrite(lambdaFunction); } } ``` > 步驟 4:Lambda 函數程式碼 在 pulumi 目錄中建立與上面相同的檔案結構: **index.ts** ``` import { S3 } from 'aws-sdk'; const s3 = new S3(); exports.handler = async (event: any) => { const bucketName = process.env.BUCKET_NAME; const fileName = 'uploaded_file.txt'; const content = 'Hello, CDK! This file was uploaded by a Lambda function!'; try { const result = await s3.putObject({ Bucket: bucketName!, Key: fileName, Body: content, }).promise(); console.log(`File uploaded successfully: ${result}`); return { statusCode: 200, body: `File uploaded successfully: ${fileName}`, }; } catch (error) { console.log(error); return { statusCode: 500, body: `Failed to upload file: ${error}`, }; } }; ``` 部署 CDK 堆疊 --------- 首先,編譯 TypeScript 程式碼: `npm run build` ,然後 將您的 CDK 部署到 AWS: `cdk deploy` --- [4.Terraform 的 CDK](https://developer.hashicorp.com/terraform/cdktf) -------------------------------------------------------------------- > 步驟1:初始化一個新的CDKTF專案 ``` mkdir cdktf-s3-lambda-ts cd cdktf-s3-lambda-ts ``` 然後,使用 TypeScript 初始化一個新的 CDKTF 專案: ``` cdktf init --template="typescript" --local ``` > 步驟 2:安裝 AWS Provider 並新增相依性 ``` npm install @cdktf/provider-aws ``` > 第 3 步:定義基礎設施 編輯 main.ts 以定義 S3 儲存桶和 Lambda 函數: ``` import { Construct } from 'constructs'; import { App, TerraformStack } from 'cdktf'; import { AwsProvider, s3, lambdafunction, iam } from '@cdktf/provider-aws'; class MyStack extends TerraformStack { constructor(scope: Construct, id: string) { super(scope, id); new AwsProvider(this, 'aws', { region: 'us-west-2' }); // S3 bucket const bucket = new s3.S3Bucket(this, 'lambdaBucket', { bucketPrefix: 'cdktf-lambda-' }); // IAM role for Lambda const role = new iam.IamRole(this, 'lambdaRole', { name: 'lambda_execution_role', assumeRolePolicy: JSON.stringify({ Version: '2023-10-17', Statement: [{ Action: 'sts:AssumeRole', Principal: { Service: 'lambda.amazonaws.com' }, Effect: 'Allow', }], }), }); new iam.IamRolePolicyAttachment(this, 'lambdaPolicy', { role: role.name, policyArn: 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', }); const lambdaFunction = new lambdafunction.LambdaFunction(this, 'MyLambda', { functionName: 'myLambdaFunction', handler: 'index.handler', role: role.arn, runtime: 'nodejs14.x', s3Bucket: bucket.bucket, // Assuming the Lambda code is uploaded to this bucket s3Key: 'lambda.zip', // Assuming the Lambda code zip file is named lambda.zip environment: { variables: { BUCKET_NAME: bucket.bucket, }, }, }); // Grant the Lambda function permissions to write to the S3 bucket new s3.S3BucketPolicy(this, 'BucketPolicy', { bucket: bucket.bucket, policy: bucket.bucket.apply(name => JSON.stringify({ Version: '2023-10-17', Statement: [{ Action: 's3:*', Resource: `arn:aws:s3:::${name}/*`, Effect: 'Allow', Principal: { AWS: role.arn, }, }], })), }); } } const app = new App(); new MyStack(app, 'cdktf-s3-lambda-ts'); app.synth(); ``` > 步驟 4:Lambda 函數程式碼 Lambda 函數程式碼應使用 TypeScript 編寫並編譯為 JavaScript,因為 AWS Lambda 本機執行 JavaScript。以下是您需要編譯和壓縮的 Lambda 函數的範例**index.ts** : ``` import { S3 } from 'aws-sdk'; const s3 = new S3(); exports.handler = async () => { const bucketName = process.env.BUCKET_NAME || ''; const content = 'Hello, CDKTF!'; const params = { Bucket: bucketName, Key: `upload-${Date.now()}.txt`, Body: content, }; try { await s3.putObject(params).promise(); return { statusCode: 200, body: 'File uploaded successfully' }; } catch (err) { console.error(err); return { statusCode: 500, body: 'Failed to upload file' }; } }; ``` 您需要將此 TypeScript 程式碼編譯為 JavaScript,對其進行壓縮,然後手動或使用腳本將其上傳到 S3 儲存桶。 確保 LambdaFunction 資源中的 s3Key 指向儲存桶中正確的 zip 檔案。 編譯和部署您的 CDKTF 專案 ---------------- 使用`npm run build`編譯專案 **生成 Terraform 配置文件** 執行`cdktf synth`指令。此命令執行您的 CDKTF 應用程式,該應用程式在`cdktf.out`目錄中產生 Terraform 設定檔( `*.tf.json`檔案): **部署您的基礎設施** `cdktf deploy` 5.[地形](https://developer.hashicorp.com/terraform) ------------------------------------------------- > 第 1 步:Terraform 設定 定義您的 AWS 供應商和 S3 儲存桶 使用以下內容建立名為**main.tf**的檔案: ``` provider "aws" { region = "us-west-2" # Choose your AWS region } resource "aws_s3_bucket" "lambda_bucket" { bucket_prefix = "lambda-upload-bucket-" acl = "private" } resource "aws_iam_role" "lambda_execution_role" { name = "lambda_execution_role" assume_role_policy = jsonencode({ Version = "2023-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "lambda.amazonaws.com" } }, ] }) } resource "aws_iam_policy" "lambda_s3_policy" { name = "lambda_s3_policy" description = "IAM policy for Lambda to access S3" policy = jsonencode({ Version = "2023-10-17" Statement = [ { Action = ["s3:PutObject", "s3:GetObject"], Effect = "Allow", Resource = "${aws_s3_bucket.lambda_bucket.arn}/*" }, ] }) } resource "aws_iam_role_policy_attachment" "lambda_s3_access" { role = aws_iam_role.lambda_execution_role.name policy_arn = aws_iam_policy.lambda_s3_policy.arn } resource "aws_lambda_function" "uploader_lambda" { function_name = "S3Uploader" s3_bucket = "YOUR_DEPLOYMENT_BUCKET_NAME" # Set your deployment bucket name here s3_key = "lambda.zip" # Upload your ZIP file to S3 and set its key here handler = "index.handler" role = aws_iam_role.lambda_execution_role.arn runtime = "nodejs14.x" environment { variables = { BUCKET_NAME = aws_s3_bucket.lambda_bucket.bucket } } } ``` > 步驟 2:Lambda 函數程式碼 (TypeScript) 為 Lambda 函數建立 TypeScript 檔案**index.ts** : ``` import { S3 } from 'aws-sdk'; const s3 = new S3(); exports.handler = async (event: any) => { const bucketName = process.env.BUCKET_NAME; const fileName = `uploaded-${Date.now()}.txt`; const content = 'Hello, Terraform and AWS Lambda!'; try { await s3.putObject({ Bucket: bucketName!, Key: fileName, Body: content, }).promise(); console.log('Upload successful'); return { statusCode: 200, body: JSON.stringify({ message: 'Upload successful' }), }; } catch (error) { console.error('Upload failed:', error); return { statusCode: 500, body: JSON.stringify({ message: 'Upload failed' }), }; } }; ``` 最後,將 Lambda 函數程式碼上傳到指定的 S3 儲存桶後,執行`terraform apply` 。 --- 我希望您喜歡在我們的雲端應用程式中編寫將文字檔案上傳到儲存桶的函數的五種簡單方法的比較。 正如您所看到的,除了一段程式碼之外,大多數程式碼都變得非常複雜。 結論! --- [![泰勒絲](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eawrorng82lqrl8lt54w.gif)](https://github.com/winglang/wing) 點擊圖片⬆️ ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/urh67eorvbn49cgbaae6.gif) > 如果您對 Wing 感興趣並且喜歡我們如何簡化雲端開發流程,請給我們一顆 ⭐ 顆星。 {% cta https://github.com/winglang/wing %} 請star ⭐ Wing {% endcta %} --- 原文出處:https://dev.to/winglang/5-ways-to-write-a-simple-function-in-your-cloud-app-1jgl

css 表格樣式指南

我最近注意到一個小悖論:很多年前——在 CSS 網格出現之前——我們使用`<table>`來模擬網格佈局。現在我們*有了*網格佈局,我們用它們來模擬表格!這是錯誤的。表格用於**表格**資料;在一堆`<div>`中呈現表格資料是沒有意義的。 造成這種弊端的原因可能是因為表格的樣式可能**有點**棘手,而且大多數 CSS 框架使用`border-collapse: collapse`作為預設的表格樣式。正如我們將在本教程中看到的,折疊邊框對於表格樣式並不總是有用。 讓我們研究一下`<table>`的元素,然後了解如何建立它們並設定它們的樣式。 元素 -- 除了`<table>`元素本身之外,您只需要這 3 個標籤來建立基本表格: |標籤 |描述 | | ---- | ---| | `td` |表資料單元 | | `th` |表格標題儲存格 | | `tr` |表行| *例子:* ``` <table> <tr><th>Header</th></tr> <tr><td>Content</td></tr> </table> ``` 但是,為了更好地構造表,我們可以將行封裝在: |標籤 |描述 | | -------- | ---| | `thead` |表頭 | | `tbody` |桌體| | `tfoot` |表頁腳| 最後,我們可以在表格中新增`<caption>` ,並在`<colgroup>`內的`<col>`標籤中定義列。 *例子:* ``` <table> <caption>Super Heroes</caption> <colgroup><col><col><col><col></colgroup> <thead> <tr><th>First Name</th><th>Last Name</th><th>Known As</th><th>Place</th></tr> </thead> <tbody> <tr><td>Bruce</td><td>Wayne</td><td>Batman</td><td>Gotham City</td></tr> <tr><td>Clark</td><td>Kent</td><td>Superman</td><td>Metropolis</td></tr> <tr><td>Tony</td><td>Stark</td><td>Iron Man</td><td>Malibu</td></tr> <tr><td>Peter</td><td>Parker</td><td>Spider-Man</td><td>New York City</td></tr> <tr><td>Matt</td><td>Murdock</td><td>Daredevil</td><td>New York City</td></tr> </tbody> </table> ``` 如果沒有任何樣式,您的瀏覽器將呈現以下內容: ![基本表格瀏覽器樣式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iq375md00ma4g8bikaqj.png) 預設的用戶代理樣式是: ``` table { border-collapse: separate; text-indent: initial; border-spacing: 2px; } ``` 現在,如果我們加入一個超級簡單的規則: ``` :is(td,th) { border-style: solid; } ``` 我們得到: ![實心邊框基本表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9o8sa2igklyxz78ec2ij.png) 注意單獨的邊框。看起來不太好看... 因此,為了了解折疊邊框的流行(以及更好的字體!),如果我們簡單地加入: ``` table { border-collapse: collapse; font-family: system-ui; } ``` ……我們得到: ![border-collapse 設定為折疊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/beia4yujksm8c5945o7s.png) 如果我們然後將`padding: .5ch 1ch`加入我們的`:is(td,th)`選擇器並將`margin-block: 1rlh`加入`<caption>` ,我們會得到: ![基本表格樣式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6tai5jys59g9q0sg3t5w.png) 回顧一下,我們**需要**得到上述樣式的是: ``` table { border-collapse: collapse; font-family: system-ui; & caption { margin-block: 1rlh; } &:is(td, th) { border-style: solid; padding: .5ch 1ch; } } ``` 若要將`<caption>`放置在表格*下方*,請使用: ``` table { caption-side: bottom; } ``` --- 斑馬條紋 ---- 要為**columns**加入奇數/偶數斑馬條紋,我們可以簡單地設定`<col>`標籤的樣式: ``` col:nth-of-type(even) { background: #F2F2F2; } ``` ![斑馬山口](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlnajfbyvxsgzlgbntge.png) 對於行,它是類似的: ``` tr:nth-of-type(odd) { background: #F2F2F2; } ``` ![斑馬行](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p47mwf3x6dp8n5qit72d.png) --- 圓角 -- 圓角有點棘手。您不能只將`border-radius`新增至`<table>` ,因此我們必須定位**第一行**和**最後**一行的**第**一個和**最後**一個儲存格: ``` th { &:first-of-type { border-start-start-radius: .5em } &:last-of-type { border-start-end-radius: .5em } } tr { &:last-of-type { & td { &:first-of-type { border-end-start-radius: .5em } &:last-of-type { border-end-end-radius: .5em } } } } ``` ……但仍然沒有發生任何事情!那是因為: > 如果您的表格有折疊邊框,則**無法**新增`border-radius` 。 因此,我們必須使用**單獨的**邊框,並*模仿*折疊的邊框: ``` table { border-spacing: 0; } :is(td, th) { border-block-width: 1px 0; border-inline-width: 1px 0; &:last-of-type { border-inline-end-width: 1px } } ``` **現在**我們有了圓角: ![圓角](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/172o5rqyidiqisopyrx6.png) --- 拆分列 --- 讓我們*保留*單獨的列,並使用`border-spacing`屬性在列之間新增間隙: ``` table { border-spacing: 2ch 0; & :is(td, th) { border-inline-width: 1px; } } ``` ![拆分列](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uplqw0uurk0yk7ot2k1k.png) 我們甚至可以加入`border-radius` : ![邊界半徑](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ldecau6tm4elj68hz7id.png) 這仍然只是一個`<table>` ,但如果用作“比較表”,則更具可讀性。 --- 分割行 --- 對於分割行,我們只需要更新`border-spacing`屬性的第二部分(y 軸): ``` table { border-spacing: 0 2ch; & :is(td, th) { border-block-width: 1px; } } ``` ![分割行](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q118cu966qesqqyir6gc.png) --- 懸停和焦點 ----- 對於大桌子,準確了解您所在的*位置*非常重要。為此,我們需要`:hover` ,並且 - 如果您使用的是鍵盤可導航的表格 - `:focus-visble` -styles。 在此範例中,懸停樣式會套用於`<col>` 、 `<tr>`和`<td>` : ![表格懸停範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zy9wrlzfvt5us63ip8ae.png) 懸停行和單元格很簡單: ``` td:hover { background: #666666; } tr:hover { background: #E6E6E6; } ``` 將滑鼠懸停在`<col>`上有點複雜。 您可以新增一條規則: ``` col:hover { background: #E6E6E6; } ``` ...但這不起作用。奇怪的是,如果您在開發工具中選擇一個 col-element 並為其啟用`:hover` ,它會起作用 - 但在 IRL 中不起作用。 相反,我們需要使用`:has`捕獲單元格的懸停,*然後*設定`<col>`元素的樣式: ``` table { &:has(:is(td,th):nth-child(1):hover col:nth-child(1) { background: #E6E6E6; } ``` 發生什麼事了? 讓我們來分解一下: 如果我們的表格**有**一個`<td>`*或*`<th>` ,它是`nth-child(1)`並且當前*懸停*,**則**選擇具有**相同**`nth-child`選擇器的`<col>` ,並設定它的`background` 。 唷! ……**並且**您需要為每一列重複此程式碼: `nth-child(2)` 、 `nth-child(3)`等。 --- 概要 -- 在懸停時顯示輪廓也很簡單,單元格和行也是如此。您需要從偏移量中*扣除*寬度: ``` :is(td, th, tr):hover { outline: 2px solid #666; outline-offset: -2px; } ``` ![表格懸停:輪廓](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4ump8dctc5q6yrpdqif.png) ### 列輪廓 概述一列*非常*棘手,但看起來不錯: ![表格懸停:大綱列](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o8om2x4gtsizjl7bwj30.png) 如果單元格的`border-width`為`1px` ,您可以在懸停時將`<col>`的`border-width`設為`2px` ,但隨後整個表格會發生變化。 Álvaro Montoro 建議在`<col>`上使用背景漸變來模擬邊框,如果表格單元格是透明的,效果很好。 為了使其與`border-radius`一起工作並保留單元格可能具有的任何背景,我最終為每個單元格使用了一個偽元素: ``` :is(td,th) { position: relative; &::after { border-inline: 2px solid transparent; border-radius: inherit; content: ''; inset: -2px 0 0 0; position: absolute; } } tr:first-of-type th::after { border-block-start: 2px solid transparent; } tr:last-of-type td::after { border-block-end: 2px solid transparent; } ``` ……然後,與我們對 col-hover 所做的類似,在懸停時將所有單元格定位為具有相同的“col-index”: ``` :has(:is(td,th):nth-child(1):hover :is(td,th):nth-child(1) { border-color: #666; } ``` 對所有列重複此操作。 --- 對齊文字 ---- 在舊規範中,您可以為`<col>`元素新增`align`屬性。那不再起作用了。 範例:您想要將第二列中的文字置中並右對齊第四列中的文字: ![表:對齊文字](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/659ffi0cieppfs3p9xvf.png) 我們可以在表本身中新增*每*列的資料屬性,而不是在每個單元格中新增一個類別: ``` <table data-c2="center" data-c4="end"> ``` 然後,在 CSS 中: ``` [data-c2~="center"] tr > *:nth-of-type(2) { text-align: center; } [data-c4~="end"] tr > *:nth-of-type(4) { text-align: end; } ``` 對所有列重複此操作。 --- 結論 -- 表格樣式指南到此結束。 我沒有介紹`colspan` 、 `rowspan` 、 `scope`和`span` 。如果您想更深入地了解這些內容,我建議您閱讀[有關表的 MDN 頁面](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table)。 示範 -- 我在這裡製作了一個包含大量演示的 CodePen: https://codepen.io/stoumann/pen/RwdVxJM --- 原文出處:https://dev.to/madsstoumann/a-guide-to-styling-tables-28d2

堅實的原則:它們堅如磐石是有充分理由的!

剛開始接觸**物件導向編程**,對**SOLID**感到有點迷失?不用擔心,在本文中,我將向您解釋它並提供如何在程式碼開發中使用它的範例。 什麼是固體? ------ 在物件導向程式設計中, **SOLID**是五個設計原則的縮寫,旨在增強對軟體的理解、開發和維護。 透過應用這組原則,您應該注意到錯誤的減少、程式碼品質的提高、程式碼組織性更強、耦合性降低、重構增強以及程式碼重用的鼓勵。讓我們來看看他們。 1. S-單一職責原則 ----------- ![建議零售價](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v564d0p0s36fwo6imofo.png) > SRP - 單一職責原則 這確實很簡單,但非常重要:**一個類別應該有一個且只有一個改變的理由。** 不再建立具有多種功能和職責的類,是嗎?您可能遇到甚至建立了一個可以完成所有操作的類,即所謂的*God Class* 。目前看起來似乎沒問題,但是當您需要更改該類別的邏輯時,肯定會出現問題。 > 上帝類別:在OOP中,這是一個`do`或`knows`太多事情的類別。 ``` class ProfileManager { authenticateUser(username: string, password: string): boolean { // Authenticate logic } showUserProfile(username: string): UserProfile { // Show user profile logic } updateUserProfile(username: string): UserProfile { // Update user profile logic } setUserPermissions(username: string): void { // Set permission logic } } ``` 此**ProfileManager**類別執行**四個**不同的任務,違反了 SRP 原則。它正在驗證和更新資料、進行演示,最重要的是,它正在設定權限,所有這些都是同時進行的。 ### 這可能導致的問題 - `Lack of cohesion -`一個類別不應該承擔不屬於它自己的責任; - `Too much information in one place -`你的類別最終會產生許多依賴性並且難以進行更改; - `Challenges in implementing automated tests -`很難模擬這樣的類別。 現在,將**SRP**應用到`ProfileManager`類別中,讓我們來看看這個原則可以帶來的改進: ``` class AuthenticationManager { authenticateUser(username: string, password: string): boolean { // Authenticate logic } } class UserProfileManager { showUserProfile(username: string): UserProfile { // Show user profile logic } updateUserProfile(username: string): UserProfile { // Update user profile logic } } class PermissionManager { setUserPermissions(username: string): void { // Set permission logic } } ``` 您可能想知道, `can I apply this only to classes?`答案是:**完全不是**。您也可以(並且應該)將其應用於方法和函數。 ``` // ❌ function processTasks(taskList: Task[]): void { taskList.forEach((task) => { // Processing logic involving multiple responsibilities updateTaskStatus(task); displayTaskDetails(task); validateTaskCompletion(task); verifyTaskExistence(task); }); } // ✅ function updateTaskStatus(task: Task): Task { // Logic for updating task status return { ...task, completed: true }; } function displayTaskDetails(task: Task): void { // Logic for displaying task details console.log(`Task ID: ${task.id}, Description: ${task.description}`); } function validateTaskCompletion(task: Task): boolean { // Logic for validating task completion return task.completed; } function verifyTaskExistence(task: Task): boolean { // Logic for verifying task existence return tasks.some((t) => t.id === task.id); } ``` 美麗、優雅、有組織的程式碼。這個原則是其他原則的基礎;透過應用它,您應該建立高品質、可讀且可維護的程式碼。 2. O——開閉原則 ---------- ![OCP](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/epfur4p9r55iwbk9i4yy.png) > OCP-開閉原則 **物件或實體應該對擴充開放,但對修改關閉。**如果您需要加入功能,最好擴展而不是修改原始程式碼。 想像一下,您需要一個類別來計算某些多邊形的面積。 ``` class Circle { radius: number; constructor(radius: number) { this.radius = radius; } area(): number { return Math.PI * this.radius ** 2; } } class Square { sideLength: number; constructor(sideLength: number) { this.sideLength = sideLength; } calculateArea(): number { return this.sideLength ** 2; } } class areaCalculator { totalArea(shapes: Shape[]): number { let total = 0; shapes.forEach((shape) => { if (shape instanceof Square) { total += (shape as any).calculateArea(); } else { total += shape.area(); } }); return total; } } ``` `areaCalculator`類別的任務是計算不同多邊形的面積,每個多邊形都有自己的面積邏輯。如果您,'lil dev,需要加入新形狀,例如三角形或矩形,您會發現自己**需要**更改此類來進行更改,對吧?這就是你遇到問題的地方,違反了`Open-Closed Principle` 。 我想到了什麼解決方案?可能會在類別中加入另一個方法並完成,問題解決了🤩。不完全是,年輕學徒😓,這就是問題所在! **修改現有類別以新增行為會帶來嚴重的風險,可能會將錯誤引入到已執行的內容中。** > 請記住:OCP 堅持認為類別應該對修改關閉,對擴展開放。 看看重構程式碼帶來的美妙之處: ``` interface Shape { area(): number; } class Circle implements Shape { radius: number; constructor(radius: number) { this.radius = radius; } area(): number { return Math.PI * this.radius ** 2; } } class Square implements Shape { sideLength: number; constructor(sideLength: number) { this.sideLength = sideLength; } area(): number { return this.sideLength ** 2; } } class AreaCalculator { totalArea(shapes: Shape[]): number { let total = 0; shapes.forEach((shape) => { total += shape.area(); }); return total; } } ``` 查看`AreaCalculator`類別:它不再需要知道要呼叫哪些方法來註冊該類別。它可以透過呼叫介面強加的契約來正確地呼叫區域方法,這是它唯一需要的。 > 只要它們實作了 Shape 接口,一切就可以正常運作。 &lt;br/&gt; > 分離介面背後的可擴展行為並反轉依賴關係。 &gt; > [鮑伯叔叔](https://en.wikipedia.org/wiki/Robert_C._Martin) - `Open for extension:`您可以為類別新增功能或行為,而無需變更其原始程式碼。 - `Closed for modification:`如果您的類別已經具有可以正常工作的功能或行為,請不要更改其原始程式碼以加入新內容。 3. L——里氏代換原理 ------------ ![LSP](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62uow23fsa5zk2wz5fz5.png) > LSP - 里氏替換原理 里氏替換原則指出**衍生類別必須可替換其基底類別。** 這個原則由 Barbara Liskov 在 1987 年提出,閱讀她的解釋可能會有點複雜。不過,不用擔心,我將提供另一個解釋和範例來幫助您理解。 > 如果對於 S 類型的每個物件 o1 都有一個 T 類型的物件 o2,使得對於所有用 T 定義的程式 P,當 o1 取代 o2 時 P 的行為保持不變,則 S 是 T 的子類型。 &gt; > 芭芭拉‧利斯科夫,1987 你做對了?不,可能不是。是的,我第一次讀時不明白(接下來的一百遍也不明白),但等等,還有另一種解釋: > 如果 S 是 T 的子類型,則程式中類型 T 的物件可以用類型 S 的物件替換,而不改變該程式的屬性。 &gt; > [維基百科](https://en.wikipedia.org/wiki/Liskov_substitution_principle) 如果您更喜歡視覺學習者,請不要擔心,這裡有一個例子: ``` class Person { speakName() { return "I am a person!"; } } class Child extends Person { speakName() { return "I am a child!"; } } const person = new Person(); const child = new Child(); function printName(message: string) { console.log(message); } printName(person.speakName()); // I am a person! printName(child.speakName()); // I am a child! ``` 父類別和衍生類別作為參數傳遞,程式碼繼續按預期工作。魔法?是的,這就是我們的朋友倒鉤的魔力。 ### 違規行為範例: - 重寫/實作一個不執行任何操作的方法; - 從基類傳回不同類型的值。 - 拋出意外的異常; 4. I——介面隔離原則 ------------ ![網際網路服務供應商](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qbdmugukrcacuqthho5x.png) > ISP-介面隔離原則 這句話說**不應該強迫一個類別實作它不使用的介面和方法。**建立更具體的介面比建立大而通用的介面更好。 在下面的範例中,建立一個**Book**介面來抽象化書籍行為,然後類別實作該介面: ``` interface Book { read(): void; download(): void; } class OnlineBook implements Book { read(): void { // does something } download(): void { // does something } } class PhysicalBook implements Book { read(): void { // does something } download(): void { // This implementation doesn't make sense for a book // it violates the Interface Segregation Principle } } ``` 通用`Book`介面迫使`PhysicalBook`類別做出毫無意義的行為(*或者我們在 Matrix 中下載實體書籍?* )並且違反了**ISP**和**LSP**原則。 使用**ISP**解決此問題: ``` interface Readable { read(): void; } interface Downloadable { download(): void; } class OnlineBook implements Readable, Downloadable { read(): void { // does something } download(): void { // does something } } class PhysicalBook implements Readable { read(): void { // does something } } ``` 現在好多了。我們從`Book`介面中刪除了`download()`方法,並將其加入到派生介面`Downloadable`中。這樣,行為就可以在我們的上下文中正確隔離,並且我們仍然尊重**介面隔離原則**。 5.D-依賴倒置原則 ---------- ![沾](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/42aomc36xq804pyldlis.png) > DIP - 依賴倒置原理 這個是這樣的:**依賴抽象而不是實現。** > 高層模組不應該依賴低層模組。兩者都應該依賴抽象。 &gt; > 抽像不應該依賴細節。細節應該取決於抽象。 &gt; > 鮑伯叔叔 現在我將展示一個簡單的程式碼來說明 DIP。在此範例中,有一個從資料庫取得使用者的服務。首先,讓我們建立一個與資料庫連接的具體類別: ``` // Low-level module class MySQLDatabase { getUserData(id: number): string { // Logic to fetch user data from MySQL database } } ``` 現在,讓我們建立一個取決於具體實作的服務類別: ``` // High-level module class UserService { private database: MySQLDatabase; constructor() { this.database = new MySQLDatabase(); } getUser(id: number): string { return this.database.getUserData(id); } } ``` 在上面的範例中, `UserService`直接依賴`MySQLDatabase`的具體實作。這違反了**DIP** ,因為**高級**類別 UserService 直接依賴**低階**類別。 如果我們想要切換到不同的資料庫系統(例如PostgreSQL),我們需要修改UserService類,這`AWFUL`了! 讓我們使用**DIP**修復此程式碼。高級類別`UserService`不應依賴特定實現,而應依賴抽象。讓我們建立一個`Database`介面作為抽象: ``` // Abstract interface (abstraction) for the low-level module interface Database { getUserData(id: number): string; } ``` 現在, `MySQLDatabase`和`PostgreSQLDatabase`的具體實作應該要實作這個介面: ``` class MySQLDatabase implements Database { getUserData(id: number): string { // Logic to fetch user data from MySQL database } } // Another low-level module implementing the Database interface class PostgreSQLDatabase implements Database { getUserData(id: number): string { // Logic to fetch user data from PostgreSQL database } } ``` 最後,UserService 類別可以依賴`Database`抽象: ``` class UserService { private database: Database; constructor(database: Database) { this.database = database; } getUser(id: number): string { return this.database.getUserData(id); } } ``` 這樣, `UserService`類別依賴`Database`抽象,而不是具體實現,滿足**依賴倒置原則**。 結論 -- 透過採用這些原則,開發人員可以建立更能適應變化的系統,使維護變得更容易,並隨著時間的推移提高程式碼品質。 本文的全部內容源自各種其他文章、我的個人筆記以及我**在深入研究物件導向程式設計 (OOP) 領域**時遇到的數十個線上影片。範例中使用的程式碼片段是基於我對這些原則的解釋和理解而建立的。我真的希望,我的小學徒,我能為促進你的理解和學習進步做出貢獻。 衷心希望您喜歡這篇文章,別忘了關注! 註:圖片取自[本文](https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898) --- 原文出處:https://dev.to/lukeskw/solid-principles-theyre-rock-solid-for-good-reason-31hn

我正在建立一個人工智慧專案:這是我將要使用的程式庫......

有了正確的函式庫,任何開發人員都可以在他們的應用程式中建立強大的人工智慧功能(如 Ninja 🥷)。 在此列表中,我編譯了 7 個很棒的 AI 庫,您現在可以使用它們(相對)輕鬆地發布功能。 不要忘記為這些圖書館加註星標以表達您的支持。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qqoipyuoxgb83swyoo4a.gif) https://github.com/CopilotKit/CopilotKit --- 1. [CopilotPortal](https://github.com/CopilotKit/CopilotKit) :建構應用程式原生人工智慧聊天機器人 ------------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0x1bwwzvc2mnrfrvsqn7.png) 應用程式內人工智慧聊天機器人助理可以「查看」您目前的應用程式狀態並在前端和後端採取操作。 一組完全可自訂的反應元件和掛鉤以及用於建立 LLM 和您的應用程式之間互動的架構。 定義*useMakeCopilotReadable* 、 *useMakeCopilotActionable*和*CopilotSidebarUIProvider*使其運作。 ``` import "@copilotkit/react-ui/styles.css"; import { CopilotProvider } from "@copilotkit/react-core"; import { CopilotSidebarUIProvider } from "@copilotkit/react-ui"; export default function App(): JSX.Element { return ( <CopilotProvider chatApiEndpoint="/api/copilotkit/chat"> <CopilotSidebarUIProvider> <YourContent /> </CopilotSidebarUIProvider> </CopilotProvider> ); } ``` https://github.com/CopilotKit/CopilotKit --- 2. [RAGxplorer](https://github.com/gabrielchua/RAGxplorer) - 視覺化並探索您的 RAG 文件 ---------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z365bk6wa7i4md3w4b5z.png) RAGxplorer 是一個 Python 工具,用於視覺化機器學習和自然語言處理中的 RAG(檢索增強生成)文件。 以互動方式探索 RAG 流程中使用的文件中的聯繫和內容。 若要設定 RAGxplorer,請在程式碼中定義 RAG 檢查點路徑並安裝指定的依賴項。 ``` import streamlit as st from utils.rag import build_vector_database st.set_page_config(page_title="RAGxplorer", page_icon="🔍") uploaded_file = st.file_uploader("Upload your PDF", type='pdf') query = st.text_input("Enter your query") search = st.button("Search") top_k = st.number_input("Number of Chunks", value=5, min_value=1) st.session_state["chroma"] = build_vector_database(uploaded_file, ...) st.session_state['retrieved_id'] = query_chroma(...) plot_embeddings(...) ``` https://github.com/gabrielchua/RAGxplorer --- 3. [Tavily GPT 研究員](https://github.com/assafelovic/gpt-researcher)- 獲得法學碩士以搜尋網路和資料庫 ----------------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4accv5t5ep1l1tkj4ze2.png) Tavilly 可讓您將 GPT 支援的研究和內容產生工具新增至您的 React 應用程式中,從而增強其資料處理和內容建立功能。 ``` # Create an assistant assistant = client.beta.assistants.create( instructions=assistant_prompt_instruction, model="gpt-4-1106-preview", tools=[{ "type": "function", "function": { "name": "tavily_search", "description": "Get information on recent events from the web.", "parameters": { "type": "object", "properties": { "query": {"type": "string", "description": "The search query to use. For example: 'Latest news on Nvidia stock performance'"}, }, "required": ["query"] } } }] ) ``` https://github.com/assafelovic/gpt-researcher --- 4. [Pezzo.ai](https://github.com/pezzolabs/pezzo) - 開發者優先的 LLMOps 平台 -------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nxvbgi5zkghkb0t64npw.jpeg) 用於管理 OpenAI 通話的集中平台。 優化您的提示和令牌使用。追蹤您的人工智慧使用情況。 免費且易於整合。 ``` const prompt = await pezzo.getPrompt("AnalyzeSentiment"); const response = await openai.chat.completions.create(prompt); ``` https://github.com/pezzolabs/pezzo --- 5. [DeepEval](https://github.com/confident-ai/deepeval) - 評估 LLM、RAG 和微調性能 -------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dowjupr91bepvopxsudd.jpeg) DeepEval 是一個開源框架,透過將評估視為單元測試來簡化法學碩士的評估。 它提供了評估 LLM 輸出的各種指標,其模組化設計允許開發人員定制他們的評估流程 要使用它,您需要安裝該程式庫、編寫測試案例並執行這些用例來評估您的 LLM 的效能。 ``` Pytest Integration: from deepeval import assert_test from deepeval.metrics import HallucinationMetric from deepeval.test_case import LLMTestCase test_case = LLMTestCase( input="How many evaluation metrics does DeepEval offers?", actual_output="14+ evaluation metrics", context=["DeepEval offers 14+ evaluation metrics"] ) metric = HallucinationMetric(minimum_score=0.7) def test_hallucination(): assert_test(test_case, [metric]) ``` https://github.com/confident-ai/deepeval --- 6. [CopilotTextarea](https://github.com/RecursivelyAI/CopilotKit) - React 應用程式中的 AI 驅動寫作 ---------------------------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2ctyhzd1hytek22s500.gif) 具有 Github CopilotX 功能的任何 React `<textarea>`的直接替代品。 自動完成、插入、編輯。 可以即時或由開發人員提前提供任何上下文。 ``` import { CopilotTextarea } from "@copilotkit/react-textarea"; import { CopilotProvider } from "@copilotkit/react-core"; // Provide context... useMakeCopilotReadable(...) // in your component... <CopilotProvider> <CopilotTextarea/> </CopilotProvider>` ``` https://github.com/RecursivelyAI/CopilotKit --- 7. [SwirlSearch](https://github.com/swirlai/swirl-search) - 人工智慧驅動的搜尋。 ---------------------------------------------------------------------- ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b8f4hycstwmx2gev8di7.gif) Swirl Search 是一個開源平台,它使用人工智慧同時搜尋多個資料來源並提供有關這些資料的起草報告。 它可以跨各種來源進行搜尋,包括搜尋引擎、資料庫和雲端服務,並且可以按照儲存庫中提供的安裝說明輕鬆設定。 Swirl Search 建置在 Python/Django 堆疊上,在 Apache 2.0 授權下發布,並作為 Docker 映像提供,使其可供使用者存取和自訂。 https://github.com/swirlai/swirl-search --- 謝謝閱讀!不要忘記為文章加入書籤,給出您的反應,並支持和查看提到的很棒的庫。 乾杯! --- 原文出處:https://dev.to/copilotkit/im-building-an-ai-project-here-are-the-libraries-im-going-to-use-pd0

資料庫 101:如何為 100 萬玩家的遊戲建立排行榜模型。

有沒有想過像**《英雄聯盟》** 、 **《要塞英雄**》甚至**《Rockband》**這樣的遊戲是如何建立排行榜模型的?在本文中,我們將了解如何正確建模模式以以極其高效的方式處理它們! 如果您剛開始使用一般資料庫或資料庫,您可能需要閱讀我的第一篇文章[《資料庫 101:初學者的資料一致性](https://dev.to/danielhe4rt/database-101-why-so-interesting-1344)》。那篇文章記錄了我自己對有多少資料庫範例的探索,因為我的眼光遠遠超出了我以前僅使用 SQL 和 MySQL 的經驗。我正在**資料庫 101**系列中追蹤我的研究。 > 距離我發表本系列的第一篇文章已經快一年了!感謝您在我學習主題時與我在一起。您的評論和想法總是非常有幫助! 1. 序言 ----- ![YARG 遊戲玩法截圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvensca2v67ma66vssnh.png) 從我還是個孩子的時候起,就像大多數普通開發者一樣,我就對遊戲及其製作方式著迷。說到這裡,我要跟大家介紹一下我兒時最喜歡的遊戲:《吉他英雄3:搖滾傳奇》。 十多年後,我決定嘗試在開源環境中為一些遊戲做出貢獻,例如[rust-ro(Rust Ragnarok Emulator)](https://github.com/nmeylan/rust-ro)以及本文的主角: [YARG(Yet Another Rhythm Game)](https://github.com/YARC-Official/YARG) 。 YARG 實際上是另一個節奏遊戲,但這個專案的不同之處在於它是完全**開源的**,他們聯合了遊戲開發和設計方面的傳奇貢獻者來讓這個專案能夠運作。 突然之間,這款遊戲被 Twitch 上的 Guitar Hero/Rockband 主播們所採用並玩,我想:好吧,這是一個開源專案,所以也許我可以利用我的資料庫技能來建立一個**速度極快的排行榜**或儲存過去的比賽。 一開始只是在他們的 Discord 上進行了一次簡單的聊天,後來變成了關於如何讓這個專案更快發展的長時間討論。 然後我決定和我的老闆談談,問他我是否可以和 YARG 的人一起工作,條件是建立一些足夠酷的東西來實現[ScyllaDB(NoSQL 寬列資料庫)](https://scylladb.com/) ,因為我在那裡擔任開發倡導者。您不會相信ScyllaDB帶來的簡單性和可擴展性如何完美契合YARG.in的需求! 無論如何,談話是廉價的。讓我向您展示一些程式碼和概念! 2.QDD-查詢驅動的資料建模 --------------- ![NoSQL 與關係型資料庫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivkj9j8ni2fakkctx53n.png) 當我們談論使用**NoSQL**進行開發時,大多數情況下我們應該理解,根據範例(文件、圖形、寬列等),您應該先了解**要執行哪個查詢**。 在 MySQL 中,主要目標是了解一致性,而在 Scylla 中,您應該專注於查詢並基於該查詢建立模式。 在這個專案中,我們將處理兩種類型的範例,它們是: - 核心價值 - 寬列(聚類) 現在讓我們來談談我們建模的查詢/功能。 ### 2.1 功能:儲存匹配 ![提交詳情 YARG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaw4q7349upgrsa5p5g3.png) 每次完成 YARG 遊戲時,最有趣的事情就是提交您的分數以及許多其他遊戲內指標。 基本上它將是基於主索引的單一查詢,僅此而已。 ``` SELECT score, stars, missed_notes, instrument, ... FROM leaderboard.submisisons WHERE submission_id = 'some-uuid-here-omg' ``` ### 2.2 功能:排行榜 ![排行榜 Figma 文件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69jp0vgxef71titt9ks0.png) 現在我們的主要目標是:一個超酷的**排行榜**,在良好的資料建模之後你不需要關心它。排行榜是按歌曲計算的,因此每次您播放特定歌曲時,您的最佳成績都會被保存並排名。 然而,這個介面有一個重要的點,那就是有過濾器來準確地知道要帶來「哪個」排行榜: - 歌曲 ID:必填 - 儀器:必填 - 修飾符:必需 - 難度:必填 - 玩家 ID:可選 - 分數:可選 想像一下我們的查詢如下所示,它會傳回按分數降序排列的結果: ``` SELECT player_id, score, ... FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND track_id = 'dani-california' LIMIT 100; -- player_id | score ----------------+------- -- tzach | 12000 -- danielhe4rt | 10000 -- kadoodle | 9999 ----------------+------- ``` 現在我們知道了將在這裡使用的功能,但是您能想像最終的模式將如何嗎? 不?好的,讓我來幫助你! 3. 資料建模時間! ---------- 是時候深入研究 ScyllaDB 的資料建模並更好地了解如何擴展它了。 ### 3.1 - 匹配建模 ![遊戲結束畫面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6kedk7iu67zg7myj9mp.png) 首先,讓我們先來了解遊戲本身: - 這是一個節奏遊戲; - 您一次播放一首特定的歌曲; - 您可以在遊戲前啟動“修改器”,讓您的生活變得更輕鬆或更困難; - 您必須選擇一種樂器(例如吉他、鼓、貝斯和麥克風)。 - 遊戲玩法的各個方面都會被跟踪,例如: - Score; - Missed notes; - Overdrive count; - Play speed (1.5x ~ 1.0x); - Date/time of gameplay; - And other cool stuff. 考慮到這一點,我們可以輕鬆地開始我們的資料建模,這將變成這樣: ``` CREATE TABLE IF NOT EXISTS leaderboard.submissions ( submission_id uuid, track_id text, player_id text, modifiers frozen<set<text>>, score int, difficulty text, instrument text, stars int, accuracy_percentage float, missed_count int, ghost_notes_count int, max_combo_count int, overdrive_count int, speed int, played_at timestamp, PRIMARY KEY (submission_id, played_at) ); ``` 讓我們跳過所有`int/text`值並跳到`set<text>` 。 **集合**類型可讓您儲存特定類型的專案清單。我決定使用這個清單來儲存修飾符,因為它非常適合。看看查詢是如何執行的: ``` INSERT INTO leaderboard.submissions ( submission_id, track_id, modifiers, played_at ) VALUES ( some-cool-uuid-here, 'starlight-muse' {'all-taps', 'hell-mode', 'no-hopos'}, '2024-01-01 00:00:00' ); ``` 使用這種類型,您可以輕鬆儲存專案清單以供以後檢索。 另一個很酷的資訊是這個查詢是一個鍵值對!這意味著什麼? 由於您始終僅透過`submission_id`來查詢它,因此它可以歸類為鍵值。 ### 3.2 排行榜建模 ![排行榜濾鏡 Figma](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpmzngra3jk5ipf3os3i.png) 在本文的這一部分中,您將學習一些很酷的寬列資料庫概念。 在我們的排行榜查詢中,如前所述,我們總是需要在 WHERE 子句中使用一些動態值,這意味著這些值將屬於**分區鍵**,而**聚類鍵**將具有可以是「可選」的值。 **分區鍵**是基於您新增的用於標識值**的欄位組合的**雜湊。你明白了嗎?不?好吧,我也花了一段時間才明白這一點,但讓我向你展示一些東西: 假設您玩了`Starlight - Muse` 100 次。如果您要查詢此訊息,將透過`score`或`player_id`等聚類鍵區分出100倍不同的結果。 ``` SELECT player_id, score --- FROM leaderboard.song_leaderboard WHERE track_id = 'starlight-muse' LIMIT 100; ``` 如果有 1.000.000 個玩家播放這首歌,你的查詢會變得很慢,並且將來會成為一個問題,因為你的分區鍵只包含一個字段,即`track_id` 。 但是,如果您向**Partition Key**加入更多字段,例如玩遊戲之前的強制性內容,也許我們可以縮小這些可能性以實現更快的查詢。現在你看到大局了嗎?加入諸如**“樂器”** 、 **“難度**”和**“修改器”等**欄位將為您提供一種均勻分割有關特定曲目的資訊的方法。 讓我們想像一些簡單的數字: ``` -- Query Partition ID: '1' SELECT player_id, score, ... FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND -- Modifiers Changed track_id = 'starlight-muse' LIMIT 100; -- Query Partition ID: '2' SELECT player_id, score, ... FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'all-hopos'} AND -- Modifiers Changed track_id = 'starlight-muse' LIMIT 100; ``` 因此,如果您以特定形狀建立查詢,它將始終查找特定令牌並根據這些特定分區鍵檢索資料。 我們來看看最終的建模,談談聚類鍵和應用層: ``` CREATE TABLE IF NOT EXISTS leaderboard.song_leaderboard ( submission_id uuid, track_id text, player_id text, modifiers frozen<set<text>>, score int, difficulty text, instrument text, stars int, accuracy_percentage float, missed_count int, ghost_notes_count int, max_combo_count int, overdrive_count int, speed int, played_at timestamp, PRIMARY KEY ((track_id, modifiers, difficulty, instrument), score, player_id) ) WITH CLUSTERING ORDER BY (score DESC, player_id ASC); ``` 分區鍵的定義如上所述,由我們**所需的參數**組成,例如:track\_id、修飾符、難度和樂器。在**聚類鍵**上,我們新增了**Score**和**player\_id** 。 > 請注意,預設情況下,聚類欄位按`score DESC`排序,以防萬一玩家得分相同,選擇獲勝者的標準將按`alphabetical` ¯\\\_(ツ)\_/¯。 首先很容易理解的是,我們**每個玩家只有一個分數**,但透過這種建模,如果玩家以不同的分數兩次經歷同一條賽道,它將產生兩個不同的條目。 ``` INSERT INTO leaderboard.song_leaderboard ( track_id, player_id, modifiers, score, difficulty, instrument, stars, played_at ) VALUES ( 'starlight-muse', 'daniel-reis', {'none'}, 133700, 'expert', 'guitar', '2023-11-23 00:00:00' ); INSERT INTO leaderboard.song_leaderboard ( track_id, player_id, modifiers, score, difficulty, instrument, stars, played_at ) VALUES ( 'starlight-muse', 'daniel-reis', {'none'}, 123700, 'expert', 'guitar', '2023-11-23 00:00:00' ); SELECT player_id, score FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND track_id = 'starlight-muse' LIMIT 2; -- player_id | score ----------------+------- -- daniel-reis | 133700 -- daniel-reis | 123700 ----------------+------- ``` 那我們要如何解決這個問題呢?嗯,這本身不是問題。這是一個特點!哈哈 身為開發人員,您必須根據專案需求建立自己的業務規則,這也不例外。我這麼說是什麼意思? 您可以在插入新條目之前執行簡單的**DELETE**查詢,並確保在該特定**分區鍵**組內, **player\_id**中的特定資料不會低於新**分數**。 ``` -- Before Insert the new Gampleplay DELETE FROM leaderboard.song_leaderboard WHERE instrument = 'guitar' AND difficulty = 'expert' AND modifiers = {'none'} AND track_id = 'starlight-muse' AND player_id = 'daniel-reis' AND score <= 'your-new-score-here'; -- Now you can insert the new payload... ``` 這樣我們就完成了簡單的排行榜系統,該系統與 YARG 中執行的系統相同,也可以在每秒數百萬個條目的遊戲中使用:D 4. 如何為 YARG 做出貢獻 ---------------- 這是我邀請您為這個精彩的開源專案做出貢獻的文字部分! 今天,我們正在為所有玩家建立一個全新的平台,使用: - 遊戲:Unity3d [(儲存庫)](https://github.com/YARC-Official/YARG) - 前端:NextJS [(儲存庫)](https://github.com/YARC-Official/yarg.in) - 後端:Laravel 10.x [(儲存庫)](https://github.com/YARC-Official/yarg-api) 我們將需要盡可能多的開發人員和測試人員與主要貢獻者一起討論遊戲的未來實現! ![YARG 不和諧](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5b2pdxvrth2o6jfmada.png) 首先,請確保加入他們的[Discord 社群](https://discord.gg/sqpu4R552r)。在進入開發板之前,所有技術討論都會在社群後台進行。 此外,在 Discord 之外,YARG 社群主要關注[EliteAsian](https://twitter.com/EliteAsian123) (核心貢獻者和專案所有者)Twitter 帳戶的開發展示。一定要跟著他去那裡。 https://twitter.com/EliteAsian123/status/1736149319382671766 僅供參考,遊戲的**首席美術師**(又稱[Kadu)](https://twitter.com/kaduyarg)也是**Elgato**的**廣播專家**和**產品創新**開發人員,曾與以下串流媒體合作: - 忍者 - 納德肖特 - 石山64 - 以及傳奇 DJ Marshmello。 Kadu 也使用他的 Twitter 分享一些見解以及 YARG 新功能和實驗的早期預覽。所以,別忘了在 Twitter 上關注他! https://twitter.com/kaduyarg/status/1689489132060397568 以下是一些有用的連結,可以幫助您了解有關該專案的更多訊息: - [官方網站](https://yarg.in/) - [Github 儲存庫](https://github.com/YARC-Official/YARG) - [任務板](https://yarg.youtrack.cloud/agiles/147-7/current) > 有趣的事實:YARG 受到了 Guitar Hero 專案負責人[Brian Bright](https://twitter.com/BrianBright/status/1744533504531317194)的關注,他喜歡該專案的開源特性。太棒了,對吧? 5. 結論 ----- 資料建模有時具有挑戰性,這項研究花了 3 個月的時間研究了許多新的 ScyllaDB 概念,並與我在 Twitch 的社群一起進行了大量測試。 我還發布了[遊戲排行榜演示](https://github.com/scylladb/gaming-leaderboard-demo),您可以在其中獲得有關如何使用**NextJS**和**ScyllaDB**實現同一專案的一些見解! 另外,如果您喜歡 ScyllaDB 並想了解更多訊息,我強烈建議您觀看我們的免費[大師班課程](https://lp.scylladb.com/masterclass-ondemand-main?siteplacement=navigation)或存取[ScyllaDB 大學](https://university.scylladb.com/)! 不要忘記喜歡這篇文章,在社交上關注我並填滿你的水瓶 xD 下一篇文章見! [在推特上關注我](https://twitter.com/danielhe4rt) [在 Github 上關注我](https://twitter.com/danielhe4rt) [在 Github 上關注我](https://twitter.com/danielhe4rt) [關注並訂閱我的 Twitch 頻道](https://twitch.tv/danielhe4rt) --- 原文出處:https://dev.to/danielhe4rt/database-101-how-to-model-leaderboards-for-1m-players-game-2pfa

解決 DEV 上的點擊誘餌:策略和技術方法

解決 DEV 上的點擊誘餌:我們的策略和行動 ====================== 最近,我們採取了措施來解決 DEV 上的點擊誘餌問題。這篇文章旨在解釋我們的方法及其背後的基本原理。 定義點擊誘餌 ------ 點擊誘餌通常是指標題中具有特定模式的內容,例如清單或聳人聽聞的標題。例如,雖然清單文章在推動 DEV 參與度方面獲得了關注,但它們有時會導致不平衡,正如 Chrome 插件等社群舉措所表明的那樣: {% 嵌入 https://dev.to/lnahrf/no-listicles-the-chrome-add-on-that-removes-list-type-articles-from-your-devto-feed-3i8 %} 我們的方法 ----- ### 強調緩解而非嚴格過濾 我們沒有實施嚴格的過濾,而是選擇了更細緻的方法。原因如下: - **內容平衡**:並非所有清單文章都是負面的;它們可以提供豐富的資訊。然而,由於我們基於參與的系統,他們常常獲得不成比例的獎勵。 - **點擊誘餌的多樣性**:點擊誘餌有多種形式,嚴格的過濾器可能無法有效地捕捉所有這些形式。 - **主觀性問題**:確定標題誘餌的主觀性使得嚴格過濾變得不切實際。 ### 評分中的人工智慧和人類判斷 我們在應用程式中引入了`clickbait_score`字段,範圍從`0.0`到`1.0` 。 {% 嵌入 https://github.com/forem/forem/pull/20493 %} 這個分數不只由演算法決定。我們利用人工智慧和人類判斷來為貼文分配分數,認識到任務的主觀性和細微差別。 ### 透過 A/B 測試實施 我們正在仔細整合點擊誘餌分數。作為我們正在進行的 A/B 測試的一部分,使用者可能會遇到不同程度的點擊誘餌緩解措施。這些資料將幫助我們在未來幾週內完善我們的方法。 ### 展望未來:可自訂的用戶設置 雖然我們正在研究管理點擊誘餌的預設設置,但我們認識到個性化的必要性。未來的更新可能包括用戶特定的設置,以根據標題誘餌分數自訂提要偏好。 *我們將在不久的將來分享更多關於我們正在採取的各種策略,以改善核心體驗並幫助**分離 DEV 上的訊號和雜訊***。 快樂編碼❤️ --- 原文出處:https://dev.to/devteam/tackling-clickbait-on-dev-strategy-and-technical-approach-3dh9

10 個可以在網路上免費學習任何內容的網站

網路蘊藏著許多寶藏,但很多人卻不知道。 這裡有 10 個資源豐富的網站,可以在網路上免費學習任何東西: --- ## 1. 編碼 **免費程式碼營** 您可以免費學習編碼、建立專案並獲得認證。 **您可以獲得以下認證:** - 響應式網頁設計 - Javascript演算法與資料結構 - 前端開發庫 - 資料視覺化 - 關係型資料庫 - 和更多 ``` Link: https://www.freecodecamp.org/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1p5uuz40iub2l7u2z5f.png) --- ## 2. 行銷 **行銷範例** 簡短、溫馨、實用的行銷範例之家,可幫助您更好地進行行銷。 **取得範例:** - 客戶獲取 - 轉換 - 保留 - 品牌策略 - 推薦策略 - 和更多 ``` Link: https://marketingexamples.com/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5b7t6d2nmw2aiml2iibx.png) --- ## 3. 無程式碼 每天獲得 30 分鐘的簡短課程,指導您 100 天的無程式碼之旅,以提升您的無程式碼技能。 - 你得到什麼? - 指導課程 - 技巧和竅門 - 靈感鏡頭 - 驚喜獎勵 - 獎勵迷你挑戰 - 內建公共提示 ``` Link: https://www.100daysofnocode.com/start-the-challenge ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lq2r5ykrguazod5b7hrp.png) --- ## 4.人工智慧 **人工智慧 100 天** 每天獲得 30 分鐘的簡短課程,指導您的 AI 學習之旅。 **你了解什麼?** - 人工智慧在日常生活中的無限應用 - 你知道科技兄弟在談論什麼。 - 你每天都使用人工智慧來建立很酷的專案並消除無聊的工作。 - 你知道為什麼你對人工智慧感到焦慮,甚至更興奮。 ``` Link: https://www.100daysai.com/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1q3fklkja9pkk93elnm.png) --- ## 5. 語言 **多鄰國** 以遊戲化的方式學習您想要學習的任何語言,以保持您的動力。 **你得到什麼?** - 透過快速、簡短的課程,您將獲得積分並解鎖新級別,同時獲得現實世界的溝通技巧。 - 結合研究支援的教學方法和令人愉快的內容來建立課程。 - 類似遊戲的功能、有趣的挑戰和提醒,輕鬆養成語言學習的習慣。 - 課程經過量身定制,可幫助您以適當的水平和節奏學習。 ``` Link: https://www.duolingo.com/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hu7kwsknz8i57dqe9pvy.png) --- ## 6. 資料結構與演算法 **CSVISTOOL** 了解資料結構和演算法如何以視覺化方式運作。 **你能學到什麼?** - 清單 - 堆疊、佇列和出隊 - 樹和跳過列表 - 哈希圖 - 排序和快速選擇 - 字串搜尋 - 圖形演算法 - 和更多 ``` Link: https://csvistool.com/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vp7z77dyhhm87i94xx8j.png) --- ## 7. 使用者體驗 **使用者體驗法則** 策劃設計人員在建立使用者介面時可以考慮的最佳實踐。 **你得到什麼?** - 啟發式 - 原則 - 格式塔 - 認知偏差 ``` Link: https://lawsofux.com/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qi0nqfadsvvky9ea66um.png) --- ## 8.Excel + Power BI **尚杜** 每週接收有關 Excel 和 Power BI 最佳提示的電子郵件 **你得到什麼?** - 強大的提示、資源和影片,幫助您在工作中取得進步。 - 資料分析、圖表、報告和自動化的真實範例 - 獎勵文件、PDF 指南和先睹為快 ``` Link: https://chandoo.org/wp/subscribe/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdo19vjlpbg5e7gz1tw0.png) --- ## 9. 時事通訊的成長 **反向成長** 了解如何從網路上最好的時事通訊成長故事中發展您的時事通訊。 **你得到什麼?** - 時事通訊企業如何賺錢 - 他們如何成長 - 他們如何透過時事通訊獲利 ``` Link: https://growthinreverse.com/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bebb1sbr2mt94udzv77p.png) --- ## 10.心智模型 **法南街** 了解讓您生活更美好的心理模式。 **如何取得?** - 核心心智模型 - 物理和化學的心理模型 - 生物學的心理模型 - 系統思維的心智模型 - 以及更多 ``` Link: https://fs.blog/mental-models/ ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tmyafxsxl9xbvbcgn0c.png) --- ## 與我聯繫 領英:https://www.linkedin.com/in/durgesh4993/ GitHub:https://github.com/Durgesh4993 LeetCode:https://leetcode.com/durgesh4993/ 簡介:https://linktr.ee/durgesh4993 --- 原文出處:https://dev.to/durgesh4993/10-websites-to-learn-anything-for-free-on-the-internet-4ahe

反應性的推導

當您第一次了解反應式系統時,範例總是看起來像這樣,這是有原因的: ``` let name = state("John"); effect(() => { console.log("Hi" + name); }) ``` > *我們將使用偽程式碼,而不是為了迎合特定庫或框架的語法。* 不需要太多就能理解,當我更新此狀態時,會發生一個呼叫我的副作用的事件。自己實現這種行為也不是太困難。但這還遠遠不是故事的全部。 無論您是想忘記 React、使用 Svelte 探索符文還是想嘗試 Angular;無論您是建立 Solid 應用程式、在 Vue 中建立視圖還是生活在 QwikCity 中,這個主題都相關。它超越了虛擬 DOM 或訊號。在您認為「useEffect」被建立為每個人存在的禍根之前,讓我們先來看看反應性最重要的部分:派生。 ----------------- ## 派生與同步 您可能已經在您選擇的 JS 框架/反應系統中看到了派生值。它可能看起來像“useMemo”,或者可能是“compulated”,或者可能就在分配了值的“$”後面。但所有這些的不變之處是你被告知它們是為了產生一種反應性關係。即使 B 或 C 發生變化,A 也是 B + C 總和: ``` let a = state(1); let b = state(1); const c = memo(() => a + b); effect(() => console.log(c)); ``` 他們可能告訴您派生值應該是純粹的——也就是說它不應該寫入任何其他狀態——但該規則也適用於它的內部。 您可以先將其應用為派生狀態的心理模型: ``` function memo(fn) { let internal = state(); effect(() => internal = fn()); return internal; } ``` 但這永遠無法正常工作。 大多數 UI 框架都關心提供互動性。即取得使用者操作的輸入,將其套用到某種狀態,然後更新 UI。我們看到它形式化為“ui = fn(state)”,但這是一個重複的循環。 就反應性而言,它看起來像: > 更新狀態-> > 執行純計算 -> > 執行副作用(例如更新 DOM) 原因是最終用戶與 UI 互動需要一致性。他們看到的(和看不到的)應該全部同步。您無法與過時的頁面部分進行交互,因為它設定了錯誤的期望。 UI 庫安排其副作用同步執行,以確保最終用戶可以信任體驗。 這意味著程式碼執行有明確的階段。庫需要確保在渲染之前解決所有相關計算。 這導致了以下之間的確切區別: ``` let name = state("John"); const upperName = memo(() => name.toUpperCase()); updateUI(name, upperName); ``` ``` let name = state("John"); let upperName = state(); effect(() => upperName = name.toUpperCase()); updateUI(name, upperName); ``` 第一個例子是推導,其中推導的狀態是它所依賴的狀態的函數。第二個範例是同步,其中狀態的變更會導致其他狀態更新。這是一個重要的區別。 在第二個範例中,根據您的反應模型,可能會發生不同的事情,而不是簡單地按預期立即顯示所有內容。根據效果安排時間與 UI 渲染時間的不同,當您更新「name」時,您可能會短暫看到更新後的「name」和「upperName」的先前值。在像 React 這樣的粗粒度渲染框架中,您的元件可能會執行兩次。因為更新效果中的狀態會再次開始循環。 ---------------- ## 無故障一致性 即使您始終可以在渲染之前進行同步,您仍然有可能使用不同中間狀態(可能是意外狀態)的值多次執行表達式,直到圖形穩定下來。推導可以提供可預測性。 現在,許多反應式系統保證對於任何狀態更新,每個節點最多只執行一次,並且執行時不會出現故障。透過無故障,開發人員向庫提供的程式碼永遠不會觀察到中間或過時狀態。 考慮: ``` let a = state(1); const b = memo(() => a + 1); const c = memo(() => a + 1); const d = memo(() => c + 1); const e = memo(() => b + d); effect(() => console.log(e)); ``` 或作為圖表 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kg9w4yehyeqhgry1wkvk.png) 不同的系統運作方式不同,但在所有情況下,我們期望初始執行產生值為 5 的「e」。 同樣清楚的是,某些狀態依賴其他狀態。當我們更新“a = 2”時,無論機制如何,如果我們只想執行每個節點一次,“c”必須在“d”之前解析,“d”必須在“e”之前解析。 ---------------- ## 推與拉 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1004yrongpx1usdsxe0x.jpg) 那我們要如何處理這個問題呢?它通常從以下兩個想法之一開始。調度(拉)和事件(推)。讓我們使用上一節中的範例來分別了解。 ### 拉動(調度) 這個想法是從副作用(目標)開始,然後詢問遇到的值。 React 通常被認為具有基於「拉」的反應性。在此系統中,當狀態更新時,它會安排檢查以查看是否需要執行任何工作。 但它檢查什麼?天真地,也許一切都改變了,因為它不知道發生了什麼變化。然而,許多 UI 庫都處理元件。如果狀態由元件擁有,那麼這可以作為起點。當元件狀態更新時,安排此元件運作。 基於拉動的系統是粗粒度的。也就是說,他們依賴自上而下地重播所有內容,因為他們不知道發生了什麼變化。如果我們想像一個更細粒度的「拉動」系統,它就無法知道任何變化,直到它追溯到變化的源頭,而變化的源頭可能存在於其依賴項中,也可能不存在。當最終需要向下執行時,額外的遍歷只是額外的工作。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kg9w4yehyeqhgry1wkvk.png) 在我們的範例中,圖片中我們首先執行要求“e”的效果。如果不在之前執行“b”或“d”,我們不知道“e”是否已更改。明確依賴項(如 React 的依賴項陣列)可以在不執行節點的情況下給出向上的路徑。所以我們可以回溯`e`、`b`、`a`,然後執行`b`,然後回溯`d`、`c`、`a`,然後執行`c`、`d`、 ` e` 在最終執行我們的效果之前。但考慮到我們無論如何都在執行整個範圍(元件),即使其中一部分沒有改變,這都是不必要的。 記憶(通常以推導的形式)允許提前退出,有助於優化這種情況,但這種方法雖然一致,但從根本上來說效率很低。 ### 推送(事件) 這個想法是更新從已更改的來源狀態向外傳播。 RxJS 是基於「推送」的反應性的常見範例。它將讓每個節點訂閱其依賴項中的更改事件,然後在收到通知時執行並在其值發生更改時通知其觀察者。 考慮深度優先傳播,因為它反映了最初建立時執行的方式。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kg9w4yehyeqhgry1wkvk.png) `a` 更新,通知 `b` 和 `c`。然後“b”執行並通知“e”。然後“e”執行並看到“b”的更新值,但隨後它遇到了“d”,它尚未執行並且具有舊值... 廣度優先也有類似的問題,因為「d」和「e」與來源「a」的距離相同,再次導致過時的值。它會嘗試執行“b”、“c”,然後執行“e”、“d”,結果發現“d”在“e”之前沒有被計算。 基於「推送」的系統很難確保我們有效地尋求保證。進行排序插入可以工作。但即使最後沒有任何效果器在監聽,它仍然可以工作。它確切地知道傳播時發生了什麼變化,但不知道該變化會產生什麼影響。 ### 推拉 第三種選擇是結合這兩種技術。訊號是事實上的「推拉」反應系統。訂閱和通知的製作方式類似於“推”,但工作的安排類似於基於“拉”的系統。透過這種方式,只安排會改變的事情,並且保持一致。 在我們更新“a”的範例中,“b”和“c”被通知它們可能會發生更改,進而通知“e”和“d”。最後,監聽「e」的效果被排隊。然後,我們的效果首先執行,在觸及值時拉低值,類似於我們上面描述的假設的細粒度「拉」系統。只不過這次只有可能受影響的效果才會排隊。 它知道發生了什麼變化以及這些變化的影響,確保我們只做所需的工作。 如果您對推拉演算法如何在各種訊號庫中工作的更多細節感興趣,請查看: {% 連結 https://dev.to/modderme123/super-charging-fine-grained-reactive-performance-47ph %} ---------------- ## 可以推導的應該推導 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxmqpzohmk1az3k92anp.png) 我不是 100% 確定這句話最初來自哪裡,但我第一次聽到這句話來自 MobX 的建立者 Michel Westrate。這些都是我們賴以生存的話語。 不言而喻,我們所期望的函式庫和框架的一致性僅靠狀態和效果是不可能實現的。當效果寫入狀態時,您不再可以遍歷依賴關係圖來了解需要計算的內容。依賴性消失了。這不僅僅是低效。這是很容易出錯的。 這是一個很深奧的話題。就這麼多,我只觸及了表面。 「推」與「拉」還有其他含義,即使在查看屬於同一類別的系統時也有很多細節。下一次,我們將研究惰性派生與急切派生以及處理非同步的潛力。 -------------- 特別感謝 Atila Fassina、Fabio Spampinato 和 Daniel Afonso 的審閱。 --- 原文出處:https://dev.to/this-is-learning/derivations-in-reactivity-4fo1

Bulma - CSS 框架時代最被低估的框架

每個人都使用 CSS 框架來簡化工作並節省時間,Bootstrap 過去是,現在仍然是框架市場的王者。每個研究所、幾乎 YouTube 上的每個教學都在使用 Bootstrap,開發人員沒有學習 CSS 基礎知識和使用 Bootstrap。那時我也是個初學者,我從[W3schools](https://www.w3schools.com/)和[Lynda](https://www.lynda.com/)學習了HTML和CSS。然後我用了很多浮動來製作網頁,還蠻喜歡這樣的方式。 ___ 響應式設計是我的下一個目標,所以CSS 框架是實現響應式最簡單的方法,我嘗試閱讀文件並觀看Bootstrap 影片,但Bootstrap 的大量類和不方便的命名讓我感到害怕,而且我不喜歡使用bootstrap 因為我認為每個使用Bootstrap 的網站看起來都非常相似,它也會將樣式作為預設值應用到元素上,我嘗試了兩次或多次,但沒有在我的腦海中得到Bootstrap,所以我找到了一些替代方案,例如Foundation 和Material,但它們就像Bootstrap 一樣。我只是想讓我的網站響應式,然後我找到了 [Brad Traversy Skeleton CSS] 的影片(https://www.youtube.com/watch?v=nVANwdryGVc) ___ 我喜歡 Skeleton CSS,但現在他們的開發人員沒有更新它,它不是基於 CSS 網格或 Flexbox。裡面有些混亂,然後我發現了[Bulma](https://www.bulma.io/) ,我只是像平常一樣使用YouTube,然後我來到了[Bulma.css 教程影片](https://www.bulma.io/) www.youtube.com/watch?v=IiPQYQT2-wg) 標記為“最簡單的框架,你可以在20 分鐘內學會”,嗯,我看了它,它確實改變了我的生活,這確實是最簡單的框架,即使你不知道不必記住課程,它有一些優點: - 無預設樣式 - 強大的 Flexbox 網格 - 小尺寸(以 Kbs 為單位) - 可重複使用並且可以修改Sass - 沒有Javascript,只有CSS - 可重複使用的元件 ___ 我有點迷戀布瑪(我想)但是你可以嘗試一下。 順便說一句,這是我的第一篇文章,你可以在 Twitter 上關注我😉 [https://www.twitter.com/justaashir](https://www.twitter.com/justaashir) --- 原文出處:https://dev.to/justaashir/bulma-the-most-underrated-framework-of-the-css-framework-era-2gj8

極為簡單的 Python 專案結構與導入

喜歡這些文章嗎?買書吧! [***Jason C. McDonald 的《Dead Simple Python》可從 No Starch Press 取得。](https://nostarch.com/dead-simple-python) --- 教程最糟糕的部分始終是它們的簡單性,不是嗎?您很少會發現一個包含多個文件的文件,更罕見的是包含多個目錄的文件。 我發現**建立 Python 專案**是語言教學中最常被忽略的部分之一。更糟的是,許多開發人員都會犯錯,在一堆常見錯誤中跌跌撞撞,直到他們得到至少「有效」的東西。 好訊息是:您不必成為他們中的一員! 在《Dead Simple Python》系列的本期中,我們將探索「import」語句、模組、包,以及如何將所有內容組合在一起而不費力氣。我們甚至會涉及 VCS、PEP 和 Python 之禪。係好安全帶! # 設定儲存庫 在我們深入研究實際的專案結構之前,讓我們先討論一下它如何適合我們的版本控制系統 [VCS]…從您*需要* VCS 的事實開始!有幾個原因是... * 追蹤您所做的每一個更改, * 弄清楚你什麼時候弄壞了東西, * 能夠查看舊版的程式碼, * 備份您的程式碼,以及 * 與他人合作。 您有很多選擇。 **Git** 是最明顯的,尤其是當您不知道還可以使用什麼時。您可以在 GitHub、GitLab、Bitbucket 或 Gitote 等上免費託管 Git 儲存庫。如果您想要 Git 以外的東西,還有許多其他選擇,包括 Mercurial、Bazaar、Subversion(儘管如果您使用最後一個,您可能會被同行視為恐龍。) 我將悄悄假設您在本指南的其餘部分中使用 Git,因為這是我專門使用的。 建立儲存庫並將「本機副本」複製到電腦後,您就可以開始設定專案了。您至少需要建立以下內容: - `README.md`:您的專案及其目標的描述。 - `LICENSE.md`:您的專案的許可證(如果它是開源的)。 (有關選擇一個的更多訊息,請參閱 [opensource.org](https://opensource.org/)。) - `.gitignore`:一個特殊文件,告訴 Git 要忽略哪些文件和目錄。 (如果您使用其他 VCS,則該檔案具有不同的名稱。請尋找。) - 包含您的專案名稱的目錄。 沒錯...**我們的Python 程式碼檔案實際上屬於一個單獨的子目錄!** 這非常重要,因為我們的儲存庫的根目錄將變得非常混亂,其中包含建置檔案、打包腳本、虛擬環境以及各種方式其他實際上不屬於原始碼的內容。 僅為了舉例,我們將虛構的專案稱為「awesomething」。 # PEP 8 和命名 Python 風格主要由一組稱為 **Python 增強提案**(縮寫為 **PEP**)的文件管轄。當然,並非所有 PEP 都被實際採納——這就是它們被稱為「提案」的原因——但有些是被採納的。您可以在Python官方網站上瀏覽主PEP索引。此索引的正式名稱為 [PEP 0](https://www.python.org/dev/peps/)。 現在,我們主要關注 [**PEP 8**](https://www.python.org/dev/peps/pep-0008/),它最初由 Python 語言建立者 Guido van Rossum 於2001 年。該文件正式概述了所有Python 開發人員應普遍遵循的程式設計風格。把它放在枕頭下!學習它,遵循它,鼓勵其他人也這樣做。 (附註:PEP 8 指出樣式規則總是有例外。它是*指南*,而不是*命令*。) 現在,我們主要關注標題為 [“包和模組名稱”](https://www.python.org/dev/peps/pep-0008/#package-and-module-names)的部分。。 > 模組應該有簡短的、全小寫的名稱。如果可以提高可讀性,可以在模組名稱中使用下劃線。 Python 套件也應該有短的、全小寫的名稱,儘管不鼓勵使用底線。 我們稍後會了解*模組*和*包*到底是什麼,但現在,請了解**模組由檔案名稱命名**,而**套件由其目錄名稱命名**。 換句話說,**檔案名稱應全部小寫,如果可以提高可讀性,則使用下劃線。**同樣,**目錄名稱應全部小寫,如果可以避免,則不使用下劃線**。換句話說... + 執行此動作:`awesomething/data/load_settings.py` + 不是這個:`awesomething/Data/LoadSettings.py` 我知道,我知道,這是一種冗長的表達方式,但至少我在你的步驟中加入了一點 PEP。 (*你好?這個東西開著嗎?*) # 套件和模組 這會讓人感覺虎頭蛇尾,但這裡是那些承諾的定義: **任何Python(`.py`)檔案都是一個*模組*,目錄中的一堆模組是一個*套件*。** 嗯……差不多了。要讓目錄成為包,您還必須做另一件事,那就是將名為「__init__.py」的檔案貼到其中。實際上,您不必將任何內容*放入*該文件中。它必須在那裡。 您也可以使用`__init__.py` 做其他很酷的事情,但這超出了本指南的範圍,因此[請閱讀文件以了解更多資訊](https://docs.python.org/3/tutorial/modules.html#packages)。 如果你*確實*忘記了套件中的`__init__.py`,它會做一些比失敗更奇怪的事情,因為這使它成為一個**隱式命名空間包**。您可以使用這種特殊類型的套件做一些有趣的事情,但我不會在這裡討論。像往常一樣,您可以透過閱讀文件來了解更多:[PEP 420:隱式命名空間包](https://www.python.org/dev/peps/pep-0420/)。 所以,如果我們看看我們的專案結構,`awesomething` 實際上是一個包,它可以包含其他包。因此,我們可以將「awesomething」稱為我們的*頂級包*,以及其*子包*下的所有包。一旦我們開始進口東西,這將非常重要。 讓我們看一下我的現實專案“遺漏”的快照,以了解我們如何建置東西... ``` omission-git ├── LICENSE.md ├── omission │ ├── app.py │   ├── common │   │   ├── classproperty.py │   │   ├── constants.py │   │   ├── game_enums.py │   │   └── __init__.py │   ├── data │   │   ├── data_loader.py │   │   ├── game_round_settings.py │   │   ├── __init__.py │   │   ├── scoreboard.py │   │   └── settings.py │   ├── game │   │   ├── content_loader.py │   │   ├── game_item.py │   │   ├── game_round.py │   │   ├── __init__.py │   │   └── timer.py │   ├── __init__.py │   ├── __main__.py │   ├── resources │   └── tests │   ├── __init__.py │   ├── test_game_item.py │   ├── test_game_round_settings.py │   ├── test_scoreboard.py │   ├── test_settings.py │   ├── test_test.py │   └── test_timer.py ├── pylintrc ├── README.md └── .gitignore ``` (如果您想知道的話,我使用 UNIX 程式“tree”來製作上面的小圖。) 您會看到我有一個名為“omission”的頂級包,它有四個子包:“common”、“data”、“game”和“tests”。我還有“resources”目錄,但只包含遊戲音訊、圖像等(為簡潔起見,此處省略)。 `resources` 不是一個包,因為它不包含 `__init__.py`。 我的頂層包中還有另一個特殊檔案:`__main__.py`。這是當我們直接透過「python -m omission」執行頂級套件時執行的檔案。我們稍後會討論「__main__.py」中的內容。 # 導入如何進行 如果您以前編寫過任何有意義的 Python 程式碼,那麼您幾乎肯定熟悉「import」語句。例如... ``` import re ``` 知道當我們導入模組時,我們實際上是在執行它是有幫助的。這意味著模組中的任何“import”語句也正在執行。 例如,[`re.py`](https://github.com/python/cpython/blob/3.7/Lib/re.py#L122) 有幾個自己的 import 語句,當我們說 `導入重新`。這並不意味著它們可用於我們從*導入“re”的文件,但這確實意味著這些文件必須存在。如果(由於某種不太可能的原因)“enum.py”在您的環境中被刪除,並且您執行了“import re”,它將失敗並出現錯誤... > 回溯(最近一次呼叫最後一次): > 檔案“weird.py”,第 1 行,位於 <module> 中 > 進口再 > 檔案“re.py”,第 122 行,位於 <module> 中 > 導入枚舉 > ModuleNotFoundError:沒有名為「enum」的模組 當然,讀到這裡,你可能會有點困惑。有人問我為什麼找不到外部模組(在本例中為“re”)。其他人想知道為什麼要導入內部模組(此處為“enum”),因為他們沒有直接在程式碼中請求它。答案很簡單:我們導入了 `re`,然後導入了 `enum`。 當然,上面的場景是虛構的:「import enum」和「import re」在正常情況下永遠不會失敗,因為這兩個模組都是Python核心庫的一部分。這只是一個愚蠢的例子。 ;) # 匯入註意事項 實際上有多種導入方式,但其中大多數應該很少使用(如果有的話)。 對於下面的所有範例,我們假設有一個名為「smart_door.py」的檔案: ``` # smart_door.py def close(): print("Ahhhhhhhhhhhh.") def open(): print("Thank you for making a simple door very happy.") ``` 例如,我們將在 Python 互動式 shell 中執行本節中的其餘程式碼,執行位置與「smart_door.py」相同。 如果我們想執行`open()`函數,我們必須先導入模組`smart_door`。最簡單的方法是...... ``` import smart_door smart_door.open() smart_door.close() ``` 我們實際上會說“smart_door”是“open()”和“close()”的**命名空間**。 Python 開發人員非常喜歡命名空間,因為它們讓函數和其他內容的來源一目了然。 (順便說一句,不要將 *命名空間* 與 *隱式命名空間包* 混淆。它們是兩個不同的東西。) **Python 之禪**,也稱為 [PEP 20](https://www.python.org/dev/peps/pep-0020/),定義了 Python 語言背後的哲學。最後一行有一個聲明解決了這個問題: > 命名空間是一個非常棒的想法——讓我們做更多這樣的事情! 然而,在某種程度上,命名空間可能會變得很痛苦,尤其是對於嵌套包來說。 `foo.bar.baz.whatever.doThing()` 太醜了。值得慶幸的是,我們確實有辦法避免*每次*呼叫函數時都必須使用命名空間。 如果我們希望能夠使用 `open()` 函數,而不必總是在其前面加上模組名稱,我們可以這樣做... ``` from smart_door import open open() ``` 但請注意,「close()」和「smart_door.close()」在最後一個場景中都不起作用,因為我們沒有直接匯入該函數。要使用它,我們必須將程式碼更改為這樣... ``` from smart_door import open, close open() close() ``` 在之前可怕的嵌套包噩夢中,我們現在可以說“from foo.bar.baz.whatever import doThing”,然後直接使用“doThing()”。或者,如果我們想要一點命名空間,我們可以說“from foo.bar.baz importwhatever”,然後說“whatever.doThing()”。 “導入”系統非常靈活。 但不久之後,您可能會發現自己說“但是我的模組中有數百個函數,我想全部使用它們!”這是許多開發人員偏離軌道的地方,這樣做... ``` from smart_door import * ``` **這非常非常糟糕!** 簡而言之,它直接導入模組中的所有內容,這是一個問題。想像一下下面的程式碼... ``` from smart_door import * from gzip import * open() ``` 你認為會發生什麼事?答案是,「gzip.open()」將是被呼叫的函數,因為這是在我們的程式碼中導入並定義的「open()」的最後一個版本。 `smart_door.open()` 已被 **shadowed** - 我們不能稱之為 `open()`,這意味著我們實際上根本無法呼叫它。 當然,由於我們通常不知道,或者至少不記得每個導入的模組中的*每個*函數、類別和變數,所以我們很容易陷入一堆混亂。 *Python 之禪* 也解決了這個情況... > 顯式優於隱式。 您永遠不必“猜測”函數或變數來自何處。文件中的某個位置應該有程式碼“明確”告訴我們它來自哪裡。前兩個場景證明了這一點。 我還應該提到,早期的 `foo.bar.baz.whatever.doThing()` 場景是 Python 開發人員不喜歡看到的。也來自 *Python 之禪*... > 扁平比嵌套更好。 一些包的嵌套是可以的,但是當你的專案開始看起來像一套精緻的俄羅斯娃娃時,你就做錯了。將模組組織到包中,但保持相當簡單。 # 在您的專案中匯入 我們之前建立的專案文件結構即將「非常方便」。回想一下我的「遺漏」專案... ``` omission-git ├── LICENSE.md ├── omission │ ├── app.py │ ├── common │ │ ├── classproperty.py │ │ ├── constants.py │ │ ├── game_enums.py │ │ └── __init__.py │ ├── data │ │ ├── data_loader.py │ │ ├── game_round_settings.py │ │ ├── __init__.py │ │ ├── scoreboard.py │ │ └── settings.py │ ├── game │ │ ├── content_loader.py │ │ ├── game_item.py │ │ ├── game_round.py │ │ ├── __init__.py │ │ └── timer.py │ ├── __init__.py │ ├── __main__.py │ ├── resources │ └── tests │ ├── __init__.py │ ├── test_game_item.py │ ├── test_game_round_settings.py │ ├── test_scoreboard.py │ ├── test_settings.py │ ├── test_test.py │ └── test_timer.py ├── pylintrc ├── README.md └── .gitignore ``` 在我的“game_round_settings”模組中,由“omission/data/game_round_settings.py”定義,我想使用“GameMode”類別。類別在「omission/common/game_enums.py」中定義。我怎樣才能到達它? 因為我將“omission”定義為包,並將模組組織到子包中,所以實際上非常簡單。在“game_round_settings.py”中,我說...... ``` from omission.common.game_enums import GameMode ``` 這稱為**絕對導入**。它從頂級包“omission”開始,然後進入“common”包,在其中查找“game_enums.py”。 一些開發人員向我提供更像「from common.game_enums import GameMode」的導入語句,並想知道為什麼它不起作用。簡而言之,「data」套件(「game_round_settings.py」所在的位置)不知道其兄弟包。 然而,它確實知道它的父母。正因為如此,Python 有一種叫做「相對導入」的東西,它可以讓我們做同樣的事情,就像這樣... ``` from ..common.game_enums import GameMode ``` `..` 表示“此套件的直接父包”,在本例中為“omission”。因此,導入後退一級,進入“common”,並找到“game_enums.py”。 關於是否使用絕對導入或相對導入有許多爭論。就我個人而言,我更喜歡盡可能使用絕對導入,因為它使程式碼更具可讀性。不過,您可以自己做決定。唯一重要的部分是結果是「顯而易見的」——任何東西的來源都不應該是神秘的。 (繼續閱讀:[Real Python - Python 中的絕對導入與相對導入](https://realpython.com/absolute-vs-relative-python-imports/) 這裡還隱藏著另一個陷阱!在 `omission/data/settings.py` 中,我有這一行: ``` from omission.data.game_round_settings import GameRoundSettings ``` 當然,由於這兩個模組都在同一個包中,我們應該可以直接說“from game_round_settings import GameRoundSettings”,對嗎? *錯誤!* 它實際上無法找到“game_round_settings.py”。這是因為我們正在執行頂級包“omission”,這意味著**搜尋路徑**(Python 查找模組的位置以及順序)的工作方式不同。 但是,我們可以使用相對導入來代替: ``` from .game_round_settings import GameRoundSettings ``` 在這種情況下,單一“.”表示“這個包”。 如果您熟悉典型的 UNIX 檔案系統,這應該開始有意義。 `..` 表示“後一級”,“.` 表示“目前位置”。當然,Python 更進一步:`...` 表示“後兩級”,`....` 表示“後三級”,依此類推。 但是,請記住,這些「等級」不僅僅是簡單的目錄。他們是包裹。如果在一個不是包的普通目錄中有兩個不同的包,則不能使用相對導入從一個包跳到另一個包。為此,您必須使用 Python 搜尋路徑,但這超出了本指南的範圍。 (請參閱本文末尾的文件。) # `__main__.py` 還記得我提到在我們的頂級包中建立一個 `__main__.py` 嗎?這是一個特殊的文件,當我們直接使用 Python 執行套件時會執行該文件。我的“omission”包可以使用“python -m omission”從我的存儲庫的根目錄執行。 這是該文件的內容: ``` from omission import app if __name__ == '__main__': app.run() ``` 是的,實際上就是這樣!我正在從頂級包“omission”導入我的模組“app”。 請記住,我也可以說「來自…」。改為導入應用程式。或者,如果我只想說“run()”而不是“app.run()”,我可以執行“from omission.app import run”或“from .app import run”。最後,只要程式碼可讀,我如何進行導入並沒有太大的技術差異。 (附註:我們可以爭論為我的主要`run()` 函數設定一個單獨的`app.py` 對我來說是否合乎邏輯,但我有我的理由......而且它們超出了本指南的範圍。 ) 首先讓大多數人感到困惑的部分是整個「if __name__ == '__main__'」語句。 Python 沒有太多**樣板** - 必須非常普遍地使用且幾乎不需要修改的程式碼 - 但這是那些罕見的位元之一。 `__name__` 是每個 Python 模組的特殊字串屬性。如果我將“print(__name__)”行貼在“omission/data/settings.py”的頂部,當該模組被導入(並因此執行)時,我們會看到“omission.data.settings”被打印出去。 當模組直接透過「python -m some_module」運作時,模組會被指派一個特殊值「__name__」:「__main__」。 因此,「if __name__ == '__main__':」實際上是在檢查該模組是否以 *main* 模組執行。如果是,它將在條件下執行程式碼。 您可以透過另一種方式看到這一點。如果我將以下內容加入到“app.py”的底部... ``` if __name__ == '__main__': run() ``` ……然後我可以直接透過 `python -m omission.app` 執行該模組,結果與 `python -m omission` 相同。現在`__main__.py`被完全忽略,`omission/app.py`的`__name__`是`"__main__.py"`。 同時,如果我只是執行“python -m omission”,“app.py”中的特殊程式碼將被忽略,因為它的“__name__”現在又是“omission.app”。 看看效果如何? # 總結 我們來複習。 * 每個專案都應該使用 VCS,例如 Git。有很多選項可供選擇。 * 每個 Python 程式碼檔案 (`.py`) 都是一個 **模組**。 * 將您的模組組織到**包**中。每個包必須包含一個特殊的「__init__.py」檔案。 * 您的專案通常應由一個頂級包組成,通常包含子包。該頂級包通常共享您的專案的名稱,並作為專案存儲庫根目錄中的目錄存在。 * **永遠不要**在導入語句中使用「*」。在考慮可能的例外之前,Python 之禪指出「特殊情況並沒有特殊到足以違反規則」。 * 使用絕對或相對導入來引用專案中的其他模組。 * 可執行專案的頂層套件中應該有一個`__main__.py`。然後,您可以使用「python -m myproject」直接執行該套件。 當然,我們可以在建立 Python 專案時使用許多更高級的概念和技巧,但我們不會在這裡討論。我強烈建議閱讀文件: + [Python 參考:導入系統](https://docs.python.org/3/reference/import.html) + [Python 教學:模組](https://docs.python.org/3/tutorial/modules.html) + [PEP 8:Python 風格指南](https://www.python.org/dev/peps/pep-0008/) + [PEP 20:Python 之禪](https://www.python.org/dev/peps/pep-0020/) + [PEP 240:隱式命名空間套件](https://www.python.org/dev/peps/pep-0420/) --- *感謝 `grym`、`deniska` (Freenode IRC `#python`)、@cbrintnall 和 @rhymes (Dev) 提出的修改建議。* --- 原文出處:https://dev.to/codemouse92/dead-simple-python-project-structure-and-imports-38c6

Deno 入門

如果你錯過了,Node 的建立者 Ryan Dahl 的新 Javascript 和 Typescript runtime[已發布](https://deno.land/)!它有一些非常酷的功能,可供公眾使用!讓我們來看看一些簡潔的功能,並開始建立一個簡單的 hello world! ## 什麼是 Deno? Deno 是 Typescript(和 Javascript)的新runtime,主要用 Rust 寫。它有一些[偉大的目標](https://deno.land/manual.html#goals)和一些非常有趣的“非目標”,例如不使用`npm`並且沒有package.json。 ## 安裝 安裝 deno 就像執行以下命令一樣簡單: `curl -fsSL https://deno.land/x/install/install.sh |噓` 然後複製“export”行並將其新增至“~/bashrc”或“~/bash_profile”中。 打開一個新終端並執行“deno”。您應該會收到“>”提示。輸入“exit”,讓我們深入研究一些功能! ## Deno 中的酷功能 ### 預設打字稿 預設情況下,整合 Deno 來執行 Typescript 檔案。它基本上使 Javascript 中的類型成為一等公民。不再需要透過 Babel 編譯來在伺服器端 Javascript 中使用 Typescript。 ### 從 URL 導入 Deno 允許您從網頁匯入,就像在瀏覽器中一樣。只需在您通常命名模組的位置新增一個 URL: ``` import { bgBlue, red, bold } from "https://deno.land/std/colors/mod.ts"; ``` ### 標準庫 此外,Deno 有一個易於導入和使用的標準函式庫。有些模組可以執行多種不同的操作,例如 HTTP 處理、日期時間工作和檔案系統工作。您可以在[此處](https://github.com/denoland/deno_std)查看。 ### 使用 ES 模組 最後,Deno 僅支援 ES 模組語法,這表示不再需要 `require()` 語句,只需良好的 ole' `import x from "y"`。 ## 你好世界範例 讓我們快速看一下 Hello World,其中重點介紹了其中一些功能! 將其複製到“hello-world.ts”檔案中。 ``` import { bgBlue, red, bold } from "https://deno.land/std/colors/mod.ts"; const sayHello = (name: string = "world") => { console.log(bgBlue(red(bold(`Hello ${name}!`)))); } sayHello(); sayHello("Conlin"); ``` 現在您可以使用“deno hello-world.ts”執行它,它應該會列印出一些內容。 將“sayHello”呼叫之一更改為“sayHello(15);”並重新執行它。您應該看到類型錯誤,因為 15 不是字串!太酷了! 您還會注意到如何從 URL 導入 - 它從標準庫中獲取一些控制台顏色內容! # 最後的想法 Deno 還沒有完全準備好用於生產 - 有幾個 [bug](https://deno.land/benchmarks.html#req-per-sec),但開發正在快速推進!這絕對是一個很酷的新開源專案,值得關注! --- 原文出處:https://dev.to/wuz/getting-started-with-deno-e1m

🥇最好的 Web 框架並不存在 🚫

**簡介** 您選擇的 Web 應用程式框架並不重要。嗯,這很重要,只是不像別人希望你相信的那麼重要。 2024 年存在如此多的庫和框架,並且最好的庫和框架[仍在激烈爭論](https://joshcollinsworth.com/blog/self-fulfilling-prophecy-of-react)這一事實證明了我的觀點。這是網頁開發人員最大的「第一世界問題」——一個實際上並不是問題的問題。在馬斯洛的開發者需求層次結構中,它絕對接近頂部(好吧,這是我編的😅) ![開發需求](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/412awt20ksr3d44a4b7b.jpeg) 例如,根據 [StateOfJS](https://2022.stateofjs.com/en-US/libraries/front-end-frameworks/) 2022 年調查(我們仍在等待 2023 年結果),2018年留存率較高的前端框架有5個; 2022 年有 11 個。這在 4 年內增長了 120%,這甚至沒有考慮到像 NextJS、SvelteKit 或Astro ! ![多年來的框架](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94zifqs2ui1rxt9kc0yw.png) 總體而言,這些都是該領域的巨大發展。它們提高了開發人員速度、捆綁包大小、效能和開發人員體驗等。但它們也讓開發人員和團隊在嘗試決定在下一個專案中使用哪一個時很難做出決定。對於初學者來說更糟糕,這可能是為什麼他們只選擇 React 這個最「主流」的解決方案。 我認為這一切都沒關係,因為最終你選擇哪一個並不重要。 **真正歸根結底,重要的是您選擇的框架**: - 穩定(足夠) - 讓你快速移動 - 讓您達到最終目標 為什麼?因為它們中的大多數都是圍繞著相同的概念建置的,已經證明自己有能力大規模執行,並且擁有可供您參與和學習的社區。 React 可能是職位描述中最突出的一個,但如果你正在尋找一個新角色並且只有 Vue 或 Angular 經驗,我無法想像你會花費一周以上的時間來建置一個副專案做出反應,向未來的雇主展示您的能力。 另一方面,如果您是初學者或初級開發人員,一旦您掌握了 HTML、CSS 和 JS 的基礎知識,學習什麼框架並不重要。我個人開始使用 PHP 學習後端開發,但後來轉向使用 Angular 進行前端開發。在我隨後的第二個角色中,我使用了React,現在我使用[Wasp](https://wasp-lang.dev)(一個基於React 和Node.js 建置的全棧框架)來開發我的副專案, https://reflectdaily.app/ - [開發人員永遠不會停止學習](https://www.youtube.com/watch?v=gl5HvBpUbt8),因此嘲笑任何特定框架都是毫無爭議的——除非它真的很糟糕,但沒有人會繼續這樣做無論如何使用它。 ![使用有效的方法](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjbnn4xijtjrwxz8p9n4.jpeg) 所以,最後,使用有效的方法。因為在99.99%的情況下,你對Web框架的選擇並不會決定你專案的命運。 如果您做了一些研究並找到了適合您需求的框架並且您喜歡使用它 - **使用它**。確實沒有充分的理由不這麼做。 ## 支持我們! 🙏⭐️ ![GH 星星點擊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/id9s6t8rcvfxty40bv2m.gif) 如果您喜歡這篇文章,[考慮在 Github 上給我們一顆星](https://kdta.io/github-wasp-lang-wasp_18)!我們在 Wasp 所做的一切都是開源的,您的支援幫助我們使 Web 開發變得更容易,並激勵我們撰寫更多這樣的文章。 ![支持我們](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qgbmn45pia04bxt6zf83.gif) --- 原文出處:https://dev.to/wasp/the-best-web-framework-doesnt-exist-2aom