🔍 搜尋結果:10

🔍 搜尋結果:10

💻Visual Studio Code 快捷指南、更高的生產力、以及您需要學習的 30 個快捷指令

介紹 == Visual Studio Code 允許您透過命令面板或鍵盤上的快捷鍵存取它提供的幾乎所有功能。 您可能每個工作日工作 8 小時,希望您能在這些工作時間中大部分時間進行編碼。所以你花了很多時間盯著你選擇的程式碼編輯器。 了解一些快捷方式可以幫助您更快地完成工作。知道如何更快地找到您需要的文件。您需要立即執行 NPM 命令,而不是開啟外部終端。 ![雙手在鍵盤上快速打字](https://media.giphy.com/media/eMxZ6lPl8dW9O/giphy.gif) 捷徑備忘單 ===== Visual Studio Code 的開發者 - [視窗](https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf) - [Linux](https://code.visualstudio.com/shortcuts/keyboard-shortcuts-linux.pdf) - [蘋果系統](https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf) 您可以下載這些備忘單,列印出來,然後將其放在辦公桌上以供快速參考,或嘗試在上班途中學習它們。不要試圖一次學會所有這些。這需要時間。所以要有耐心,你就會掌握它們。 鍵位圖 === 您是 Vim 用戶嗎?也許 Emacs 快捷方式已經刻在你的大腦裡了?或者,無論出於何種原因,您使用記事本++並欣賞記事本++的鍵盤快捷鍵😵? Visual Studio 為大家提供了一個擴充功能!讓我們安裝 ⚛ `Atom Keymap` 。我們將在沒有我們心愛的滑鼠的幫助下(幾乎)做到這一點。 1\) 開啟 Visual Studio 程式碼。 2\) Visual Studio Code 開啟後,按: `CTRL+SHIFT+X` 。該快捷方式將打開擴展列表,並且您的遊標將聚焦在搜尋欄上。輸入以下`@category:keymaps` 。 (如果您想了解更多有關本節中擴展程序如何工作的訊息,請在下面發表評論!) 3\) 您現在會看到鍵盤映射清單。按`Tab` ,然後按`Down Arrow ⬇` 。 4\) 按`⬇`直到選擇`Atom Keymap` 。現在按`Enter` 。 5)遺憾的是我找不到選擇「安裝」按鈕的方法。您現在需要點擊🖱! 您可以找到幾乎所有您能想像到的編輯器的鍵盤映射。安裝您最喜歡的那個,您就有了快捷方式!很酷吧? 鍵盤快速鍵設定 (JSON) ============== 有多種方法可以查看鍵盤快捷鍵設定。其中一種是透過圖形介面,也可以選擇使用透過 JSON 檔案來編輯捷徑。 圖形介面 ---- 我們可以按`CTRL+k`開啟圖形介面,然後仍然按住`CTRL` ,您應該按`CTRL+s` 。 ![鍵盤快捷鍵設定 GUI](https://thepracticaldev.s3.amazonaws.com/i/3etyosi4ljtp1d9lvk5i.png) 頂部有一個搜尋欄,您可以在其中搜尋要查看的命令或鍵盤快捷鍵。這些對話框在 Visual Studio Code 中看起來往往相同,您將開始經常看到它們。 您可以看到四列。讓我們來看看它們。 \*指令:Visual Studio Code 執行的操作。 - 鍵綁定:執行操作時必須按下的按鍵組合。 - 何時:這是 Visual Studio Code 的過濾器,它告訴 Visual Studio Code 捷徑是否應該在該上下文中可操作。有些過濾器可能是整合終端、原始碼中的錯誤等等。 - 來源:Visual Studio 程式碼可以透過多種方式了解捷徑。最常見的是`Default` ,這些命令是 Visual Studio Code 隨附的開箱即用命令。顧名思義`User`是由用戶建立的命令。第三種方式是透過`Extension` 。擴展作者還可以決定加入快捷方式。如果您最喜歡的快捷方式不起作用,這可能是它停止工作的原因。 若要變更鍵綁定,請雙擊該行,然後會彈出一個模式。然後按下所需的組合鍵並按下`Enter` 。 鍵綁定 JSON 文件 ----------- 現在我們知道了鍵綁定的一般工作原理,讓我們來看看`keybindings.json`檔案。 其中有兩個:預設的`keybindings.json`和使用者特定的`keybindings.json`檔案。按`CTRL+SHIFT+P`或`F1`開啟命令匣並鍵入`keyboard shortcuts`現在您應該在命令托盤中看到至少兩個條目。 - 首選項:開啟預設鍵盤快速鍵 (JSON)。 這是 Visual Studio Code 儲存所有預設快捷方式的文件,以及底部未使用的可用捷徑清單。我會避免在這裡更改它們。 - 首選項:開啟鍵盤快速鍵 (JSON) 這是用戶特定的鍵綁定文件,您應該編輯此文件。一開始,它只是一個空陣列而已! 要在 JSON 檔案中新增快捷方式,您只需新增一個如下所示的物件: ``` [ { "key": "CTRL+ALT+P", "command": "git.pull", "when": "" } ] ``` 您需要指定密鑰和命令。 `when`告訴 Visual Studio Code 應在何處執行此命令。如果你把它留空,它會到處監聽。我們在上一部分談到了這一點。 有用的快捷鍵 ====== 打開命令面板 ------ 您已經知道這一點,但也許您跳到了這一部分 😉 - `CRTL+SHIFT+P`或`F1` 這將開啟 Visual Studio Code 中最強大的功能。命令面板。只需輸入您認為想要的內容,它仍然可以找到它! 打開和關閉側邊欄 -------- 有時您想要更多的水平空間,但側邊欄卻妨礙了您!只需按 - `CTRL+B` 您可以打開和關閉側邊欄 輸入禪宗模式 ------ 你喜歡 Visual Studio 程式碼中的 Zen Mod 嗎?是的,它是內建的! 為此,您需要按: - `CTRL+k` ,放開兩個按鍵並按`z` 。 這將打開和關閉 Zen Mod。 聚焦綜合終端 ------ 我最喜歡的功能之一是 Visual Studio Code 中的整合終端機。我99%的時間都在用它!因此要快速打開或關閉它,您需要按: - `CTRL+j` 這將打開整合終端並將遊標聚焦在其中。如果您再次按下它,它將關閉,並且您的遊標將返回到原來的位置。 在您的專案中搜尋文件 ---------- Visual Studio Code 有一個很棒的檔案搜尋內建功能。當您使用遠端擴展時,它也非常快。要打開它,您只需按: - `CTRL+p` 這將打開一個對話框,您可以在其中查看最近打開的文件,這本身就非常好。它還支援模糊搜尋。這意味著您可以鍵入任何單字,它會在檔案的路徑中找到。所以你不必精確!該對話還支持更多的事情。例如`go-to line`或除錯以及更多功能!如果您想了解更多請在下面評論。 切換到最近開啟的工作區 ----------- 您在微服務架構中工作並且需要一直切換資料夾?因為你不使用 mono 倉庫?我有捷徑給你!按: - `CTRL+r` 這將開啟一個對話框,其中包含最近開啟的工作區/資料夾的清單。 額外提示:如果您在該對話方塊中按`CTRL+ENTER` Visual Studio Code 將在新視窗中開啟它。 分割編輯器視窗 ------- 人們喜歡 vim,因為它很容易在編輯器之間分割視圖。 Visual Studio Code 也內建了功能。只需按 - `CTRL+\` 若要建立 2 列或 - `CTRL+k` ,放開`k`並按住`CTRL`並按`\` 建立一個新行。第二個聽起來比它更難,但是一旦它進入你的大腦,它需要你幾秒鐘的時間,你現在知道如何更改或建立新的快捷方式😉 聚焦編輯器視窗 ------- 既然您知道如何拆分編輯器窗口,您還需要學習如何快速跳轉這些視圖。這非常簡單,並且還有預設的鍵綁定。你需要按 - `CTRL+[1-9]` 這表示您需要按`CTRL`加您想要關注的視窗的編號。對於第一個視窗按`CTRL+1` ,第二個視窗`CTRL+2` ,您明白了 Easy 的想法嗎? 關閉目前編輯器視窗 --------- 現在您打開了太多編輯器窗口,並且您想要關閉它們。這可以透過按快速完成 - `CTRL+w` 這將關閉目前開啟的視窗。 僅關閉已儲存的編輯器視窗 ------------ 有時您會開啟如此多的編輯器,以至於您不再知道要儲存了什麼。是的,我知道您可以透過選項卡欄中的那個點看到這一點,但是,您仍然無法集中精力並找到正確的檔案。 Visual Studio Code 為您提供支援!只需按 - `CTRL+k`然後放開`CTRL`和`k`並按`u` 這將保存所有窗口,以便您可以檢查未保存的窗口並保存它們。 開啟一個新文件 ------- 您需要一個新檔案來繪製一些程式碼嗎?或者,您需要為您的寵物專案建立一個新檔案?按 - `CTRL+n` 這將開啟一個新編輯器。 更改目前文件的語言 --------- 您想切換目前文件中選定的語言,因為您想要`Javascript (react)`而不是`Javascript` ?按 - `CTRL+k` 然後放開`CTRL`和`k`並按 'm`。 這將打開一個新的對話,您可以在其中搜尋所需的語言。 前往線路 ---- 現在讓我們專注於如何讓編輯變得更容易。第 1042 行有錯誤(如果您的文件那麼長,那麼問題就來了)。你不想滾動!按 - `CTRL+g` 這將開啟一個對話框,您需要輸入要跳到的行號。與`CTRL+p`結合使用會非常強大。 轉到符號 ---- 您的第一個問題是,什麼是符號?在程式語言中,符號通常是變數。在 CSS 中,它們是選擇器。若要查看對話,請按 - `CTRL+SHIFT+O` 這將開啟一個對話框,其中包含目前文件中可用符號的清單。 - `CTRL+t` 您會看到一個只有`#`的對話框,您需要鍵入所需的符號,Visual Studio Code 會在空工作區中搜尋該符號(如果您使用的語言支援該符號)。所以你需要自己檢查一下。 向上或向下移動一條線。 ----------- 有時您需要移出`if`內的那行程式碼,或只是移動一行,因為它被提前呼叫了。您可以透過按 - `Alt+Down` 將目前選定的行向下移動一行 - `Alt+Up` 將目前選定的行向上移動一行 複製目前行 ----- 您想用一些變數填充該陣列,但您懶得寫一個循環。那麼要如何填滿`array[0]` `array[1]`和`array[2]`呢?透過複製第一行兩次並僅更改您需要的內容。對於那個新聞界 - `ALT+SHIFT+Up` 這將複製當前選定的行並將其貼上到上面的一行中 - `ALT+SHIFT+Down` 這將複製目前選定的行並將其貼上到下面的一行中 (這個快捷方式在這裡會很方便) 顯示建議 ---- Visual Studio Code 有內建建議。大多數時候它會自動為您彈出,但有時不會,而您確實需要它。簡單,按 - `CTRL+Spacebar` 這將打開建議對話框 註解掉目前選擇 ------- 有時您需要隔離程式碼並註解掉它周圍的所有內容。按 - `CTRL+/` 如果您選擇了多行,則會將其註解掉。如果您沒有選擇任何內容,它只會註解掉這一行。 選擇多行程式碼 ------- 要註解掉該程式碼區塊,您需要選擇多行。這是透過按完成的 - `CTRL+Shift+Up` 從目前行開始選擇並向上移動遊標。 - `CTRL+Shift+down` 從目前行開始選擇並向下移動遊標。 折疊和展開您的程式碼 ---------- 你有這麼大的功能,但你真的看不到它了,因為它太大了,需要重構,但你沒有時間,所以你想忘記它嗎?您可以折疊和展開程式碼,以便在 100 行中可以產生 1 行。若要執行此操作,請按 - `CTRL+SHIFT+[` 折疊(隱藏)程式碼 - `CTRL+SHIFT+]` 展開(顯示)程式碼 切一條孔線 ----- 對於此,您不能選擇任何程式碼。按 - `CTRL+x` 當沒有選擇任何內容時,這會剪切整行。 縮排/減少線 ------ 人們通常知道如何縮排程式碼。您可以選擇要縮排的程式碼並按 - `Tab` 按下您想要的次數按 Tab 鍵,這樣效果就適合您了。 您知道可以取消縮排嗎?將程式碼從右移到左?您可以透過按 - `SHIFT+tab` 結論 == 還有更多的捷徑。這些快捷鍵是我最常使用的快捷鍵。我希望這可以幫助您更多地了解 Visual Studio Code 中的快捷方式,並且您現在可以建立自己的快捷方式。 我是否忽略了每個人都需要知道的有用命令? 你錯過了什麼嗎?有什麼不清楚嗎? 請寫評論。我盡我所能回答你所有的問題! **👋問好!** [Instagram](https://www.instagram.com/lampewebdev/) |[推特](https://twitter.com/lampewebdev)|[領英](https://www.linkedin.com/in/michael-lazarski-25725a87)|[中等](https://medium.com/@lampewebdevelopment)|[抽搐](https://dev.to/twitch_live_streams/lampewebdev)| [Youtube](https://www.youtube.com/channel/UCYCe4Cnracnq91J0CgoyKAQ) --- 原文出處:https://dev.to/lampewebdev/the-guide-to-visual-studio-code-shortcuts-higher-productivity-and-30-of-my-favourite-shortcuts-you-need-to-learn-mb3

如何撰寫出色的 README 文件

可以說,對於任何開源專案來說,最重要的文件就是自述文件。一個好的自述文件不僅告訴人們該專案的用途和用途,還告訴人們他們如何使用該專案並為其做出貢獻。 如果您在撰寫自述文件時沒有充分解釋您的專案的用途或人們如何使用它,那麼它幾乎違背了開源的目的,因為其他開發人員不太可能參與或為其做出貢獻。 TL;DR - 太長?跳到最後並使用我的[模板](#template)。 什麼是自述文件? -------- 本質上,自述文件是一個單一的文字檔案( `.txt`或`.md` ),可作為專案或目錄的一站式文件。對於大多數開源專案來說,它通常是最明顯的文件和登陸頁面。即使自述文件的名稱全部大寫,也是為了吸引讀者的注意力並確保這是他們首先閱讀的內容。 有證據顯示自述文件的歷史可以追溯到 20 世紀 70 年代。我能找到的最古老的例子是 DEC PDP-10 計算機的[自述文件](http://pdp-10.trailing-edge.com/decus_20tap3_198111/01/decus/20-0079/readme.txt.html),日期為 1974 年 11 月 27 日。儘管自述文件名稱的起源存在爭議,但最流行的兩種理論是: 1. 帶有打孔卡的原始大型計算機的程式設計師會留下一疊帶有“READ ME!”的紙質指令。寫在前面。 2. 這個名字是向劉易斯·卡羅爾的《愛麗絲夢遊仙境》致敬,其中主角愛麗絲發現了一瓶標有“喝我”的藥水和標有“吃我”的蛋糕,這使她的體型發生了變化。 自述文件中應包含哪些內容? ------------- 好的,那麼一個很棒的自述文件該包含什麼內容呢?作為起點,我建議您包括以下關鍵內容: **1. 命名事物** 不要忘記為您的專案或功能命名。 GitHub 上有數量驚人的沒有名稱的專案。 **2. 介紹或總結** 寫一篇簡短的兩三行簡介,解釋你的專案的用途和用途。還要省略“簡介”、“摘要”或“概述”等標題 - 很明顯這是一個簡介。 **3. 先決條件** 在介紹之後立即加入一個部分,標題為列出任何想要使用該專案的人在開始之前可能需要的任何先決知識或工具。例如,如果它在最新版本的 Python 上執行,請告訴他們安裝 Python。這是一個例子: ``` Prerequisites Before you continue, ensure you have met the following requirements: * You have installed the latest version of Ruby. * You are using a Linux or Mac OS machine. Windows is not currently supported. * You have a basic understanding of graph theory. ``` **4. 如何安裝** 提供安裝步驟!令人驚訝的是,我遇到的許多專案只提供基本的使用說明,並期望您神奇地知道如何安裝它。如果需要多個步驟,請確保將安裝分解為編號的步驟。 **5. 如何使用該東西** 新增使用者安裝專案後如何使用該專案的步驟。如果您認為有用,請確保包含使用範例和解釋命令選項或標誌的參考。如果您在單獨的文件或網站中有更高級的文件,請從此處連結到該文件。 **6. 如何為事情做出貢獻** 提供為專案做出貢獻的步驟。或者,如果您希望人們在向您的專案貢獻拉取請求之前閱讀它,您可能希望在單獨的文件中建立貢獻者指南,並從自述文件連結到該指南。 **7. 加入貢獻者** 在作者部分感謝為該專案提供幫助的任何貢獻者。這是一種很好的方式,讓開源感覺像是團隊的努力,並感謝每個花時間做出貢獻的人。 **8. 加入致謝** 同樣,如果您使用了其他人的作品(程式碼、設計、圖像等),並且該作品具有需要確認的版權,您可能需要在此處加入。您還可以感謝為該專案提供幫助的任何其他開發商或機構。 **九、聯絡方式** 您可能不想這樣做,因為您是一個非常注重隱私的人,但如果有人有疑問、想要與您合作或對您的專案印象深刻並為您提供工作機會,那麼將您的聯絡方式放在前面是有意義的中心。 **10.新增許可證訊息** 如果適用,您肯定希望包含許可證資訊。除非您提供此軟體,否則依賴第三方軟體的新創公司和其他公司不太可能能夠使用您的專案。請造訪[Choosealicense.com](https://choosealicense.com/)或[opensource.org](https://opensource.org/licenses) ,以取得您可以使用的授權清單。 在您的自述文件中加入耀斑 🔥 -------------- 如果您確實想讓您的自述文件脫穎而出並且看起來具有視覺吸引力,您可以執行以下操作: - **新增徽標**:如果您的專案有徽標,請將其新增至自述文件的頂部。品牌使專案看起來更專業並幫助人們記住它。 - **新增徽章或盾牌**:您可以新增徽章和盾牌以反映專案的當前狀態、它使用的許可證以及它使用的任何依賴項是否是最新的。而且它們看起來很酷!您可以在[Shields.io](https://shields.io/)找到徽章清單或自行設計。 - **新增螢幕截圖**:有時一個簡單的螢幕截圖或一組螢幕截圖可以表達的內容遠遠超過一千個單字。但請注意,如果您確實使用螢幕截圖,則每次更新專案時都需要更新它們。 - **使用表情符號?** :現在很多專案似乎都使用表情符號,儘管是否使用它們取決於您。它們是為你的自述文件注入一點色彩和幽默的好方法,讓專案感覺更人性化。 如果您使用[所有貢獻者](https://allcontributors.org/)來感謝貢獻,您可以使用他們的[表情符號鍵](https://allcontributors.org/docs/en/emoji-key)來表示不同的貢獻類型: ``` * 🐛 for raising a bug ``` ``` * 💻 for submitting code ``` ``` * 📖 for docs contributions etc. ``` 這是 GitHub 徽章或盾牌的樣子,供參考(毫無疑問您以前見過它們!): ![Shields.io 徽章](https://thepracticaldev.s3.amazonaws.com/i/de766ouyuouxmjs2yvcm.png) 我的模板<a name="template"></a> --------------------------- 我建立了一個模板,涵蓋了本文中提出的大部分建議。請隨意分叉存儲庫,提出改進建議或根據自己的目的自訂它!您可以在 GitHub[上](https://github.com/scottydocs/README-template.md)找到我的模板。 資源 -- 如果您需要更多有關自述文件的建議,我還推薦以下資源: - Daniel Beck 在 2016 年 Write the Docs 的演講[「Write the Readable」](https://www.youtube.com/watch?v=2dAK42B7qtw) 。 - Lorna Jane Mitchell 在 API 文件 2019 中的演講[「Github 作為登陸頁面」](https://youtu.be/fXMN4X9B8Rg) 。 - 查看 Franck Abgrall 的[README 產生器](https://github.com/kefranabg/readme-md-generator)。 --- 原文出處:https://dev.to/scottydocs/how-to-write-a-kickass-readme-5af9

S.O.L.I.D:提升編碼技能的 5 個黃金法則

在軟體開發領域,這個以其多樣化和強烈持有觀點而聞名的領域,很少有實踐能夠像 SOLID 原則那樣達成共識,作為成為更好的軟體工程師的保證途徑。 Robert C. Martin 在 2000 年代初期正式製定的 5 條黃金法則極大地影響了軟體開發產業,並為更好的程式碼品質和決策過程製定了新標準,至今仍具有相關性。 ![堅實的原則](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2mdlic5qf7f0ws36owf.jpg) SOLID 原則是專門為支援 OOP(物件導向程式設計)範例而設計的。因此,本文是為希望提高開發技能並編寫更優雅、可維護和可擴展程式碼的 OOP 開發人員而設計的。 這裡使用的語言是 TypeScript,遵循常見的跨語言 OOP 概念。需要基本的 OOP 知識。 --- 1. S = 單一職責原則(SRP) ------------------ 單一職責原則 (SRP) 是五個 SOLID 原則之一,它規定每個類別應該只有一個職責,以保持有意義的關注點分離。 此模式是一種稱為「上帝物件」的常見反模式的解決方案,「上帝物件」只是指承擔太多職責的類別或物件,使其難以理解、測試和維護。 遵循 SRP 規則有助於使程式碼元件可重複使用、鬆散耦合且易於理解。讓我們探討這項原則,展示 SRP 違規情況和解決方案。 ### 全域宣告 ``` enum Color { BLUE = 'blue', GREEN = 'green', RED = 'red' } enum Size { SMALL = 'small', MEDIUM = 'medium', LARGE = 'large' } class Product { private _name: string; private _color: Color; private _size: Size; constructor (name: string, color: Color, size: Size) { this._name = name; this._color = color; this._size = size; } public get name(): string { return this._name; } public get color(): Color { return this._color; } public get size(): Size { return this._size; } } ``` ### 違反 在下面的程式碼中, `ProductManager`類別負責**products 的建立和存儲**,違反了單一職責原則。 ``` class ProductManager { private _products: Product[] = []; createProduct (name: string, color: Color, size: Size): Product { return new Product(name, color, size); } storeProduct (product: Product): void { this._products.push(product); } getProducts (): Product[] { return this._products; } } const productManager: ProductManager = new ProductManager(); const product: Product = productManager.createProduct('Product 1', Color.BLUE, Size.LARGE); productManager.storeProduct(product); const allProducts: Product[] = productManager.getProducts(); ``` ### 解決 將產品建立和儲存的處理分離到兩個不同的類別可以減少`ProductManager`類別的職責數量。這種方法進一步模組化了程式碼並使其更易於維護。 ``` class ProductManager { createProduct (name: string, color: Color, size: Size): Product { return new Product(name, color, size); } } class ProductStorage { private _products: Product[] = []; storeProduct (product: Product): void { this._products.push(product); } getProducts (): Product[] { return this._products; } } ``` #### 用法: ``` const productManager: ProductManager = new ProductManager(); const productStorage: ProductStorage = new ProductStorage(); const product: Product = productManager.createProduct("Product 1", Color.BLUE, Size.LARGE); productStorage.storeProduct(product); const allProducts: Product[] = productStorage.getProducts(); ``` --- 2. O = 開閉原理 (OCP) ----------------- > “軟體實體應該對擴展開放,但對修改關閉” 開閉原則 (OCP) 是*「寫一次,寫得夠好以便可擴展,然後就忘記它」。* 這項原則的重要性取決於這樣一個事實:模組可能會根據新的需求不時發生變化。如果在模組編寫、測試並上傳到生產環境後出現新需求,則修改此模組通常是不好的做法,尤其是當其他模組依賴它時。為了防止這種情況,我們可以使用開閉原則。 ### 全域宣告 ``` enum Color { BLUE = 'blue', GREEN = 'green', RED = 'red' } enum Size { SMALL = 'small', MEDIUM = 'medium', LARGE = 'large' } class Product { private _name: string; private _color: Color; private _size: Size; constructor (name: string, color: Color, size: Size) { this._name = name; this._color = color; this._size = size; } public get name(): string { return this._name; } public get color(): Color { return this._color; } public get size(): Size { return this._size; } } class Inventory { private _products: Product[] = []; public add(product: Product): void { this._products.push(product); } addArray(products: Product[]) { for (const product of products) { this.add(product); } } public get products(): Product[] { return this._products; } } ``` ### 違反 讓我們描述一個實作產品過濾類別的場景。讓我們加入按顏色過濾產品的功能。 ``` class ProductsFilter { byColor(inventory: Inventory, color: Color): Product[] { return inventory.products.filter(p => p.color === color); } } ``` 我們已經測試了此程式碼並將其部署到生產中。 幾天后,客戶請求一項新功能 - 也按大小過濾。然後我們修改該類別以支援新的要求。 **現在違反了開閉原則!** ``` class ProductsFilter { byColor(inventory: Inventory, color: Color): Product[] { return inventory.products.filter(p => p.color === color); } bySize(inventory: Inventory, size: Size): Product[] { return inventory.products.filter(p => p.size === size); } } ``` ### 解決 在不違反 OCP 的情況下實現過濾機制的正確方法應該使用「規範」類別。 ``` abstract class Specification { public abstract isValid(product: Product): boolean; } class ColorSpecification extends Specification { private _color: Color; constructor (color) { super(); this._color = color; } public isValid(product: Product): boolean { return product.color === this._color; } } class SizeSpecification extends Specification { private _size: Size; constructor (size) { super(); this._size = size; } public isValid(product: Product): boolean { return product.size === this._size; } } // A robust mechanism to allow different combinations of specifications class AndSpecification extends Specification { private _specifications: Specification[]; // "...rest" operator, groups the arguments into an array constructor ((...specifications): Specification[]) { super(); this._specifications = specifications; } public isValid (product: Product): boolean { return this._specifications.every(specification => specification.isValid(product)); } } class ProductsFilter { public filter (inventory: Inventory, specification: Specification): Product[] { return inventory.products.filter(product => specification.isValid(product)); } } ``` #### 用法: ``` const p1: Product = new Product('Apple', Color.GREEN, Size.LARGE); const p2: Product = new Product('Pear', Color.GREEN, Size.LARGE); const p3: Product = new Product('Grapes', Color.GREEN, Size.SMALL); const p4: Product = new Product('Blueberries', Color.BLUE, Size.LARGE); const p5: Product = new Product('Watermelon', Color.RED, Size.LARGE); const inventory: Inventory = new Inventory(); inventory.addArray([p1, p2, p3, p4, p5]); const greenColorSpec: ColorSpecification = new ColorSpecification(Color.GREEN); const largeSizeSpec: SizeSpecification = new SizeSpecification(Size.LARGE); const andSpec: AndSpecification = new AndSpecification(greenColorSpec, largeSizeSpec); const productsFilter: ProductsFilter = new ProductsFilter(); const filteredProducts: Product[] = productsFilter.filter(inventory, andSpec); // All large green products ``` 過濾機制現在是完全可擴展的。現有的類別不應該再被修改。 如果有新的過濾要求,我們只需建立一個新規範即可。或者如果需要更改規範組合,可以透過使用`AndSpecification`類別輕鬆完成。 --- 3. L=里氏替換原理(LSP) ---------------- 里氏替換原則(LSP)是軟體元件靈活性和穩健性的重要規則。它由 Barbara Liskov 提出,並成為 SOLID 原則的基本要素。 LSP 規定**超類別的物件應該可以用子類別的物件替換,而不影響程式的正確性。**換句話說,子類別應該擴展超類別的行為而不改變其原始功能。採用這種方法可以提高軟體元件的質量,確保可重複使用性並減少意外的副作用。 ### 違反 下面的範例說明了違反里氏替換原則 (LSP) 的場景。當`Rectangle`物件被`Square`物件取代時,透過檢查程序的行為可以觀察到這種違規的跡象。 #### 聲明: ``` class Rectangle { protected _width: number; protected _height: number; constructor (width: number, height: number) { this._width = width; this._height = height; } get width (): number { return this._width; } get height (): number { return this._height; } set width (width: number) { this._width = width; } set height (height: number) { this._height = height; } getArea (): number { return this._width * this._height; } } // A square is also rectangle class Square extends Rectangle { get width (): number { return this._width; } get height (): number { return this._height; } set height (height: number) { this._height = this._width = height; // Changing both width & height } set width (width: number) { this._width = this._height = width; // Changing both width & height } } function increaseRectangleWidth(rectangle: Rectangle, byAmount: number) { rectangle.width += byAmount; } ``` #### 用法: ``` const rectangle: Rectangle = new Rectangle(5, 5); const square: Square = new Square(5, 5); console.log(rectangle.getArea()); // Expected: 25, Got: 25 (V) console.log(square.getArea()); // Expected: 25, Got: 25 (V) // LSP Violation Indication: Can't replace object 'rectangle' (superclass) with 'square' (subclass) since the results would be different. increaseRectangleWidth(rectangle, 5); increaseRectangleWidth(square, 5); console.log(rectangle.getArea()); // Expected: 50, Got: 50 (V) // LSP Violation, increaseRectangleWidth() changed both width and height of the square, unexpected behavior. console.log(square.getArea()); //Expected: 50, Got: 100 (X) ``` ### 解決 重構的程式碼現在遵循 LSP,確保超類別`Shape`的物件可以替換為子類別`Rectangle`和`Square`的物件,而不會影響計算面積的正確性,也不會引入任何改變程式行為的不必要的副作用。 #### 聲明: ``` abstract class Shape { public abstract getArea(): number; } class Rectangle extends Shape { private _width: number; private _height: number; constructor (width: number, height: number) { super(); this._width = width; this._height = height; } getArea (): number { return this._width * this._height; } } class Square extends Shape { private _side: number; constructor (side: number) { super(); this._side = side; } getArea (): number { return this._side * this._side; } } function displayArea (shape: Shape): void { console.log(shape.getArea()); } ``` #### 用法: ``` const rectangle: Rectangle = new Rectangle(5, 10); const square: Square = new Square(5); // The rectangle's area is correctly calculated displayArea(rectangle); // Expected: 50, Got: 50 (V) // The square's area is correctly calculated displayArea(square); // Expected: 25, Got: 25 (V) ``` --- 4. I = 介面隔離原則 (ISP) ------------------- 介面隔離原則 (ISP) 強調建立特定於客戶端的介面而不是一刀切的重要性。 這種方法根據客戶的需求集中類,消除了類別必須實現它實際上不使用或不需要的方法的情況。 透過應用介面隔離原則,軟體系統可以以更靈活、易於理解和易於重構的方式建構。讓我們來看一個例子。 ### 違反 這裡違反了 ISP 規則,因為`Robot`必須實現完全沒有必要的`eat()`函數。 ``` interface Worker { work(): void; eat(): void; } class Developer implements Worker { public work(): void { console.log('Coding..'); } public eat(): void { console.log('Eating..'); } } class Robot implements Worker { public work(): void { console.log('Building a car..'); } // ISP Violation: Robot is forced to implement this function even when unnecessary public eat(): void { throw new Error('Cannot eat!'); } } ``` ### 解決 下面的範例代表了我們之前遇到的問題的解決方案。現在,介面更加簡潔且更加特定於客戶端,允許客戶端類別僅實現與其相關的方法。 ``` interface Workable { work(): void; } interface Eatable { eat(): void; } class Developer implements Workable, Eatable { public work(): void { console.log('Coding..'); } public eat(): void { console.log('Eating...'); } } class Robot implements Workable { public work(): void { console.log('Building a car..'); } // No need to implement eat(), adhering ISP. } ``` #### ISP 前後: ![重構前後的介面隔離原則](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szh5wkpkc30z4t91j5oy.png) --- 5. D = 依賴倒置原理(DIP) ------------------ 依賴倒置原則(DIP)是最終的SOLID原則,重點是透過使用抽象來減少低層模組(例如資料讀取/寫入)和高層模組(執行關鍵操作)之間的耦合。 DIP 對於設計能夠適應變化、模組化且易於更新的軟體至關重要。 **DIP 的關鍵準則是:** 1. **高層模組不應該依賴低層模組。兩者都應該依賴抽象。**這意味著應用程式的功能不應該依賴特定的實現,以便使系統更加靈活並且更容易更新或替換低階實現。 2. **抽像不應該依賴細節。細節應該取決於抽象。**這鼓勵設計專注於實際需要什麼操作,而不是如何實現這些操作。 ### 違反 讓我們來看一個展示依賴倒置原則 (DIP) 違規的範例。 `MessageProcessor` (高階模組)緊密耦合並直接依賴`FileLogger` (低階模組),違反了原則,因為它不依賴抽象層,而是依賴特定的類別實作。 **額外獎勵:**這也違反了開閉原則(OCP)。如果我們想要更改日誌記錄機制以寫入資料庫而不是文件,我們將被迫直接修改`MessageProcessor`函數。 ``` import fs from 'fs'; // Low Level Module class FileLogger { logMessage(message: string): void { fs.writeFileSync('somefile.txt', message); } } // High Level Module class MessageProcessor { // DIP Violation: This high-level module is is tightly coupled with the low-level module (FileLogger), making the system less flexible and harder to maintain or extend. private logger = new FileLogger(); processMessage(message: string): void { this.logger.logMessage(message); } } ``` ### 解決 以下重構的程式碼表示為了遵守依賴倒置原則 (DIP) 所需進行的變更。與前面的範例相反,高階類別`MessageProcessor`持有特定低階類別`FileLogger`的私有屬性,現在它持有`Logger`類型的私有屬性(表示抽象層的介面)。 這種更好的方法減少了類別之間的依賴關係,從而使程式碼更具可擴展性和可維護性。 #### 聲明: ``` import fs from 'fs'; // Abstraction Layer interface Logger { logMessage(message: string): void; } // Low Level Module #1 class FileLogger implements Logger { logMessage(message: string): void { fs.writeFileSync('somefile.txt', message); } } // Low Level Module #2 class ConsoleLogger implements Logger { logMessage(message: string): void { console.log(message); } } // High Level Module class MessageProcessor { // Resolved: The high level module is now loosely coupled with the low level logger modules. private _logger: Logger; constructor (logger: Logger) { this._logger = logger; } processMessage (message: string): void { this._logger.logMessage(message); } } ``` #### 用法: ``` const fileLogger = new FileLogger(); const consoleLogger = new ConsoleLogger(); // Now the logging mechanism can be easily replaced const messageProcessor = new MessageProcessor(consoleLogger); messageProcessor.processMessage('Hello'); ``` #### DIP 之前和之後: ![重構前後的依賴倒置原則](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kju8qfpie60b104vuz90.png) 結論 -- 透過遵循 SOLID 原則,開發人員在開發或維護任何規模的軟體系統時,可以避免常見的陷阱,例如緊密耦合、缺乏靈活性、程式碼可重複使用性差以及一般維護困難。掌握這些原則是成為更好的軟體工程師的又一步。 --- 原文出處:https://dev.to/idanref/solid-the-5-golden-rules-to-level-up-your-coding-skills-2p82

如何編寫有用的 commit 訊息(我的提交訊息範本)

我們都曾在某個時刻經歷過有關 git commit 訊息的混亂。 ![XKCD - 隨著專案的拖延,我的 git 提交訊息的資訊量越來越少](https://thepracticaldev.s3.amazonaws.com/i/xn60rbbj7353tb5gtkh1.png) 我也不例外。我的部落格的提交訊息如下所示: ``` fixxxx stuff post post post post posts mmm posts front maddy Add chris oliver add syntax article add git patch article fix video video arty art art Fix links oops ``` 因為我部落格的 git 歷史記錄只有我自己看過,所以沒關係。我已經接受了我永遠無法在我的部落格中充分利用 git 的事實,而且我完全同意這一點。 不幸的是,有些人對待有多個貢獻者的真實專案就像我對待我的部落格一樣。我發現這種做法是無知而不是懶惰的結果。因此,我將分享一些關於如何在實際專案中使用提交訊息的技巧。 ### 為什麼要關心? 😤[我不在乎,跳到模板!](#the-final-template) 🚀 Git 是一個強大的工具,即使您只使用它來保存程式碼更改歷史記錄並且不利用其最強大的功能。 然而,你會發現你挖掘得越深,git 就會變得越強大。您還會發現 git 的許多最有用的功能都是在提交訊息有用的假設下運作的。 想想你上次使用`git blame`是什麼時候。如果您發現一條提交訊息,上面`fixed a bad bug` ,這會有幫助嗎?可能不是,您可能試圖找到有關您正在處理的程式碼的更多上下文;你需要解釋什麼以及為什麼。 Git 提交訊息必須包含每次更改背後的內容和原因,以便明天勇敢的 git 探索者能夠進入提交作者的頭腦。如果提交訊息不包含該訊息,為什麼還要寫一個?提交訊息只有在對將來某個時候試圖理解更改的人有用時才有用。 為了建立一個良好的提交訊息的模板,我將把提交訊息分成幾個部分。 ### 首先,主題行 在提交訊息中,第一行(有時稱為主題行)應與正文隔離。理想情況下,這一行總結了提交中所做的更改。 當我寫主題行時,我嘗試完成這句話,“這次提交將......” 例如,我可能會編寫一個主題行,內容類似於`Remove unused, commented code` 。這可以很好地結束我的句子:“此提交將刪除未使用的帶註釋的程式碼。” 在設定主題行格式時,需要記住一兩個規則。 首先,主題行中的第一個字元應大寫;這只是一個常見的約定。根據我的經驗,它還使閱讀一長串的單行提交清單變得更加容易。 其次,您的提交訊息不應超過五十個字元。這是因為 GitHub 等工具會將該行截斷為 50 個字元。因此,為了讓其他人能夠有效地瀏覽和理解你的主題行,你應該嘗試用五十個字符來總結整個變化。 我的提交訊息範本的第一行如下所示: `Summarize the change in less than 50 characters` ### 接下來,第一個正文“段落” 在某些提交中,主題行足以傳達整個想法。例如,如果您的提交將`Add a comma to the README` ,您可能不需要自己解釋。 然而,在大多數提交中,您的更改可能會受益於一些額外的上下文。我們不希望未來的開發人員在嘗試理解更改背後的原因時錯過上下文。 這就是訊息正文發揮作用的地方。我將正文分為“段落”,這些“段落”只是鬆散定義的由空格分隔的文字字串。它們可以是要點、句子或其他東西;重要的是它們從冷開始就易於閱讀和理解。 過去,我通常使用提交訊息正文的第一段來解釋我所做的事情。這些天,我已經不再關注*「什麼」* ,而是開始記錄*「為什麼」* 。 [Ben Orenstein 最近改變了我對提交訊息格式的看法](https://twitter.com/r00k/status/1175100703829909505?s=20): {% 推特 1175100703829909505 %} 因此,在這種情況下,我們想要引導我們做出改變*的原因*。 這是一個例子: ``` Refactor the coupon UI Because: - The old UI code is fairly slow - There were a few unused dependencies - The old UI has aged poorly ``` 這些「段落」的偉大之處在於只有一個格式規則:72 個字元換行。這更多的是一種遺留傳統,而不是任何實質的東西。然而,主要原因是這允許 git 縮進一些空間(假設最大字元限制為 80)。我建議遵循這條規則,儘管它並不總是嚴格必要的。 這是到目前為止的提交訊息範本: ``` Summarize the change in less than 50 characters Because: - Explain the reasons you made this change - Make a new bullet for each reason - Each line should be under 72 characters ``` ### 現在是第二正文“段落” 既然我們已經總結了更改並分享了進行更改的原因,那麼以較長的形式準確地解釋我們所做的事情可能是謹慎的做法。 我用第二個「段落」來更詳細地解釋我在更改中所做的事情,例如: ``` Refactor the coupon UI Because: - The old UI code is fairly slow - There were a few unused dependencies - The old UI has aged poorly I thought it was necessary to remove some of the old coupon UI code. Unfortunately, it has aged pretty poorly, and I think this refactor makes the code much easier to support in the long-run. Primarily, this commit improves the performance of the coupon component. It also removes some unused dependencies. ``` 提交正文的這一部分應該比 50 個字元的摘要更深入地解釋所做的事情。格式由您決定(只要您以 72 個字元換行即可)。 這是更新後的模板: ``` Summarize the change in less than 50 characters Because: - Explain the reasons you made this change - Make a new bullet for each reason - Each line should be under 72 characters Explain exactly what was done in this commit with more depth than the 50 character subject line. Remember to wrap at 72 characters! ``` ### 其他部分:附加註釋和合著者 此時,我們正在編寫有效且連貫的提交訊息。然而,有時提交訊息需要一些額外的註釋。這可以在最後一節中完成。 例如: ``` Refactor the coupon UI Because: - The old UI code is fairly slow - There were a few unused dependencies - The old UI has aged poorly I thought it was necessary to remove some of the old coupon UI code. Unfortunately, it has aged pretty poorly, and I think this refactor makes the code much easier to support in the long-run. Primarily, this commit improves the performance of the coupon component. It also removes some unused dependencies. These changes should resolve issue #1337. This commit removed the left-pad dependency, so please stop using it! Co-authored-by: nspinazz89 <[email protected]> ``` 在這個例子中我能夠: - 參考相關問題 - 加入一行以警告我刪除了依賴項 - 包含與我一起參與該提交的人員的引用 此時,任何查看此提交訊息的人都會知道: 1. 做了什麼一目了然 2. 為什麼需要改變 3. 有關已完成操作的詳細訊息 4. 有關變更的任何有用的詳細訊息 這使得我們的提交訊息對我們未來的自己和任何其他需要理解我們程式碼的開發人員來說更加有用。 即使您不同意我編寫提交訊息的方法,也很難否認我們必須編寫提交訊息,以便其他開發人員在閱讀我們的程式碼時能夠進入我們的視野。 我認為大多數人都同意“好”程式碼的標誌是可維護性,您可以透過編寫有助於其他人理解甚至將來更改您的程式碼的提交訊息來增強程式碼的可維護性。 ### 最終模板 ``` Summarize the change in less than 50 characters Because: - Explain the reasons you made this change - Make a new bullet for each reason - Each line should be under 72 characters Explain exactly what was done in this commit with more depth than the 50 character subject line. Remember to wrap at 72 characters! Include any additional notes, relevant links, or co-authors. ``` ### 還有更多... 這些天我寫了[很多文章](https://jh.codes),我經營一個[播客](https://www.devpath.fm),並且我已經開始發送一份關於我聽到的所有精彩故事的[時事通訊摘要](https://pages.convertkit.com/674caf55d4/f30f7753a7)。 您還可以在[Twitter](https://twitter.com/jakeherrington)上關注我,我在那裡製作一些愚蠢的表情包並談論如何成為開發人員。 --- 原文出處:https://dev.to/jacobherrington/how-to-write-useful-commit-messages-my-commit-message-template-20n9

#DevOps for noobs - 反向代理簡介

您聽過反向代理嗎?來這裡,我會盡力向你解釋! ### 什麼是代理?<a name="O que é Proxy?"></a> 代理就像電腦和網路之間的中介。當您想要存取網路上的某些內容時,您不是直接連接,而是透過代理連接,然後代理代表您發出請求。收到回應後,代理會將其發送回給您。 有不同類型的代理商! #### 範例:匿名代理<a name="Exemplo: proxy anônimo"></a> 假設您想造訪 google,但您不希望網站知道您的真實 IP 位址。您可以使用匿名代理,而不是直接連接到網站。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5e20g6u7yddrrya6354s.png) 因此,代理商基本上充當您和網路之間的“中介”,出於安全、存取控製或匿名等原因而使用。 ### 反向代理<a name="Proxy Reverso"></a> 假設一家公司擁有三台內部伺服器,每台伺服器託管一個不同的網站:「site1.com」、「site2.com」和「site3.com」。他們設置了反向代理伺服器來處理外部流量。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1mb5glyj2lai1rbke6j8.png) #### 例子:<a name="Exemplo:"></a> 1. 外部用戶端嘗試透過在瀏覽器中輸入位址來存取「site1.com」。 2. 反向代理伺服器接收客戶端請求。 3. 反向代理伺服器將請求轉送到託管「site1.com」的內部伺服器。 4. 內部伺服器處理請求並將回應傳回反向代理伺服器。 5. 反向代理伺服器接收來自內部伺服器的回應並將其發送回外部客戶端。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m9103oqmmap419ixybyl.png) 這種設定允許公司在內部伺服器上託管多個網站,並透過**單一入口點(反向代理)**提供對它們的外部存取。 ### 安全:<a name="Segurança:"></a> 反向代理位於伺服器端,與位於客戶端的普通代理不同。這意味著它位於伺服器和網際網路之間,保護內部伺服器。 此外,反向代理可以配置為提供附加功能,例如負載平衡、內容快取、SSL 加密和請求過濾,以提高安全性和效能。 ### 結論:<a name="Conclusão:"></a> 代理商就像網路的守護者,保護您免受危險網站的侵害,隱藏您的線上身份,甚至繞過網站封鎖。此外,它還可以加快您經常造訪的頁面的載入速度,並關注公司員工的線上活動。 哦,還有一個反向代理,它有助於平衡不同伺服器之間的流量並保持您的網站快速安全地執行。 結束。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsv4qjf30uyx3kkzqco7.png) 感謝那些讀到這裡的人<3 --- 原文出處:https://dev.to/camilacodes/devops-para-noobs-proxy-reverso-1lg0

如何將 .py 轉換為 .exe?一步步指導。

--- 標題: 如何將 .py 轉換為 .exe?一步步指導。 發表:真實 封面圖片:https://thepracticaldev.s3.amazonaws.com/i/3c27e6ni9a7preeeqo0v.jpg 描述:如何將 .py 轉換為 .exe 的說明 標籤: python, 初學者, oop, 學習 --- 自動 PY 到 EXE =========== 我們要使用的唯一工具是**Auto PY to EXE** ! **Auto PY to EXE**是一款令人驚嘆的應用程式,用於從專案中產生 .exe 文件,無論它是一個 .py 檔案還是任意數量的檔案。 該應用程式有一個漂亮的 GUI,如下所示: ![所有文字](https://warehouse-camo.cmh1.psfhosted.org/4fc81b16448c94eda8a266110b56284ca9883185/68747470733a2f2f692e696d6775722e636f6d2f6464304c43326e2e706e67) 如何開始 ---- 步驟一、安裝 ------ 使用 PyPI 安裝: 要安裝該應用程式,請在**cmd**中執行以下行: `pip install auto-py-to-exe` 若要開啟應用程式,請在**cmd**中執行此行: `auto-py-to-exe` 注意:如果您以這種方式安裝時遇到任何問題,或者您想從GitHub 安裝它,請前往\[主頁\] (https://pypi.org/project/auto-py-to-exe) 或觀看此說明影片「Auto PY to EXE」的開發者\[他自己\] (https://github.com/brentvollebregt)。 {% youtube OZSZHmWSOeM %} ### 欲了解更多附加訊息,請使用此 #### \[「使用 auto-py-to-exe 時的問題」\] (https://nitratine.net/blog/post/issues-when-using-auto-py-to-exe) 步驟 2. 轉換 -------- 您需要選擇幾個主要選項: 1. 選擇你的 .py 文件 2. 選擇“一個目錄”或“一個檔案”選項 3. 選擇其他文件 1. 選擇你的 .py 文件 -------------- 如果您有多個文件,請選擇一個來啟動程式。 2.1. 「一個目錄」選項 ------------- ![所有文字](https://thepracticaldev.s3.amazonaws.com/i/9mrf0i0cm0shdgoizjdz.JPG) 很簡單。當選擇“One Directory”選項時,“Auto PY to EXE”會將所有相依性放在**一個資料夾**中。您可以在“進階”選單中選擇輸出目錄。如果您有圖標和背景等媒體文件,如果您將媒體文件/資料夾放在輸出目錄中,那麼在 .exe 中使用它們應該不會有任何問題。 像這樣的東西: ![所有文字](https://thepracticaldev.s3.amazonaws.com/i/1a8b99f7f5gggq7fe7cv.JPG) 2.2. 「一個檔案」選項 ------------- ![所有文字](https://thepracticaldev.s3.amazonaws.com/i/cuq5tm4xsjnngoi6uqmc.JPG) 當選擇“One File”選項時,“Auto PY to EXE”將建立一個包含所有依賴項但**不包含媒體檔案的.exe 檔案**。如果您的程式只有**預設的 Windows GUI** ,沒有圖示、背景、媒體文件,或者您可以將媒體資料夾放在 .exe 文件附近,請隨意跳過以下說明。對於那些想要將媒體檔案打包到 .exe 檔案本身的人,請閱讀第 3 段。 3. 選擇其他文件 --------- 「Auto PY to EXE」中有一個名為「Additional Files」的選單,可讓您新增您選擇的檔案。但有一個問題。 「Auto PY to EXE」使用**pyinstaller**將資料解壓縮到臨時資料夾中,並將該目錄路徑儲存在 \_MEIPASS 環境變數中。您的專案將找不到必要的文件,因為路徑已更改,也不會看到新路徑。換句話說,如果選擇「一個檔案」選項,則在「其他檔案」功能表中選擇的檔案**將不會新增**到 .exe 檔案中。要解決此問題,您應該使用Auto PY to EXE 開發人員提供的程式碼\[此處\](https://nitratine.net/blog/post/issues-when-using-auto-py-to-exe/#debugging ) ``` def resource_path(relative_path): ``` ``` """ Get absolute path to resource, works for dev and for PyInstaller """ ``` ``` try: ``` ``` # PyInstaller creates a temp folder and stores path in _MEIPASS ``` ``` base_path = sys._MEIPASS ``` ``` except Exception: ``` ``` base_path = os.path.abspath(".") ``` ``` return os.path.join(base_path, relative_path) ``` 要在您的專案中使用此程式碼,請替換您*現在*擁有的媒體檔案的連結 例如: ``` setWindowIcon(QIcon('media\icons\logo.png')) ``` *和* ``` setWindowIcon(QIcon(resource_path('logo.png')) ``` 現在連結將被正確引用,並且所選檔案已成功打包到 .exe 檔案中。 用於比較: 之前可能有連結 ``` "C:\Users\User\PycharmProjects\media\icons\logo.png" ``` 之後可能有連結 ``` "C:\Users\User\AppData\Local\Temp\\_MEI34121\logo.png" ``` 按下**“轉換 .PY 至 .EXE”** ![所有文字](https://warehouse-camo.cmh1.psfhosted.org/d2f89e7dfcbbd3635e0f098b43dbc9df7c74b7a4/68747470733a2f2f692e696d6775722e636f6d2f663354456e5a492e706e67) 等待 ![所有文字](https://warehouse-camo.cmh1.psfhosted.org/a71bb45213b2285ac68eedc2994709c478deb12d/68747470733a2f2f692e696d6775722e636f6d2f4d6a644f4e63432e706e67) 步驟 3. 執行您的程式! ------------- 現在一切都完成了! 執行。測試一下。看看發生了什麼事。 確保一切正常。 #### 您建立了一個目錄 您需要的每個檔案都應該位於**單一目錄**中。 #### 你製作了一個文件 這樣你應該有**一個 .exe 檔**。如果您有需要並且正確完成,您的 .exe 檔案將包含其中的所有媒體。**您不需要任何帶有 .exe 檔案的媒體檔案/資料夾**即可正確顯示它們。 --- ### 聚苯乙烯 如果您對應加入哪些重要資訊有任何回饋或建議,請隨時告訴我! 本指南並未描述以各種可能的方式完成的每個可能的選項。 我希望您發現這些資訊有用! 祝您的專案順利! --- 原文出處:https://dev.to/eshleron/how-to-convert-py-to-exe-step-by-step-guide-3cfi

😻建立您自己的 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

我建立了一個 AI PowerPoint 產生器 - 方法如下:(Next.js、OpenAI、CopilotKit)

長話短說 ==== 在本文中,您將學習如何使用 Nextjs、CopilotKit 和 OpenAI 建立人工智慧驅動的 PowerPoint 應用程式。我們將涵蓋: - 利用 ChatGPT 建立您的 PowerPoint 簡報📊 - 與您的 PowerPoint 簡報聊天💬 - 將音訊和圖像新增至您的 PowerPoint 簡報🔉 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zkbn3i2vw59na8yn2gm0.gif) --- CopilotKit:建構深度整合的應用內人工智慧聊天機器人💬 ------------------------------- CopilotKit 是[開源人工智慧副駕駛平台。](https://github.com/CopilotKit/CopilotKit)我們可以輕鬆地將強大的人工智慧聊天機器人整合到您的 React 應用程式中。完全可定制和深度集成。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pixiay2v8raimvui28l6.gif) {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} ###### \*在布胡布上 現在回到文章。 --- **先決條件** -------- 要開始學習本教程,您需要在電腦上安裝以下軟體: - 文字編輯器(例如 Visual Studio Code) - Node.js - 套件管理器 使用 NextJS 建立 PowerPoint 應用程式前端 ------------------------------ **步驟 1:**使用下列指令 Git 複製 PowerPoint 應用程式樣板。 ``` git clone https://github.com/TheGreatBonnie/aipoweredpowerpointpresentation ``` **步驟 2:**在文字編輯器上開啟 PowerPoint 應用程式樣板,並使用下列指令安裝所有專案相依性。 ``` npm install ``` 步驟3: • 前往根目錄\*\*\*\*並建立一個名為**`.env.local`的檔案。**在該文件中,加入下面保存您的 ChatGPT API 金鑰的環境變數。 ``` OPENAI_API_KEY="Your ChatGPT API Key” ``` **步驟4:**在命令列執行命令*npm run dev* 。導航至 http://localhost:3000/,您應該會看到 PowerPoint 應用程式前端。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kom1urw8ggeevz2dspk8.png) 建立 PowerPoint 投影片功能 ------------------- 步驟 1:前往**`/[root]/src/app/components`** ,並建立一個名為`present.tsx`的檔案。然後在文件頂部導入以下相依性。 ``` "use client"; import { useCopilotContext } from "@copilotkit/react-core"; import { CopilotTask } from "@copilotkit/react-core"; import { useMakeCopilotActionable, useMakeCopilotReadable, } from "@copilotkit/react-core"; import { useEffect, useState } from "react"; import "./../presentation/styles.css"; import Markdown from "react-markdown"; ``` 步驟 2:定義一個名為 Slide 的 TypeScript 接口,其中包含 PowerPoint 簡報投影片的標題和內容屬性。 ``` // Define slide interface interface Slide { title: string; content: string; } ``` 步驟 3:建立一個名為`Presentation`函數,並使用usestate 初始化名為`allSlides`和`currentSlideIndex`狀態變數`usestate.`變數`allSlides`將保存幻燈片陣列,而`currentSlideIndex`將保存目前幻燈片索引。 ``` export function Presentation (){ const [allSlides, setAllSlides] = useState<Slide[]>([]); const [currentSlideIndex, setCurrentSlideIndex] = useState<number>(0); } ``` 步驟 4:在`Presentation`函數中,使用`useMakeCopilotReadable`掛鉤新增投影片的`allSlides`陣列作為應用程式內聊天機器人的上下文。 ``` useMakeCopilotReadable("Powerpoint presentation slides: " + JSON.stringify(allSlides)); ``` 步驟 5:使用`useMakeCopilotActionable`掛鉤設定一個名為`createNewPowerPointSlide`操作,其中包含描述和更新`allSlides`和`currentSlideIndex`狀態變數的實作函數,如下所示。 ``` useMakeCopilotActionable( { name: "createNewPowerPointSlide", description: "create slides for a powerpoint presentation. Call this function multiple times to present multiple slides.", argumentAnnotations: [ { name: "slideTitle", type: "string", description: "The topic to display in the presentation slide. Use simple markdown to outline your speech, like a headline.", required: true, }, { name: "content", type: "string", description: "The content to display in the presentation slide. Use simple markdown to outline your speech, like lists, paragraphs, etc.", required: true }, ], implementation: async (newSlideTitle, newSlideContent) => { const newSlide: Slide = { title: newSlideTitle, content: newSlideContent}; const updatedSlides = [...allSlides, newSlide]; setAllSlides(updatedSlides); setCurrentSlideIndex(updatedSlides.length - 1); }, }, [], ); ``` 步驟6:定義一個名為`displayCurrentSlide`的函數,用於在前端顯示目前投影片索引。 ``` // Display current slide const displayCurrentSlide = () => { const slide = allSlides[currentSlideIndex]; return slide ? ( <div className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center" style={{ textShadow: "1px 1px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000", }} > <Markdown className="markdown">{slide.title}</Markdown> <Markdown className="markdown">{slide.content}</Markdown> </div> ) : ( <div className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center"> No Slide To Display </div> ); }; ``` 步驟 7: 定義一個名為 addSlide 的函數,該函數包含一個名為 CopilotTask 的類別。 CopilotTask 類別定義新增投影片的功能。 ``` // Add new slide function const addSlide = new CopilotTask({ instructions: "create a new slide", actions: [ { name: "newSlide", description: "Make a new slide related to the current topic.", argumentAnnotations: [ { name: "title", type: "string", description: "The title to display in the presentation slide.", required: true, }, { name: "content", type: "string", description: "The title to display in the presentation slide.", required: true, }, ], implementation: async (newSlideTitle,newSlideContent,) => { const newSlide: Slide = {title: newSlideTitle,content: newSlideContent,}; const updatedSlides = [...allSlides, newSlide]; setAllSlides(updatedSlides); setCurrentSlideIndex(updatedSlides.length - 1); }, }, ], }); const context = useCopilotContext(); const [randomSlideTaskRunning, setRandomSlideTaskRunning] = useState(false); ``` 步驟 8:定義兩個函數 goBack 和 goForward。 goBack 函數定義導覽到上一張投影片的功能,而 goForward 函數定義導覽到下一張投影片的功能。 ``` // Button click handlers for navigation const goBack = () => setCurrentSlideIndex((prev) => Math.max(0, prev - 1)); const goForward = () => setCurrentSlideIndex((prev) => Math.min(allSlides.length - 1, prev + 1)); ``` 步驟9:傳回一個呼叫displayCurrentSlide函數的元件,並包含呼叫addSlide、goBack和goForward函數的按鈕。 ``` return ( <div> {displayCurrentSlide()} <button disabled={randomSlideTaskRunning} className={`absolute bottom-12 left-0 mb-4 ml-4 bg-blue-500 text-white font-bold py-2 px-4 rounded ${randomSlideTaskRunning ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-700"}`} onClick={async () => { try { setRandomSlideTaskRunning(true); await addSlide.run(context); } finally { setRandomSlideTaskRunning(false); } }} > {randomSlideTaskRunning ? "Loading slide..." : "Add Slide +"} </button> <button className={`absolute bottom-0 left-0 mb-4 ml-4 bg-blue-500 text-white font-bold py-2 px-4 rounded ${randomSlideTaskRunning ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-700"}`} onClick={goBack}>Prev</button> <button className={`absolute bottom-0 left-20 mb-4 ml-4 bg-blue-500 text-white font-bold py-2 px-4 rounded ${randomSlideTaskRunning ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-700"}`} onClick={goForward}>Next</button> </div> ); ``` 步驟10:在Presentation資料夾中,將以下程式碼加入page.tsx檔案。 ``` "use client"; import { CopilotKit } from "@copilotkit/react-core"; import { CopilotSidebar } from "@copilotkit/react-ui"; import {Presentation} from "../components/present"; import "./styles.css"; let globalAudio: any = undefined; let globalAudioEnabled = false; const Demo = () => { return ( <CopilotKit url="/api/copilotkit/openai"> <CopilotSidebar defaultOpen={true} labels={{ title: "Presentation Copilot", initial: "Hi you! 👋 I can give you a presentation on any topic.", }} clickOutsideToClose={false} onSubmitMessage={async (message) => { if (!globalAudioEnabled) { globalAudio.play(); globalAudio.pause(); } globalAudioEnabled = true; }} > <Presentation/> </CopilotSidebar> </CopilotKit> ); }; export default Demo; ``` 步驟11:導覽至http://localhost:3000/,點擊「開始」按鈕,您將被重定向到與聊天機器人整合的演示頁面,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a74ilgzf5ep6snbli7uh.png) 步驟12:給右側的聊天機器人一個提示,例如「在TypeScript上建立PowerPoint簡報」聊天機器人將開始產生回應,完成後,它將在頁面左側顯示產生的PowerPoint投影片,如下圖所示 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lxhkvltf33uwyvrt4a8a.png) 步驟 13:關閉聊天機器人窗口,然後按一下新增投影片 + 按鈕將新投影片新增至 PowerPoint 簡報中,如下所示。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxl59gxkt02pmyadxzuk.png) 第 14 步:按一下「上一張」按鈕,您將導覽至上一張投影片。如果您按一下「下一步」按鈕,您將導覽至下一張投影片。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/expdwslfo2o49x7y6a6p.png) 建立 PowerPoint 投影片 自動語音功能 ------------------------ 步驟1:在`present.tsx`檔案中,宣告一個名為`globalAudio`的變數,如下所示。 ``` let globalAudio: any = undefined; ``` 步驟2:在`Presentation`元件中,宣告一個`useEffect`鉤子,用一個新的**`Audio`**物件初始化**`globalAudio`** ,如下所示。 ``` useEffect(() => { if (!globalAudio) { globalAudio = new Audio(); } }, []); ``` 步驟 3:更新 useMakeCopilotActionable 掛鉤,透過 API 將 PowerPoint 幻燈片文字轉換為語音,如下所示。 ``` useMakeCopilotActionable( { name: "createNewPowerPointSlide", description: "create slides for a powerpoint presentation. Call this function multiple times to present multiple slides.", argumentAnnotations: [ { name: "slideTitle", type: "string", description: "The topic to display in the presentation slide. Use simple markdown to outline your speech, like a headline.", required: true, }, { name: "content", type: "string", description: "The content to display in the presentation slide. Use simple markdown to outline your speech, like lists, paragraphs, etc.", required: true }, { name: "speech", type: "string", description: "An informative speech about the current slide.", required: true, }, ], implementation: async (newSlideTitle, newSlideContent, speech) => { const newSlide: Slide = { title: newSlideTitle, content: newSlideContent }; const updatedSlides = [...allSlides, newSlide]; setAllSlides(updatedSlides); setCurrentSlideIndex(updatedSlides.length - 1); const encodedText = encodeURIComponent(speech); const url = `/api/tts?text=${encodedText}`; globalAudio.src = url; await globalAudio.play(); await new Promise<void>((resolve) => { globalAudio.onended = function () { resolve(); }; }); await new Promise((resolve) => setTimeout(resolve, 500)); }, }, [], ); ``` 步驟 4:更新 addSlide 函數,透過 API 將新的 PowerPoint 投影片文字轉換為語音,如下所示。 ``` // Add new slide function const addSlide = new CopilotTask({ instructions: "create a new slide", actions: [ { name: "newSlide", description: "Make a new slide related to the current topic.", argumentAnnotations: [ { name: "title", type: "string", description:"The title to display in the presentation slide.", required: true, }, { name: "content", type: "string", description:"The title to display in the presentation slide.", required: true, }, { name: "speech", type: "string", description: "An informative speech about the current slide.", required: true, }, ], implementation: async (newSlideTitle, newSlideContent, speech) => { const newSlide: Slide = { title: newSlideTitle, content: newSlideContent }; const updatedSlides = [...allSlides, newSlide]; setAllSlides(updatedSlides); setCurrentSlideIndex(updatedSlides.length - 1); const encodedText = encodeURIComponent(speech); const url = `/api/tts?text=${encodedText}`; globalAudio.src = url; await globalAudio.play(); await new Promise<void>((resolve) => { globalAudio.onended = function () { resolve(); }; }); await new Promise((resolve) => setTimeout(resolve, 500)); }, } ] }); ``` 步驟 5: 再次向聊天機器人發出「在 TypeScript 上建立 PowerPoint 簡報」提示,您應該會聽到簡報投影片的聲音。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iu6s1c4q5foto1xe919a.png) 建立圖像生成功能 -------- 步驟1:在present.tsx檔案中,新增一個名為backgroundImage的新屬性來鍵入介面Slide,如下所示。 ``` // Define slide interface interface Slide { title: string; content: string; backgroundImage: string; } ``` 步驟 2:更新 useMakeCopilotActionable 掛鉤以產生 PowerPoint 簡報投影片的圖片。 ``` useMakeCopilotActionable( { name: "createPowerPointSlides", description: "create slides for a powerpoint presentation. Call this function multiple times to present multiple slides.", argumentAnnotations: [ { name: "slideTitle", type: "string", description: "The topic to display in the presentation slide. Use simple markdown to outline your speech, like a headline.", required: true, }, { name: "content", type: "string", description: "The content to display in the presentation slide. Use simple markdown to outline your speech, like lists, paragraphs, etc.", required: true }, { name: "backgroundImage", type: "string", description: "What to display in the background of the slide (i.e. 'dog' or 'house').", required: true, }, { name: "speech", type: "string", description: "An informative speech about the current slide.", required: true, }, ], implementation: async (newSlideTitle, newSlideContent, newSlideBackgroundImage, speech) => { const newSlide: Slide = { title: newSlideTitle, content: newSlideContent, backgroundImage: newSlideBackgroundImage }; const updatedSlides = [...allSlides, newSlide]; setAllSlides(updatedSlides); setCurrentSlideIndex(updatedSlides.length - 1); const encodedText = encodeURIComponent(speech); const url = `/api/tts?text=${encodedText}`; globalAudio.src = url; await globalAudio.play(); await new Promise<void>((resolve) => { globalAudio.onended = function () { resolve(); }; }); await new Promise((resolve) => setTimeout(resolve, 500)); }, }, [], ); ``` 步驟 2:更新 addSlide 函數以產生新的 PowerPoint 簡報投影片的圖片。 **步驟3:**更新`slide.tsx`檔案中的`Slide`元件以透過[`unsplash.com`](http://unsplash.com/)產生映像 ``` // Add new slide function const addSlide = new CopilotTask({ instructions: "create a new slide", functions: [ { name: "newSlide", description: "Make a new slide related to the current topic.", argumentAnnotations: [ { name: "title", type: "string", description:"The title to display in the presentation slide.", required: true, }, { name: "content", type: "string", description:"The title to display in the presentation slide.", required: true, }, { name: "backgroundImage", type: "string", description: "What to display in the background of the slide (i.e. 'dog' or 'house').", required: true, }, { name: "speech", type: "string", description: "An informative speech about the current slide.", required: true, }, ], implementation: async (newSlideTitle, newSlideContent, newSlideBackgroundImage, speech) => { const newSlide: Slide = { title: newSlideTitle, content: newSlideContent, backgroundImage: newSlideBackgroundImage }; const updatedSlides = [...allSlides, newSlide]; setAllSlides(updatedSlides); setCurrentSlideIndex(updatedSlides.length - 1); const encodedText = encodeURIComponent(speech); const url = `/api/tts?text=${encodedText}`; globalAudio.src = url; await globalAudio.play(); await new Promise<void>((resolve) => { globalAudio.onended = function () { resolve(); }; }); await new Promise((resolve) => setTimeout(resolve, 500)); }, } ] }); ``` 步驟 3:更新 displayCurrentSlide 函數以將背景圖像新增至 PowerPoint 簡報投影片中。 ``` // Display current slide const displayCurrentSlide = () => { const slide = allSlides[currentSlideIndex]; return slide ? ( <div className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center" style={{ backgroundImage: 'url("https://source.unsplash.com/featured/?' + encodeURIComponent(allSlides[currentSlideIndex].backgroundImage) + '")', textShadow: "1px 1px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000", }} > <Markdown className="markdown">{slide.title}</Markdown> <Markdown className="markdown">{slide.content}</Markdown> </div> ) : ( <div className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center"> No Slide To Display </div> ); }; ``` **步驟 4:**前往 Web 應用程式,您應該會看到背景圖像已新增至 PowerPoint 投影片中。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1zgcgn1h6c5hz8dh7m9a.png) 結論 -- 總而言之,您可以使用 CopilotKit 建立應用內 AI 聊天機器人,該機器人可以查看當前應用程式狀態並在應用程式內執行操作。 AI 聊天機器人可以與您的應用程式前端、後端和第三方服務對話。 筆記: - 告訴聊天機器人要寫什麼 - 建立包含文字、圖片和自動語音的幻燈片。 這是全部實作程式碼: https://github.com/CopilotKit/CopilotKit/blob/mme/tools/CopilotKit/examples/next-openai/src/app/helloworld/page.tsx 你可以拿程式碼寫文章,一定要截圖。 確保按照邏輯實現的順序寫文章: - 首先,外部 React 元件( `page.tsx`中的`HelloWorld`元件) ``` - cover `CopilotKit` and `CopliotSidebar` ``` - 然後覆蓋`Presentation`反應元件而不加入 Copilot 功能 ``` - include the `Slide` react component ``` - 最後,在建立基本的 React 應用程式後,加入描述 Copilot 特定功能的部分( `useMakeCopilotReadable`和`useMakeCopilotActionable` ) - 最後,介紹生成音訊+影像的函數。保持描述非常簡短,只需說“我們透過瀏覽器audio-gen API產生音訊”和“我們透過[`unsplash.com`](http://unsplash.com/)產生圖像” 執行演示: - 請參閱文件/貢獻指南,以了解如何執行 CopilotKit 儲存庫中包含的範例應用程式:https://docs.copilotkit.ai/contribute/quickstart-contribute - 執行 - 前往`/helloworld`頁面 --- 結論 -- 總而言之,您可以使用 CopilotKit 建立應用內 AI 聊天機器人,該機器人可以查看當前應用程式狀態並在應用程式內執行操作。 AI 聊天機器人可以與您的應用程式前端、後端和第三方服務對話。 對於完整的源程式碼: https://github.com/TheGreatBonnie/aipoweredpresentation 感謝@theGreatBonnie 在本文中所做的出色工作。 別忘了... ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pixiay2v8raimvui28l6.gif) {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} --- 原文出處:https://dev.to/copilotkit/how-to-build-ai-powered-powerpoint-app-nextjs-openai-copilotkit-ji2

初級開發者需要聽到的 10 個「殘酷事實」🗯🙉

嗨,我是文斯 ------ 大家好,我是[Vince](https://twitter.com/hot_town) ,一位全球教育家轉型為 Web 開發人員。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zasstfygajj6s5w034xt.png) 上圖中間的就是我,當時我在肯亞北部從事農業教育計畫。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1enks693w0of9r2fzqhd.png) 這些天,我正在建立業餘專案(如上圖所示的[Open SaaS)](https://opensaas.sh) ,並擔任開發人員關係工程師。 提升你的開發生涯 -------- 我必須承認,我即將向您呈現的「10個殘酷事實」不一定是事實,而是我在轉行過程中形成的觀點。我想我的獨特視角可能對有抱負的開發人員和其他職業轉換者有一定的價值。 眾所周知,對於那些想要尋找新職業而不走傳統教育路線的人來說,軟體開發是一個可行的選擇。正因為如此,而且事實上薪水往往非常好,我認為一部分做出轉變的人可能是出於錯誤的原因。 一旦你確立了自己的初級地位,通常很難知道你應該做什麼來推進你的職業生涯。正如我和我的同事在最近的[Reddit 貼文](https://www.reddit.com/r/webdev/comments/112im2m/senior_devs_what_are_the_most_damaging/)和[後續影片](/blog/2023/02/21/junior-developer-misconceptions)中討論的那樣,那裡有很多觀點(包括我的),而後輩往往會產生很多誤解。 因此,我列出了在開始從事科技職業時應考慮的事項。 10 個殘酷的事實 --------- 1 👎**如果你只是為了錢而做,你就不會成功。**確實,你不需要學位或任何人的許可才能在這個職業中取得進步,但你需要野心和精神耐力。需要真正的興趣來維持它們。 2 🧱**盡快開始建造。**找到您感興趣的問題並自行建立解決方案。為您使用的開源專案做出貢獻。一系列獨特的作品充分說明了您的能力。另外,沒有比經驗更好的老師了。 3 💰**您無需支付樣板、訓練營或課程的費用。**事實上,你最好自己解決問題,只有在真正陷入困境時才尋求幫助。那裡有大量的免費資源,當您在工作時,這些可能是唯一可以幫助您的東西。 --- 說到樣板,我們剛剛發布了[Open SaaS](https://opensaas.sh) ,這是一個完全免費、開源、功能豐富的 React + NodeJS SaaS 模板,可幫助您快速輕鬆地啟動 SaaS 應用程式。 [![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sf1fhsgwuurkre9a7drq.png)](https://opensaas.sh) 如果您對此有疑問、需要幫助、反饋或靈感,請跳入[Discord 伺服器](https://discord.gg/zKFDFrsHa9)並介紹自己。 --- 4 😎**你不必跟隨潮流。跟隨你感興趣的。**正如我之前所說,從事這份工作需要有心理承受能力。追隨你的興趣會讓你保持專注並有助於避免倦怠。 5 👩‍💻**您不需要對一項技術瞭如指掌,這**與一些開發人員可能希望您相信的相反。事實是,你一直在學習,你的知識中總是會存在差距。重要的是您對能夠填補這些空白的信心。 6 😱**無所畏懼並尋求回饋。**把你的作品放在那裡,並準備好接受批評。如果你能忍受它,你就會成為一個更好的開發者。 7 🧐**你應該對自己在做什麼有深刻的體會。**不要只是複製貼上別人的答案(或 GPT 的答案)來解決您的問題,然後就到此為止。質疑事物為何有效,自己找出答案。 8 🏋️‍♀️**不幸的是,你必須做繁重的工作。不要一開始就期望高薪。**而且您可能希望透過在空閒時間從事業餘專案來改進您的作品集,或者您可能會比您希望的時間更長時間地擔任初級開發人員。 9 🧗‍♂️**挑戰自我。但不要太多。**如果你不尋求挑戰,你就不會進步。但如果你承擔的任務遠遠超出你目前的能力,你就會受苦。找到最佳位置,處理那些讓你感覺有點不舒服的事情,但你仍然可以集中註意力。堅持下去,一年後你會對自己所取得的成就感到驚訝。 10 🗣**程式設計絕對不是您需要的唯一技能。**尊重他人、善於溝通、認真負責、雄心勃勃和謙遜將使您處於不同的聯盟,並使您成為任何技術團隊中的寶貴資產。 現在開始工作吧! -------- 這就是我的總結。 對於這10個“真相”,你有何看法?我錯過了什麼?我是不是已經完全飽了💩?!請在下面的評論中告訴我們。 --- 原文出處:https://dev.to/wasp/10-hard-truths-junior-developers-need-to-hear-3j0e

我們透過 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

只需 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

2024 年適合您的資料科學簡歷的 Python 庫

**長話短說** -------- 到 2024 年,Python 仍然是資料科學的主要語言,因為它簡單,而且還擁有用於資料清理、特徵工程、視覺化和機器學習的各種函式庫。 如果您想開始或將您的職業生涯轉向更加以資料科學為導向的方向,此列表將為您提供您需要了解的庫。 ![動圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wkuszl36ow451qqonbc5.gif) --- 1-太皮 ---- **領域:全面應用** ![類型](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j6z61hrjtov7vjymjt5d.png) Taipy 旨在加快應用程式開發,從最初的原型到生產就緒的應用程式。 這個開源 Python 函式庫專為輕鬆開發前端 (GUI) 和 ML/資料管道而設計。 它程式碼量低,專為任何 pythonista 設計。 主要特徵: - 邁向資料科學:筆記本相容並與機器學習平台(Dataiku、Databricks 等......)輕鬆集成 - Taipy 隨著應用程式用戶的增加而擴展 - Taipy 適用於大型資料集 - 非同步模式:非常適合處理高負載應用程式 ![皇后樂團 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0un08vhstrk6zpst5yti.gif) {% cta https://github.com/Avaiga/taipy %} Star ⭐ Taipy 儲存庫 {% endcta %} 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- 2-Matplotlib ------------ **領域:資料視覺化** ![隨著](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mspnyvvpbi9vk5qw9dp1.png) Matplotlib 是最著名的視覺化小工具庫。 借助該庫,您可以利用其廣泛的圖表和自訂功能輕鬆繪製任何 2D 圖形。 一個很棒的庫,可以透過簡單快速的圖表檢查模型的效能。 {% cta https://github.com/matplotlib/matplotlib %} Star ⭐ 儲存庫 {% endcta %} --- 3- 熊貓 ----- **領域:資料處理與分析** ![貓熊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2xnkvuwpwzok4o1zpci.png) 如何在不了解 Pandas 的情況下使用 Python 進行編碼?熊貓是Python皇室! 該庫的兩個資料結構是: - 資料框 - 系列 該庫允許快速且有效率地載入、清理和準備資料。 主要功能包括: - 載入資料中 - 重塑資料框 - 基礎統計 {% cta https://github.com/pandas-dev/pandas %} Star ⭐ 儲存庫 {% endcta %} --- 4-Numpy ------- **領域:數值計算** ![麻木](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjpcse69no86muy2lpd9.png) Numpy 不如 Pandas 通用,但它是科學計算和資料預處理的重要工具。 使用 Numpy 時,您將熟悉陣列並知道如何有效地進行資料操作和數學函數。 這個庫對於您的資料科學專案絕對是必不可少的。 {% cta https://github.com/numpy/numpy %} Star ⭐ 儲存庫 {% endcta %} --- 5-Scikit-學習 ----------- **領域:機器學習** ![學習](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9a14zmbtz9xx9wwgx4ck.png) 另一個 Python 函式庫,這一次,您在 Python 中進行機器學習的首選。 該庫有多種演算法: - K-均值聚類 - 回歸 - 分類 但它還透過例如資料分割和降維技術來設定您的機器學習專案。 {% cta https://github.com/scikit-learn/scikit-learn %} Star ⭐ 儲存庫 {% endcta %} --- 6-西伯恩 ----- **領域:統計資料視覺化** ![西博恩](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afzvf6tgmbp3v90p0res.png) Seaborn 將為 Matplotlib 帶來一些附加功能。 當 Matplotlib 強調精確性和簡單性時,該程式庫帶來了複雜且有吸引力的視覺化效果。 {% cta https://github.com/mwaskom/seaborn %} Star ⭐ 儲存庫 {% endcta %} --- 7-TensorFlow 或 Pytorch ---------------------- **領域:深度學習** ![深度學習](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3yn7zvjiut485x5ni4o.png) Pytorch 還是 TensorFlow 這就是問題所在。 這兩個庫提供了神經網路的介面。 它們非常靈活,可為您提供高效的 API 來建立和建立神經網路模型。 選擇取決於您,但這裡有一些區別: - PyTorch 具有更自然語言處理的角度 - Pytorch 更具 Python 風格 {% cta https://github.com/tensorflow/tensorflow %} Star ⭐ TensorFlow 儲存庫 {% endcta %} {% cta https://github.com/pytorch/pytorch %} Star ⭐ PyTorch 儲存庫 {% endcta %} --- 8-硬 --- **領域:深度學習** ![難的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51dvps6qkwilxfttge85.png) Keras 是開始深度學習的好方法,因為它在 TensorFlow 之上執行,但實作過程得到簡化。 {% cta https://github.com/keras-team/keras %} Star ⭐ 儲存庫 {% endcta %} --- 9-狀態模型 ------ **領域:統計建模** ![統計資料](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hzzy1arx88hr6404r79j.png) 該庫有一系列統計模型。 它是機器學習專案探索性資料分析階段的絕佳工具。 一系列功能涵蓋從描述性分析到統計測試;它也是一個適合處理時間序列資料、單變數和多元統計等的函式庫。 {% cta https://github.com/statsmodels/statsmodels %} Star ⭐ 儲存庫 {% endcta %} --- 10-極地 ----- **領域:快速資料操作** ![極性](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/psrc89710z73zechouya.png) Polars 是一個為處理大型資料集而建立的 DataFrame 函式庫。 它的靈感來自 Python 的頂級庫 - Pandas,但進行了(快速)調整,速度提高了 10 到 100 倍。處理大型資料集時必須了解的工具。 {% cta https://github.com/pola-rs/polars %} Star ⭐ 儲存庫 {% endcta %} --- 結論 -- 這十個函式庫對於任何機器學習專案都是必不可少的,掌握它們將增強您的資料科學履歷。 請隨時評論您最喜歡的 ML/AI 庫! --- 原文出處:https://dev.to/taipy/python-libraries-for-your-datascience-cv-in-2024-5cl7

再見電子。你好金牛座!

利用 Rust 支援的後端框架與 React 前端相結合,提供出色的無瀏覽器體驗 ---------------------------------------- ![最初發佈於 Medium](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjac58ufbb26esj569wa.png) 許多開發人員都可以告訴您他們對 JavaScript GUI 框架又愛又恨的關係,該框架幫助徹底改變了許多桌面應用程式的製作方式。事實上,我們今天使用的許多應用程式,無論是與開發、社交媒體、通信……凡是有關的應用程式,都是使用 Electron 框架建置的。 如果您好奇,請從其[網站](https://www.electronjs.org/apps)查看使用 Electron 的應用程式的精選清單。 --- 關鍵是,Electron 為具有 Web 開發經驗的開發人員提供了為多個平台建立獨立桌面應用程式的機會…所有這些都無需學習任何新的程式語言!它提供了使用我們許多人一直使用的相同 JavaScript、CSS 和 HTML 的能力,這當然是非常棒的! 簡單總結一下 Electron 是如何做到這一點的: > Electron 是一個使用 JavaScript、HTML 和 CSS 建立桌面應用程式的框架。透過將 Chromium 和 Node.js 嵌入到其二進位檔案中,Electron 允許您維護一個 JavaScript 程式碼庫並建立可在 Windows、macOS 和 Linux 上執行的跨平台應用程式 - 無需本地開發經驗。 --- ![用電子建置](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o0sy6qchjuwm028t080p.png) --- 使用 Electron 建立桌面應用程式的最大缺點之一,正如你們中的一些人可能在 Stack Overflow 和其他論壇中看到的那樣…生成的二進位檔案往往非常大!如此之大,即使只是一個中等大小的程式碼庫也可能產生約 60MB 的最終二進位。 在親身經歷了這種挫敗感之後,我開始想知道是否有一個神奇的解決方案可以解決這個問題……事實證明, **Rust 恰好提供了一個!** --- ![巨大差距](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkpvcpzi3wz10ewunbg2.png) --- > Tauri 是一個工具包,可協助開發人員使用幾乎任何現有的前端框架為主要桌面平台開發應用程式。核心是用 Rust 建構的,CLI 利用 Node.js,使 Tauri 成為一種真正的多語言方法來建立和維護出色的應用程式。 ### 潛入 令我興奮的是,他們的命令列鷹架工具建立了使用熟悉的前端框架啟動和執行所需的所有 Rust 檔案。不僅如此,一旦我準備好開始將自己的功能加入到後端以供 UI 使用,Tauri 就可以讓一切工作變得相當無縫! --- ![快速開始](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rnu0x8rtnvn5eq92272j.png) --- 我決定嘗試讓 Tauri 為我計劃參與的一個社區專案建立一個新的桌面儀表板應用程式,劇透一下……**它並沒有讓人失望!** 正如我之前提到的,入門相當簡單: - 確保您的系統已安裝 Rust - 如果在 Windows 或 Linux 上,請確保安裝相關相依性 - 執行一個簡單的命令來設定您的專案 之後,問題是將前端原始檔全部放在一起,同時當我需要一些有關 UI 和後端之間的進程間通訊的指導時,偶爾會參考 Tauri 的文件。 --- {% 嵌入 https://gist.github.com/dedSyn4ps3/5703367578339fc8c3440ea8a09fa449 %} --- 使用 Tauri 建立儀表板的美妙之處在於,我不再需要為了能夠正確利用進程間通訊而建立單獨的`preload.js`檔案。 所需要的只是在我想要從 UI 呼叫的函數上方的`main.rs`中進行正確的註釋,以及在我的 React `jsx`檔案中加入一個簡單的導入行: `import { invoke } from '@tauri-apps/api/tauri'` 最終,Tauri 建置的應用程式的強大之處在於其後端使用 Rust。這使得像我這樣的開發人員能夠將他們的最終產品建置成本地執行的二進位文件,其大小只是許多 Electron 建置的應用程式的一小部分。 ### 結論 至少對我來說,很明顯,Tauri 肯定有潛力繼續發展,直至推翻 Electron 作為主導的「前端」GUI 框架。儘管由於是基於 Rust 建置的,可能會存在一些令人生畏的因素,但了解其內部結構所需的少量時間是非常值得的! --- ![最後結果](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grj3o7g3hhbndota5fgn.png) --- 我鼓勵任何想要開始前端 GUI 開發之旅的人檢查 Tauri 框架,並抵制立即將 Electron 作為直接解決方案的衝動……我向你保證,你會感到驚訝! 為了完整起見,您可以在我的 Gitlab 上找到我的社群專案的完整程式碼庫。如果您正在為自己的專案尋找任何想法,請檢查一下! {% 嵌入 https://gitlab.com/dedSyn4ps3/enviroplus-desktop %} {% 嵌入 https://dev.to/dedsyn4ps3 %} {% cta https://github.com/dedsyn4ps3 %} 💻 也查看我的 Github!{% endcta %} --- 原文出處:https://dev.to/dedsyn4ps3/goodbye-electron-hello-tauri-26d5

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

為 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 卡通 發表:真實 描述:comiCSS 本週兩歲了。為了慶祝,我出版了每日漫畫,為這個重要的日子做準備。這是這七部漫畫的收藏。 標籤: css,webdev,showdev 封面圖:https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sa95c4u6o8475xxwl3kz.png canonical\_url:https://alvaromontoro.com/blog/68051/css-cartoons-for-comicss-second-anniversary 發佈時間:2024-02-08 09:00 +0000 --- &lt; p&gt; [comiCSS](https://comicss.art)本週兩歲了。為了慶祝,我出版了每日漫畫,為這個重要的日子做準備。這是這七部漫畫的收藏。 &lt; p&gt; comiCSS 是一部關於 CSS 編碼的 CSS 漫畫。是的,**漫畫和卡通都是用 HTML 和 CSS 編碼的**(有幾個 SVG 例外,它們也在內部使用 CSS)。是的,我已經這樣做兩年了。為什麼?因為它很有趣,所以它們可能很愚蠢,但是,希望它們也具有教育意義(有些比其他的更有教育意義)……因為,為什麼不呢? &lt; p&gt; 這是我本週製作的漫畫集。我希望你喜歡他們。 &lt; h2 id =「雲端開發人員」&gt; [雲端開發者](https://comicss.art/?id=116) &lt; p&gt; ![一個人使用電腦的卡通,背景中有云,旁邊是一個有以下 CSS 程式碼的方塊:.cloud-developer { background: azure;隔離的英文休息:無;壓力:100;內容:無; }](https://alvaromontoro.com/images/blog/comicss-series-cloud-developer.png) 有趣的事實:這部動畫片中的背景顏色是真正的「天藍色」。 --- &lt; h2 id="國王"&gt; [國王](https://comicss.art/?id=117) &lt; p&gt; ![一個留著鬍子、頭戴王冠、手持權杖的男人的卡通畫,旁邊是一個帶有以下 CSS 程式碼的框: .king {position:absolute;豐富度:100;顏色:寶藍色; :first-child { 所有:繼承; } }](https://alvaromontoro.com/images/blog/comicss-series-king.png) 有趣的事實:國王的長袍是「寶藍色」的。這部漫畫是該系列所有漫畫中在社群媒體上最成功的一部。 --- &lt; h2 id="歌劇魅影"&gt; [歌劇魅影](https://comicss.art/?id=118) &lt; p&gt; ![歌劇魅影的卡通(一個披著斗篷、戴著面具遮住臉的男人)手拿一朵玫瑰,旁邊有以下 CSS 程式碼:#phantom-of-the-opera { mask:url(#face);背面可見性:隱藏;可見性:隱藏;音高:低;音量:柔和; }](https://alvaromontoro.com/images/blog/comicss-series-phantom-of-the-opera.png) 我喜歡這個想法,但實施需要更充分。我仍然認為它有潛力...也許改天我可以改進... --- &lt; h2 id =「獲勝者」&gt; [優勝者](https://comicss.art/?id=119) &lt; p&gt; ![卡通畫中,一個人舉起手臂舉起獎杯,而五彩紙屑落在他們周圍。場景旁邊有以下 CSS 程式碼:#winner { order: 1;跑步:第一;顏色: 金色; &::after { 內容: '獎盃'; } }](https://alvaromontoro.com/images/blog/comicss-series-winner.png) [有人建議](https://front-end.social/@[email protected]/111877220149537836)關於[ABBA 的《勝者為王》,](https://www.youtube.com/watch?v=92cwKCU8Z5c)內容應該是「全部」……而我討厭我自己沒有考慮到這一點。儘管如此,我還是保留了獎盃。 --- &lt; h2 id="獨裁者"&gt; [獨裁者](https://comicss.art/?id=120) &lt; p&gt; ![獨裁者:一個穿著軍裝、戴著獎章、戴著太陽眼鏡的簡約卡通人物,旁邊是以下 CSS 程式碼: .dictator {position:fixed!important;將改變:順序!重要;不透明度:0!重要;邊框:雙實心!重要; .country:has(&) :not(.supporter) { will-change: 孤兒,寡婦!重要;翻譯:100vmax 0!重要; } }](https://alvaromontoro.com/images/blog/comicss-series-dictator.png) 這部漫畫比我以前出版的漫畫更黑暗。直到最後一刻我才懷疑是否要刪除`orphans`和`widows`的提及。 --- &lt; h2 id="籃球運動員"&gt; [籃球運動員](https://comicss.art/?id=121) &lt; p&gt; ![籃球運動員:一個人用一根手指旋轉籃球的簡約卡通畫,旁邊有以下 CSS 程式碼: .basketball-player { 海拔:更高;最小高度:75 英吋;最大高度:91 英吋;將改變:位置;玩期間: url(#game);位置:跑動(球);流:'進攻'; }](https://alvaromontoro.com/images/blog/comicss-series-basketball-player.png) 有趣的事實:NBA 有史以來最高的球員(迄今為止)是馬努特·波爾(Manute Bol),他身高7 英尺7 英寸……或91 英寸。對一個大塊頭球員來說,這只是一個小小的眨眼。 --- &lt; h2 id =「太空人」&gt; [太空人](https://comicss.art/?id=122) &lt; p&gt; ![太空人:一個穿著太空人服的人的簡約卡通,裡面有很多星星。背景。緊接著以下 CSS 程式碼: .astronaut { elevation: 上方;隔離的英文流自:太空船;流向:外太空;過渡:浮動; }](https://alvaromontoro.com/images/blog/comicss-series-astronaut.png) 我對兩個選擇器之間的懷疑: `.astronaut`和`#MajorTom` 。 CSS 可以描述[David Bowie 的 Space Oddity](https://www.youtube.com/watch?v=iYYRH4apXDo) ,但採用了更明顯的選項。 --- &lt; p&gt; 我喜歡這種風格和格式,我可能會繼續畫這樣的漫畫……但速度會放慢。除了常規的 CSS/Web 開發漫畫之外,可能每週更新一次。 &lt; p&gt; 同時,如果您喜歡這些漫畫,請存取[comiCSS](https://comicss.art)網站並**關注[Twitter](https://twitter.com/comi_CSS)或[LinkedIn](https://www.linkedin.com/company/comicss/)上的帳戶**以獲取更新。或[成為 Patreon 的支持者](https://www.patreon.com/alvaromontoro)並幫助該專案。 --- 原文出處:https://dev.to/alvaromontoro/css-cartoons-29bp

開發人員工具包:您必備的開源開發工具

每個開發人員都需要一個工具包來簡化他們的工作流程、提高生產力並有效地處理一些最複雜的任務。 這可能是開發、測試或專案管理,擁有合適的工具可以決定您的開發過程的成敗。 讓我們來看看我最喜歡的一些,我希望它們也成為您的最愛! ![在此基礎上展開](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7fvk3fph68m1z2tq48s0.gif) --- **讓我們開始吧!** 👇 1.[翼](https://github.com/winglang/wing) --------------------------------------- ![翅膀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1msmm5l13nbs7axvdyu.gif) > - 🔥 雲端程式語言 > - 🔥 將基礎架構和執行時間程式碼合併為一種語言的統一程式設計模型 {% cta https://github.com/winglang/wing %} 請star ⭐ Wing {% endcta %} --- 2.[收件匣清零](https://github.com/elie222/inbox-zero) ------------------------------------------------ ![收件匣清零](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xb7cd1kg70cq5khv88m.gif) > - 👉 幾分鐘內清理你的收件匣 > - 👉 時事通訊清理、人工智慧自動化、冷電子郵件攔截器和分析 {% cta https://github.com/elie222/inbox-zero %} 請加註星標 ⭐ 收件匣零 {% endcta %} --- 3.[紙標](https://github.com/mfts/papermark) ----------------------------------------- ![紙標](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/710dp08orz9sspoewl3a.gif) > - 🚨 開源 DocSend 替代方案 > - 🚨 透過即時分析和白標選項安全地共享推廣資料、銷售提案和其他文件 {% cta https://github.com/mfts/papermarkr %} 請加註星標 ⭐ Papermark {% endcta %} --- 4.[適體資料庫](https://github.com/aptabase/aptabase) ----------------------------------------------- ![適體資料庫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zd8q170vhr87pg3uw7hz.gif) > - 📣 應用程式分析 > - 📣 適用於您選擇的框架! (JS | NextJS 等) {% cta https://github.com/aptabase/aptabase %} 請加註星標 ⭐ SoapUI {% endcta %} --- 5.[文件](https://github.com/documenso/documenso) ---------------------------------------------- ![文件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/judhelmv2k9eaiqbj7cf.gif) > - 🚀 開源文件簽名 > - 🚀 與所有您喜愛的工具整合 - 發送、連接、接收和嵌入到任何地方 {% cta https://github.com/documenso/documenso %} 請加註星標 ⭐ Documenso {% endcta %} --- 6.[翻轉](https://github.com/flipt-io/flipt) ----------------------------------------- ![翻動](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qhgyuk513flhzxakqzq.gif) > - ⚡ 現代工程團隊的支援 GitOps 的功能管理平台。 > - ⚡ 遵循現代 DevOps 最佳實踐,例如基於主幹的開發、持續交付和軟體終止開關,而無需重新啟動應用程式。 {% cta https://github.com/flipt-io/flipt %} 請加註星標 ⭐ Flipt {% endcta %} --- 7.[開啟狀態](https://github.com/openstatusHQ/openstatus) ---------------------------------------------------- ![開放狀態](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1teukczxnb1b1mmnwvp1.gif) > **建立信任:** > - ✨ 向使用者展示您的可靠性,並減少客戶服務單的數量。 > **自訂域** > - ✨ 帶上您自己的域名,並為狀態頁面賦予個性化風格。 {% cta https://github.com/openstatusHQ/openstatus %} 請加註星標 ⭐ OpenStatus {% endcta %} --- --- 原文出處:https://dev.to/winglang/developers-toolkit-your-essential-open-source-devtools-hgc

CSS 行高的工作原理和最佳實踐

CSS 屬性`line-height`定義兩個內嵌元素之間的間距。典型用途是分隔文字。您可以看到人們將其與“前導”進行比較,“前導”是印刷術中使用的術語,指兩行文本的基線之間的空間。 `line-height`工作方式不同。它在文字上方和下方加入了空間。 ![行距與行高](https://thepracticaldev.s3.amazonaws.com/i/lsrnzx1hin6mkqg6fagw.png) 左:行距,右:行高 用法 -- 您可以使用具有不同值的`line-height`如下所示: ``` body { line-height: normal; /* default */ line-height: 2; line-height: 1em; line-height: 1rem; line-height: 200%; line-height: 20px; } ``` 噢,孩子😧!好多啊。讓我們一一分析一下👍。 ### 預設值和無單位值 如果您不將其設定為不同的值,則「正常」是預設值。通常,這意味著它設定為`1.2` ,這取決於瀏覽器供應商。那麼只有一個數字值而沒有任何單位是什麼意思呢?它實際上是一個乘數。它採用`font-size`值並將其乘以`1.2` 。讓我們用下面的例子來計算一條線的高度。 ``` body { font-size: 16px; line-height: 1.5; } ``` 我們只需要做以下計算:16 \* 1.5 = 24px。現在我們知道文字的最小高度為 24 像素。因此它將在文字下方和上方加入 4 個像素。酷就這麼簡單😎! ### em 和 rem 下一個是`em`和`rem` 。 `rem`相對於根元素的`font-size` , `em`相對於目前元素的 font-size。這是一個例子 ``` html { font-size: 12px; } .remExample { font-size: 16px; line-height: 1.5rem; /* line-height will be 12 * 1.5 = 18px */ } .emExample { font-size: 16px; line-height: 1.5em; /* line-height will be 16 * 1.5 = 24px */ } ``` ### 百分比 `%`值有點難以閱讀。 100%意味著乘以1。再次舉例來說明這一點。 ``` body { font-size: 12px; } .percentage { font-size: 16px; line-height: 150%; /* line-height will be 16 * 1.5 = 24px */ } ``` ### 像素(px) 對我來說最簡單也是最令人困惑的是`px`值。將其設為任何像素值都會將其精確地設定為該值。因此,如果您的`font-size`為 16px,並且您將`line-height`設為 12px,您的字體將比它所包裝的容器更大。一般來說,您應該盡量避免在行高中使用`px`值! ``` body { font-size: 16px; } .pixel { line-height: 12px; } ``` ### 一些最佳實踐 一般來說,我先將`body`元素中的`font-size`和`line-height`設定為以下值。 ``` body { font-size: 16px; line-height: 1.5; } ``` 由此,您可以建立所有其他樣式。我會盡量避免使用無單位數字以外的任何東西。另外,嘗試使用易於分割的`font-size`值,例如 16 或 12。這將有助於您在設計中保持平衡。您也可以在`margin`和`padding`中使用它。在腦中計算 16 \* 1.5 比 13 \* 1.5 更容易。然後您將永遠知道實際價值是多少。 ``` body { font-size: 16px; line-height: 1.5; } h1, h2, h3, h4, ul, ol { margin-bottom: 15rem; } button { display: inline-block; padding: 0.75rem 1.5rem; } ``` 當然,你可以嘗試一下,這些規則也會有例外,但我總是這樣開始。 資源 -- - http://www.indesignskills.com/tutorials/leading-typography/ - https://developer.mozilla.org/en-US/docs/Web/CSS/line-height - https://www.w3schools.com/cssref/pr\_dim\_line-height.asp - https://css-tricks.com/almanac/properties/l/line-height/ - https://ux.stackexchange.com/questions/35270/is-there-an-optimal-font-size-line-height-ratio **謝謝閱讀!** --- 原文出處:https://dev.to/lampewebdev/css-line-height-jjp