🔍 搜尋結果:原型

🔍 搜尋結果:原型

每個前端開發人員都應該了解的軟體工程原理

作為前端開發人員,我們通常專注於建立漂亮的使用者介面。然而,重要的是要記住,美麗也在於內部,像素完美的方法也應該轉化為我們的程式碼組織和結構。在本文中,我們將探討每個前端開發人員都應該了解並在其專案中應用的一些基本軟體工程原理。 1. DRY(不要重複) ------------ DRY 原則強調程式碼可重複使用性和維護的重要性。透過將通用功能提取到可重複使用元件、函數或模組中來避免重複程式碼。透過堅持 DRY 原則,您可以減少程式碼重複,提高可維護性,並使您的程式碼庫更加模組化。 React 鼓勵元件驅動的架構,其中職責被隔離,以便於未來的開發和可擴展性。 我們以一個簡單的電子商務應用程式中的產品頁面為例。我們希望看到待售產品清單。我們可以將頁面分解為更小的、可重複使用的元件。 成分: 1. 產品卡:顯示單一產品及其名稱、價格和描述。 2. 產品清單:顯示產品清單。 ``` // ProductCard.js import React from 'react'; const ProductCard = ({ product }) => { return ( <div> <h2>{product.name}</h2> <p>Price: ${product.price}</p> <p>Description: {product.description}</p> </div> ); }; export default ProductCard; ``` ``` // ProductList.js import React, { useState } from 'react'; import ProductCard from './ProductCard'; const ProductList = () => { const [products, setProducts] = useState([ { id: 1, name: 'Product 1', price: 9.99, description: 'Description 1' }, { id: 2, name: 'Product 2', price: 19.99, description: 'Description 2' }, // ... ]); return ( <div> {products.map((product) => ( <ProductCard key={product.id} product={product} /> ))} </div> ); }; export default ProductList; ``` 在此範例中,我們看到,透過將與產品相關的邏輯分離到`ProductCard`元件中,我們可以在`ProductList`元件的`map`功能中重複使用它,並避免清單頁面中每個產品專案的重複程式碼。 2. SOLID 原則 -------- SOLID 是一個縮寫詞,代表物件導向設計的五個關鍵原則: - **單一**責任原則 (SRP):每個模組或類別應該只有一個更改理由。 - **開放**/封閉原則(OCP):軟體實體應該對擴展開放,對修改關閉。 - **李斯科夫**替換原則(LSP):子類型應該可以替換其基本類型,而不改變程式的正確性。 - **介面**隔離原則 (ISP):不應強迫客戶端依賴他們不使用的介面。 - **依賴**倒置原則(DIP):高層模組不應該依賴低層模組。兩者都應該依賴抽象。 讓我們來看看如何在 React TypeScript 元件中應用里氏替換原則 (LSP): ``` // Vehicle.ts interface Vehicle { drive(): void; name: string; } // Car.ts class Car implements Vehicle { constructor(private name: string) { this.name = name; } drive(): void { console.log(`Driving a ${this.name}`); } } // Motorcycle.ts class Motorcycle implements Vehicle { constructor(private name: string) { this.name = name; } drive(): void { console.log(`Riding a ${this.name}`); } } // App.tsx import React from 'react'; import { Vehicle } from './Vehicle'; import Car from './Car'; import Motorcycle from './Motorcycle'; function VehicleComponent(props: { vehicle: Vehicle }) { props.vehicle.drive(); return <div>Driving a {props.vehicle.name}</div>; } const App = () => { const car = new Car(); const motorcycle = new Motorcycle(); return ( <div> <VehicleComponent vehicle={car} /> <VehicleComponent vehicle={motorcycle} /> </div> ); }; export default App; ``` 在此範例中,我們有一個`Vehicle`接口,它定義了`name`屬性和`drive`方法。然後我們有兩個具體的實作: `Car`和`Motorcycle` ,它們都實作了`Vehicle`介面。 在 App 元件中,我們建立`Car`和`Motorcycle`的實例並將它們傳遞給 VehicleComponent。 `VehicleComponent`對傳入的車輛物件呼叫驅動方法。 LSP 確保我們可以用`Car`或`Motorcycle`代替`Vehicle`接口,而不改變程序的正確性。 `VehicleComponent`可與`Car`和`Motorcycle`實例無縫協作,展示子類型對其基本類型的可替換性。 3. KISS(保持簡單,愚蠢) ---------------- KISS 原則提倡設計和實現的簡單性。編寫易於理解、簡單且能做好一件事的程式碼。避免不必要的複雜性和過度設計,因為從長遠來看,這可能會導致混亂和維護挑戰。 讓我們來看看`Counter`元件的 2 個實作。 ``` // Complex Counter import React, { useState, useEffect } from 'react'; import { debounce } from 'lodash'; const ComplexCounter = () => { const [count, setCount] = useState(0); const [clicked, setClicked] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (clicked) { setCount(prev => prev + 1) setClicked(false) } }, [clicked, setClicked]); const handleClick = (clicked: boolean) => { setClicked(!clicked); }; return ( <div> <p>Count: {count}</p> <button onClick={() => handleClick(clicked)}>Increment</button> </div> ); }; export default ComplexCounter; ``` ``` // Simple Counter import React, { useState } from 'react'; const SimpleCounter = () => { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Increment</button> </div> ); }; export default SimpleCounter; ``` 我們發現`ComplexCounter`實作更難理解和維護,而且更容易出錯。 它引入了一個不必要的`clicked`狀態變數和一個`useEffect`掛鉤。 這是一個如何不實作 React 元件的範例。 4. YAGNI(你不需要它) --------------- YAGNI 提醒我們避免基於推測的未來需求過早加入功能。相反,應專注於正確實現當前所需的功能。當您建立一個非常以用戶為中心的產品時,這一點變得非常重要。最好不要根據您認為用戶可能想要的假設來引入新功能。使用適當的使用者研究框架和原型設計方法。 遵循 YAGNI,您可以防止不必要的複雜性、減少開發時間並維護精簡的程式碼庫。 5. 乾淨的程式碼 --------- 乾淨的程式碼是可讀的、可理解的、可維護的。遵循編碼約定和最佳實踐,使用有意義的變數名稱,並編寫不言自明的程式碼。保持函數和類別小而集中,堅持一致的格式,並努力使程式碼庫清晰。 讓我們來看一個簡單的實用函數,用於出於資料安全目的隱藏部分使用者的私人資訊。 ``` const hashUsersPrivateInformation = (privateInformation: string): string => { // Calculate the length of the private info to determine how many characters to mask const maxLength = privateInformation.length > 4 ? privateInformation.length - 4 : privateInformation.length; // Create a regular expression pattern to match the desired number of characters const regexPattern = `.{1,${maxLength}}`; const regex = new RegExp(regexPattern); return privateInformation.replace(regex, (match) => '*'.repeat(match.length)); }; ``` 我們看到: 1. 函數的名稱是自我描述的 2. 它包含可以幫助其他開發人員的有用註釋。 3. 它有一個可以理解的主要目的。 我們應該以類似的方式建立我們的程式碼。 結論 -- 將這些軟體工程原理融入您的前端開發工作流程中,您可以編寫更高品質的程式碼,改善與團隊成員的協作,並建立強大且可擴展的應用程式。軟體工程不僅僅是編寫程式碼;還涉及編寫程式碼。它是為複雜問題建立可靠、可維護且優雅的解決方案。 --- 原文出處:https://dev.to/gboladetrue/software-engineering-principles-every-frontend-developer-should-know-1ej7

17 個值得嘗試的最佳開發人員生產力工具

效率和生產力不僅是開發人員的目標,也是必需品。我們製作了大量的工具並編寫了日常任務的腳本,所有這些都是為了騰出時間來處理真正重要的事情。在當今龐大的開發者生態系中,一系列[生產力工具](https://www.devzero.io/blog/ai-tools-for-software-developers-in-2023-to-boost-dev-productivity)隨時可以簡化我們的工作流程。 生產力工具的作用不僅僅是減少重複性任務的[時間](https://www.devzero.io/blog/time-management-tools-and-tips-boosting-productivity-for-software-developers)。它們在管理程式碼和促進團隊協作方面至關重要。借助正確的工具包,開發人員可以將注意力從平凡轉向創新,以新的自由度來應對創意挑戰。讓我們深入了解頂級開發者生產力工具,以在 2024 年提升您的遊戲水平。 衡量開發人員的生產力 ---------- 首先,讓我們解決一個基本問題:我們如何衡量開發人員的生產力?開發人員的日常生活不僅包括編寫程式碼,因此衡量生產力需要廣泛審視整個軟體開發過程的效率和有效性。 我們可以追蹤熟悉的指標,例如程式碼行數、開發的功能、修復的錯誤和交付時間表。然而,真正理解生產力需要一種整體方法,一種權衡軟體開發的有形和無形方面的方法。因此,考慮品質、影響和協作也很重要。 了解生產力工具 ------- 接下來,我們來詳細分析開發人員可以使用的不同類型的生產力工具: - IDE、程式碼編輯器和助手是任何開發人員武器庫的基石,為編碼、編輯、測試和除錯提供整合平台。 - 開發環境確保開發人員可以專注於編寫程式碼,而不是管理基礎架構。 - 專案管理和協作工具對於組織任務、追蹤進度和確保團隊溝通順暢至關重要。 - 設計和原型工具使開發人員能夠製作引人注目的視覺設計並改進其應用程式的 UI/UX。 - 偵錯工具對於快速辨識和修復錯誤和其他程式碼問題至關重要。 - 框架和抽象可以幫助開發人員透過重複使用通用元件更快地交付程式碼。 - 部署應用程式是最後一步,但確保效能和穩定性是關鍵。 從編碼的基礎工作到使用者介面和團隊協作的微調,每個類別在提高生產力方面都發揮著至關重要的作用。 IDE、程式碼編輯器和助手 ------------- 讓我們來看看 2024 年一些流行的 IDE 和程式碼編輯器。 1. IntelliJ IDEA --------- [IntelliJ IDEA](https://www.jetbrains.com/idea/)是 Java 和 Kotlin 開發人員的首選 IDE,提供的綜合[開發環境](https://www.devzero.io/blog/why-software-development-environments-are-important-and-how-to-manage-them-effectively)遠遠超出 Atom 等簡單程式碼編輯器所提供的功能。此 IDE 具有出色的高級功能,例如深入程式碼理解以實現卓越的導航和重構。與基本編輯器不同,IntelliJ 整合了資料庫和版本控制的基本工具,透過讓您所需的一切觸手可及來簡化您的工作流程。 IntelliJ 社群版免費提供,並提供對其功能的廣泛探索,但存取權限僅限於學生、BootCamp 成員和特定焦點小組。對於其他人來說,專業版的價格約為每月 20 美元,並且可以完全存取 IntelliJ 強大的工具套件。 2. Visual Studio Code -------------------- Microsoft 的[Visual Studio Code](https://code.visualstudio.com/)是跨所有框架、語言和程式庫的開發人員的首選程式碼編輯器。其突出的特點是一個龐大的擴展庫,旨在提高生產力。想像一下,利用 TabNine 進行 AI 驅動的程式碼補全,或整合 GitHub Copilot,利用其 AI 輔助功能將編碼速度提高十倍。除此之外,Visual Studio Code 還提供內建的 Git 控制、用於 shell 命令的整合終端以及用於無縫程式碼分析的專用偵錯器。 最重要的是,它完全免費,並且與 Windows、Mac 和 Linux 平台普遍相容。 3. AppMap ------- [AppMap](https://www.appmap.io/)是一種視覺化工具,可提供應用程式程式碼庫內互動的詳細概述。它為開發人員提供了整個應用程式中資料流和控制的圖形表示,幫助他們更直觀地理解複雜的系統。透過 AppMap,開發人員可以輕鬆瀏覽不同的元件,了解模組之間的依賴關係,並確定潛在的最佳化或重構領域。透過直觀地繪製應用程式的內部工作原理,AppMap 增強了開發團隊之間的協作,並有助於在開發過程中做出更好的決策。 Appmap 最近推出了 Navie。 Navie 是一種生成編碼 AI,具有 API 和資料庫感知能力,因此它可以為整個程式碼庫中的複雜變更提供程式碼建議。 Navies 回答並建議針對開發人員問題進行程式碼更改,例如「我的資料庫查詢效能很慢。我如何解決它?或“我需要更改令牌系統以提高身份驗證安全性,我該如何進行?” ‍ 海軍的建議針對每位開發人員及其正在開發的軟體進行高度個人化,同時確保您的 IP 安全。 4.Copilot ----- 向無可爭議的版本控制統治者屈服:GitHub。憑藉其一系列強大的功能,包括透過 GitHub 工作流程進行自動化部署、 [GitHub Copilot](https://github.com/features/copilot)的人工智慧驅動協助以及 Dependabot 的主動安全修補,GitHub 處於開發創新的前沿。就像 Visual Studio Code 是編碼的首選一樣,GitHub 是開發人員進行版本控制的首選平台。 GitHub 的免費套餐包含豐富的產品,非常適合小型團隊、獨立開發人員、自由工作者和新創公司。但對於大型組織和企業來說,Teams 計劃(每位使用者每月3.67 美元)和Enterprise 計劃(每位使用者每月19.25 美元)解鎖了一系列高級功能,例如GitHub Codespaces,這是與GitHub 無縫整合的虛擬IDE,可直接在平台內進行編碼。此外,付費方案還提供增強的協作功能,例如能夠任命多個拉取請求審閱者和指定程式碼擁有者,從而簡化開發流程並確保程式碼品質。 ‍ 此類別中出現的另外兩個工具是[SuperMaven](https://supermaven.com/)和[TabbyML](https://github.com/TabbyML/tabby) ,兩者都使用快速且安全的 LLM 來完成程式碼完成和建議。 開發環境 ---- 在當今的微服務和複雜的基於雲端的服務和第三方庫的世界中,本地主機無法提供所需的適當環境。這會導致整個 SLDC 不斷重構並減慢部署週期。 5.DevZero --------- [DevZero](https://www.devzero.io/)是一個為開發人員在雲端提供一致的、類似生產的開發環境的平台。開發人員可以在他或她的本機電腦上工作,但仍然體驗生產環境的所有細微差別,例如資料庫、雲端原生服務等。到生產都是一致的。新開發人員只需幾分鐘即可入職,而不是幾天。這使工程組織具有一致性和易於管理。不再除錯本機。 DevZero 的一個顯著優勢是縮短了 CI 時間。開發人員可以節省重構和編譯基礎架構處理所花費的寶貴時間,因為現在他們可以立即在生產環境中執行本機程式碼。這也提高了整體發布頻率並消除了在不同環境中進行測試的障礙。 協作和專案管理 ------- 開發人員經常處理無數的選項卡,並且可能會跨多個顯示器進行操作,但切換平台以進行協作和任務管理的想法可能是一個真正的痛點。讓我們深入研究一些旨在提高開發人員生產力和促進無縫團隊協作的關鍵工具。 6. Slack ----- Slack 徹底改變了遠端協作,使公司能夠即時通訊和共享文件。對於開發人員來說,它是協作的動力源泉,可與 GitHub 等工具無縫集成,以即時更新程式碼推送或部署。這種整合確保每個人都能及時了解專案狀態,而無需不斷地來回訊息。您可以透過 Slack 的整合使用任何專案管理工具,例如 Trello、JIRA 等。 Slack 透過可自訂的工作流程和應用程式進一步發展,讓平台內任務和問題管理。雖然免費計劃支援基本通訊和最多十個集成,但要擴展到自訂自動化及其他功能,需要升級到專業計劃(每人每月 8.25 歐元)或商業計劃(每人每月 14.10 歐元)。這種靈活性使 Slack 成為追求效率和簡化工作流程的開發團隊不可或缺的工具。 7. Height ----- 在管理專案和維持組織性方面,擁有可靠的工作追蹤工具至關重要。 [Height](http://height.app/)是一款功能強大的專案管理工具,提供廣泛的功能,旨在簡化協作並最大限度地提高效率。借助 Height,開發人員可以輕鬆分配任務、設定截止日期、追蹤進度並監控團隊績效。其直覺的收件匣式介面和強大的分析功能使其成為希望掌控工作量並按時交付專案的團隊的首選。 8. Linear ----- [Linear.app](https://linear.app/)是一個專案管理和問題追蹤工具,旨在幫助團隊更有效地協作和管理工作。 Linear 提供了一個用於組織任務、追蹤進度和促進團隊成員之間溝通的平台。該工具以其時尚且用戶友好的介面而聞名。 9. Pullflow ----- 審查 PR 很多時候是工程組織的瓶頸。它不像編寫程式碼那樣有回報,並且需要上下文切換。 [Pullflow](https://pullflow.com/)旨在透過其人工智慧增強的程式碼審查協作功能來減少上下文切換並改善溝通和公關管理。 Pullflow 整合了 VSCode、Github 和 Slack 之間的 PR 通信,因此開發人員無需進行上下文切換。 設計和原型製作工具 --------- 開發人員從頭開始精心設計設計並仔細考慮每個佈局、顏色和字體選擇的時代已經演變。今天的 UI/UX 開發人員享受 Figma 等工具的重大飛躍,其中設計與程式碼相結合。讓我們詳細探討一下。 10. Figma ------- [Figma](https://www.figma.com/)透過提供可無縫整合到專案中的現成程式碼片段,徹底改變了設計到開發流程。在過去的一年裡,Figma 推出了許多插件,為 React、Vue 甚至 HTML 等流行框架提供樣板元件,並支援 Figma 設計直接轉換為 Webflow。 FigJam 是一項出色的功能,事實證明,它對於規劃和確定建造和發布的範圍、衝刺規劃和製作架構圖非常有價值。它在協作和策略規劃階段的效用怎麼強調都不為過。 由於其基於網路的特性,Figma 提供了無與倫比的易用性,並輔以適用於 Windows 和 macOS 的專用桌面應用程式。您需要加入其中一項付費方案才能使用開發模式並存取所有設計元素的程式碼。如果您使用組織計劃,您甚至可以使用私人插件。 11.Whimsical和Excalidraw ------------------ 在解釋複雜概念或設計系統架構時,圖表和視覺化通常是必不可少的。 [Excalidraw](https://excalidraw.com/)和[Whimsical](https://whimsical.com/)是兩種流行的快速繪圖工具,可讓開發人員輕鬆建立圖表。憑藉其簡單而強大的介面,開發人員可以立即建立線框、流程圖和其他視覺表示。這些工具非常適合集思廣益並向利害關係人展示概念,使它們成為開發人員工具包的寶貴補充。 偵錯工具 ---- 除錯是軟體開發生命週期中最具挑戰性和最耗時的部分之一。然而,正確的警報和監控系統可以節省無數時間。讓我們深入研究可以顯著簡化除錯過程、提高效率並減少開發工作流程中的停機時間的基本工具。 12.Postman ----- [Postman](https://www.postman.com/)已成為測試和記錄 API 的基礎 API 開發工具,因其在除錯生產和本地 API 方面的強大能力而贏得了開發人員的廣泛認可。它使用戶能夠發送和模擬 HTTP 請求,這項功能對於等待後端 API 準備就緒的前端開發人員特別有利,可確保持續進展。 除了在測試中的實用性之外,Postman 還充當 API 文件的集中儲存庫,促進團隊內的無縫共享和協作。其基本計劃(每個用戶每月 14 美元)對於大多數開發人員來說應該足夠了。 13.Sentry ----- [Sentry](https://sentry.io/)是效能監控和錯誤追蹤領域的強大工具,擅長自動辨識程式碼庫中的錯誤和錯誤。 Sentry 的 SDK 適用於幾乎所有廣泛使用的框架和技術(包括 JavaScript、PHP、Python 和 Ruby),可無縫整合到您的專案中。 檢測到錯誤後,Sentry 會提供全面的見解,例如堆疊追蹤、來源頁面和使用者訊息,這些對於有效診斷和解決問題非常寶貴。此外,程式碼覆蓋率和會話重播等功能被證明是不可或缺的,尤其是在面臨重現難以捉摸的錯誤的艱鉅任務時。 Sentry 的功能確保開發人員可以花更少的時間進行故障排除,而將更多的時間用於開發,從而提高整體生產力和程式碼品質。 您可以嘗試 Sentry 及其免費的單獨開發者計畫。然而,為了充分利用它,我建議嘗試團隊計劃(每月 26 美元),您可以將隊友加入到 Sentry 工作區。您還需要每月支付 29 美元購買程式碼覆蓋率。 框架和抽象 ----- 當今的許多元件在應用程式中都很常見:身份驗證、授權、資料庫存取、UI 元件等。寫內容從頭開始。 14.Vercel ------ 建置和部署 Web 應用程式可能是一項複雜的任務,尤其是當專案規模不斷擴大時。 Web 應用程式部署框架(例如 Vercel)為開發人員提供了簡化且可擴展的解決方案來部署其 Web 應用程式。 [Vercel](https://www.vercel.com/)是一個雲端平台,旨在簡化 Web 應用程式的部署和託管。它以專注於透過提供自動部署、無伺服器功能和全球內容交付等功能為開發人員提供無縫體驗而聞名。 15. Neurelo ------ [Neurelo](https://www.neurelo.com)為您的資料 API 提供了一個與資料庫無關的程式設計介面。 Neurelo 無需學習 MongoDB 或 PostgreSQL 的查詢語言並為它們建立 API,而是在幾分鐘內為您提供優化的自動生成的 API,包括模式建置器,以及使用 Git 管理開發、登台和生產環境的界面類似版本控制來管理追蹤更改。最後,它使用人工智慧提供自動生成的文件以及透過點擊生成和測試複雜查詢的能力。 許多公司最終會產生自己的抽象層來管理開發人員的資料庫存取或使用 SQLAlchemy 或 Hibernate 等物件關係映射器 (ORM)。 Neurelo 建立了一個通用的強大且與資料庫無關的替代方案。 部署應用程式 ------ 16. Fly.io --------- 部署應用程式可能是一個複雜且耗時的過程。應用程式部署工具(例如[Fly.io](http://fly.io/) )旨在透過提供一個用於輕鬆部署和管理應用程式的平台來簡化此流程。 ‍ Fly.io是一個提供全球應用部署網路的平台。它允許開發人員在跨越全球多個地點的分散式基礎設施上部署和執行他們的應用程式。 Fly.io 專注於透過將應用程式執行個體分佈在更靠近最終用戶的位置來優化應用程式效能,減少延遲並改善整體用戶體驗。 ‍ 該平台支援各種程式語言和框架,使開發人員能夠部署各種應用程式,包括Web應用程式、API和微服務。 Fly.io 使用邊緣運算和全球選播網路的組合來最佳化路由並確保使用者要求定向到最近的可用應用程式實例。 17. Tigris ----------- [Tigris](https://www.tigrisdata.com/)是一種與 S3 相容的全球分散式物件儲存服務,它將資料儲存為物件儲存桶中。物件是一個文件和描述該文件的任何元資料。桶子是存放物件的容器。 ‍ 哪個才是最好的開發工具? ------------ 只要您的武器庫中擁有每個類別中的任何一種工具,您就可以開始使用了。但如果我必須為您選擇一種工具,我會選擇 Visual Studio Code。它因其多功能性、對語言和框架的廣泛支援以及強大的擴展生態系統而脫穎而出,使其成為首選。 工程生產力工具 ------- 工程生產力工具支援軟體開發的特定工程方面。這可能包括分析、自動化測試、部署、容器化或靜態程式碼分析。使用這些工具,您可以確保程式碼品質和效能,並在開發週期的早期發現潛在問題。一些常見的工程生產力工具包括Docker、Jenkins、Confluence、JIRA等。 結論 我很想知道 2024 年您會從這個[清單](https://www.devzero.io/blog/how-to-calculate-developer-productivity-metrics-using-mergestat-and-devzero)中選擇哪種工具。從本質上講,GitHub 和 Visual Studio Code 是 2024 年的必備工具。我仍在研究它們,誰知道呢,它們可能會出現在 2025 年的清單中。 本文原刊於 https://www.devzero.io/blog/best-developer-productivity-in-2024 --- 原文出處:https://dev.to/shohams/17-best-developer-productivity-tools-to-try-1a2a

JavaScript 中的三個點 (...)

> 嘿!我是薩加爾。我喜歡編寫教學和文章來幫助開發人員更好地理解 JavaScript 的魔力。如果您對本文有任何疑問,請發表評論,我會回覆您,或在 Twitter [@sagar\_codes](https://twitter.com/sagar_codes)上找到我。 在這篇文章中,我們將討論 ES6 中引入的一個特性,即展開運算子和剩餘運算子。 🔥 🔥 🔥 我已經成為這三個點的忠實粉絲,它們可能會改變您在 JavaScript 中解決問題的風格。我們可以以兩種不同的方式使用三個點作為擴充運算子和剩餘運算子。 休息參數😴 ----- 使用剩餘參數,我們可以將任意數量的參數收集到一個陣列中,並用它們執行我們想要的操作。引入剩餘參數是為了減少由參數引起的樣板程式碼。 🙌 ``` function myFunc(a, b, ...args) { console.log(a); // 22 console.log(b); // 98 console.log(args); // [43, 3, 26] }; myFunc(22, 98, 43, 3, 26); ``` 在 myFunc 的最後一個參數中,前綴為 …,這將導致所有剩餘參數都放置在 javascript 陣列中。 其餘參數收集所有剩餘參數,因此在最後一個參數之前加入其餘參數是沒有意義的。剩餘參數必須是最後一個形參。 ``` function myFunc(arg1, ...rest, arg2) { // arg2 ? } ``` 其餘參數可以解構(僅限陣列),這意味著它們的資料可以解壓縮為不同的變數。 ``` function myFunc(...[x, y, z]) { return x * y* z; } myFunc(1) // NaN myFunc(1, 2, 3) // 6 myFunc(1, 2, 3, 4) // 6 (fourth parameter is not destructured) ``` 傳播運算符✨ ------ 擴展運算子用於將可迭代物件(如陣列)的元素擴展到可以容納多個元素的位置。 ``` function myFunc(x, y, ...params) { // used rest operator here console.log(x); console.log(y); console.log(params); } var inputs = ["a", "b", "c", "d", "e", "f"]; myFunc(...inputs); // used spread operator here // "a" // "b" // ["c", "d", "e", "f"] ``` 組合陣列的方法一直有很多種,但展開運算子提供了一種組合陣列的新方法: ``` const featured = ['Deep Dish', 'Pepperoni', 'Hawaiian']; const specialty = ['Meatzza', 'Spicy Mama', 'Margherita']; const pizzas = [...featured, 'veg pizza', ...specialty]; console.log(pizzas); // 'Deep Dish', 'Pepperoni', 'Hawaiian', 'veg pizza', 'Meatzza', 'Spicy Mama', 'Margherita' ``` 透過擴充運算符,現在可以使用比 Object.assign() 更短的語法來淺複製(不包括原型)或合併物件。 ``` var obj1 = { foo: 'bar', x: 42 }; var obj2 = { foo: 'baz', y: 13 }; var clonedObj = { ...obj1 }; // Object { foo: "bar", x: 42 } var mergedObj = { ...obj1, ...obj2 }; // Object { foo: "baz", x: 42, y: 13 } ``` 👉 結論 ---- 當我們在程式碼中看到三個點(…)時,它要么是剩餘參數,要么是擴展運算子。 有一個簡單的方法可以區分它們: 1. 當三個點 (…) 位於函數參數末尾時,它是“剩餘參數”,並將參數列表的其餘部分收集到一個陣列中。 2. 當三個點 (…) 出現在函數呼叫或類似情況中時,它被稱為“擴展運算符”,並將陣列擴展為列表。 謝謝閱讀。希望您喜歡這篇文章,歡迎按讚、留言或與您的朋友分享這篇文章。 😄 快樂編碼… --- 原文出處:https://dev.to/sagar/three-dots---in-javascript-26ci

用於建立 AI/ML 應用程式的最佳開發工具!

我來自世界各地的 DevOps 領域,在加入我現在的公司 SingleStore 之前,AI/ML 世界對我來說是全新的。我加入已經 8 個月了,一切進展得非常順利。從各種部落格、教程、工具等中學習AI/ML 中所有新的很酷的東西。這些要求的工具。順便說一句,我們有很多內容和材料可以開始,但我想看看行業之外還發生了什麼,並做我自己的研究。 正如我所說,已經過去 8 個月了。在我在這裡的整個旅程中,從舉辦網路研討會、在會議上發言,到撰寫有關新興技術趨勢的博客,我偶然發現了一系列不可或缺的工具。在本文中,我將分享這些工具,從新興程式語言到 AI 框架,再到向量資料庫,再到簡化 AI/ML 應用程式建立的開發工具。***讓我們開始吧。*** 1. 程式語言 ------- ### [翅膀](https://git.new/winglang) ![只是一個翅膀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pyqzc2vsp6ckovq7j7p.png) 我嘗試使用多種語言,但發現大多數語言都被誇大了。是的,就在那時,我遇到了一個正在討論這種為雲端和人工智慧應用程式設計的新語言的社群。那是我第一次嘗試 Wing 程式語言,發現它令人印象深刻。 你可能會問 - 為什麼是 Wing? Wing 提供了一個統一的程式設計模型,將基礎架構和應用程式程式碼整合到一個有凝聚力的框架內。這種獨特的方法使開發人員能夠簡化他們的工作流程,消除不斷切換情境的需要,並顯著提高生產力和創造力。 這正是您在建立 AI/ML 應用程式時所需要的,更專注於核心功能而不是底層基礎設施。我遇到了他們的 Open AI Joker 應用程式,它可以產生笑話並將其翻譯成不同的語言。整個框架的流暢程度令人驚嘆。請注意,Wing 仍在積極開發中。 您可以使用最少的程式碼建立任何 AI/ML 應用程式。讓我們看看 Joker 應用程式是如何運作的。該應用程式使用 OpenAI 生成笑話並將其翻譯成不同的語言。有一個喜劇演員,一個開放人工智慧助手,可以產生笑話,每當它生成笑話時,笑話就會被放入/儲存在一個桶中。有兩個譯者,西班牙語和希伯來語。這些譯者訂閱一個主題。每當有笑話產生時,他們都會收到並翻譯。而且,他們也把翻譯好的笑話丟進桶裡了。很簡單。 以下是此範例的技術概述圖,展示如何將[OpenAI 的 API 與 Wing](https://github.com/winglang/examples/tree/main/examples/openai-joker)結合使用。 ![翅膀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5chcap4ufyxnv6aef9m.png) 如果您還沒有嘗試過 Winglang,您可以透過簡單的命令輕鬆嘗試 ``` npm install -g winglang ``` 使用 git clone 指令將程式碼複製到本機 ``` git clone https://github.com/winglang/wing.git ``` 轉到範例資料夾,然後在終端機中執行以下命令: ``` npm install wing it ``` 呼叫“START HERE”函數,並在“Joke Store”中查看結果。 2.向量資料儲存與分析工具 ------------- ### SingleStore 和筆記本 ![單一儲存資料庫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/migeuz23bst8l2s445i4.jpeg) 對於 AI/ML 應用程式,您需要一個資料庫來儲存非結構化資料。我大約 8 個月前加入 SingleStore,當時我對 AI/ML 和向量資料庫還是個新手。隨著圍繞向量資料庫的大肆宣傳,我開始了解向量資料庫,並發現 SingleStore 作為向量資料庫如何為行業帶來驚人的補充。它不僅用於儲存向量資料,而且該公司還使用 SingleStore 進行即時分析。現在,看看支援即時分析的向量資料儲存的力量,這是一種超級力量。 下面我要來跟大家介紹一下SingleStore;它是一個基於雲端的資料庫管理系統(RDBMS),專為資料密集型應用程式而設計。它以其資料攝取、事務處理和查詢處理的速度而聞名。 SingleStore 早在 2017 年就開始支援向量儲存。 SingleStore 的 Notebook 功能基於流行的 Jupyter Notebook,廣泛應用於資料科學和機器學習社群。 SingleStore Notebook 擴展了 Jupyter Notebook 的功能,使資料專業人員能夠輕鬆使用 SingleStore 的分散式 SQL 資料庫,同時在語言和資料來源方面提供出色的可擴充性。 [試試 SingleStore 並獲得價值 600 美元的免費積分](https://www.singlestore.com/cloud-trial/?utm_medium=referral&utm_source=pavan&utm_term=devto&utm_content=aimltools)。 3. 資料操作與分析工具 ------------ 我只是喜歡處理資料並使用公開的資料集(例如葡萄酒資料集、泰坦尼克號資料集等)進行不同的實驗。我著迷地看到 NumPy 和 Pandas 在資料探索和提出不同解決方案方面的能力。 Pandas 和 NumPy 是 Python 生態系統中用於資料分析和科學計算的兩個最受歡迎的函式庫。 ### 熊貓和 NumPy ![熊貓和 numpy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zl8ez8r05a61wcy9zaze.png) 任何 AI/ML 應用程式的核心都是資料。 Pandas 和 NumPy 等工具是 Python 中資料操作和分析的基礎。 Pandas 提供了用於操作數值表和時間序列的高級資料結構和操作,使其成為在用於訓練模型之前預處理和清理資料的理想選擇。 NumPy 增加了對大型多維陣列和矩陣的支持,以及對這些陣列進行操作的大量數學函數的支持,這對於資料預處理和模型訓練中的效能密集型操作至關重要。 4. 人工智慧與機器學習框架 -------------- 我使用過 TensorFlow、PyTorch,最近接觸過 LangChain 和 LlamaIndex,對它們幫助 AI/ML 工程師使用 API、向量儲存功能、邏輯、推理等建立強大應用程式所需的所有工具包的能力印象深刻。讓我們一一來看看他們的超能力。 ### TensorFlow 和 PyTorch ![pytorch中的tensonflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23wl305qjftx5y33ewvt.png) 由 Google 開發的[TensorFlow](https://www.tensorflow.org/)和由 Facebook 開發的[PyTorch](https://pytorch.org/)是用於建立和訓練複雜機器學習模型的兩個最受歡迎的框架。 TensorFlow 以其靈活性和強大的可擴展性而聞名,使其適用於研究原型和生產部署。 PyTorch 因其易用性、簡單性和動態計算圖而受到讚譽,可以更直觀地編碼複雜的 AI 模型。這兩個框架都支援廣泛的人工智慧模型,從簡單的線性回歸到複雜的深度神經網路。 ### 浪鏈 ![浪鏈](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zy5mcfwl843zlrte6x0b.png) [LangChain](https://www.langchain.com/)由 Harrison Chase 開發,於 2022 年 10 月首次亮相,它是一個開源平台,旨在建立由大型語言模型支援的強大應用程式,例如 ChatGPT 等聊天機器人和各種客製化應用程式。 Langchain 致力於為資料工程師提供一個包羅萬象的工具包,以便在聊天機器人、自動問答、文字摘要等各種用例中利用法學碩士。 ### 駱駝指數 ![駱駝指數](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2tgndtlwx6emah2k6s2h.png) [LlamaIndex](https://www.llamaindex.ai/)是一種先進的編排框架,旨在增強 GPT-4 等 LLM 的功能。雖然法學碩士本質上很強大,並且接受過大量公共資料集的培訓,但他們通常缺乏與私有或特定領域資料互動的方法。 LlamaIndex 彌補了這一差距,提供了一種結構化的方式來攝取、組織和利用各種資料來源——包括 API、資料庫和 PDF。透過將這些資料索引為針對法學碩士最佳化的格式,LlamaIndex 促進了自然語言查詢,使用戶能夠無縫地與其私有資料進行對話,而無需重新訓練模型。 5.深度學習模型 -------- 作為初學者,我一直在尋找簡單而靈活的東西來開發深度學習模型,就在那時我發現了 Keras。許多 AI/ML 專業人士欣賞[Keras](https://keras.io/)在原型設計和開發深度學習模型方面的簡單性和高效性,使其成為首選,特別是對於初學者和需要快速開發的專案。 ### 難的 ![難的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqtk1tp1berno2yie8u7.png) 對於尋求高級神經網路 API 的開發人員來說,現在已整合到 TensorFlow 中的 Keras 提供了更簡單的介面來建立和訓練深度學習模型。 Keras 抽象化了建構神經網路的大部分複雜性,使其易於初學者使用,同時仍足夠強大以進行研究。 6. 開發和版本控制平台 ------------ ### GitHub 和 DVC ![DVC套件](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1tx82df0xei0m5qwpk3.png) 由於模型開發的迭代性質和對可重複性的需求,協作和版本控制在 AI/ML 開發專案中至關重要。 [GitHub](https://github.com/)是領先的原始碼管理平台,允許團隊協作處理程式碼、追蹤問題和管理專案里程碑。 [DVC(資料版本控制)](https://dvc.org/)透過處理 Git 無法有效管理的大型資料檔案、資料集和機器學習模型來補充 Git,從而實現對 AI 專案中使用的資料和模型檔案的版本控制。 7. AI模型部署與監控 ------------ 我建立了一些 AI/ML 應用程式,但是如何以及在哪裡部署它們?這就是我的想法跳到這個類別中的兩個主要工具:Docker 和 Kubernetes。正如我之前所說,我來自世界各地的 DevOps 地區,我已經使用過這些工具,並且知道它們是如何運作的。 Docker 將您的應用程式容器化,而 Kubernetes 用於大規模部署您的應用程式。 ### Docker 和 Kubernetes ![Docker 和 Kubernetes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thj4mvioz76tja3ew3iw.png) 將人工智慧模型部署到生產中需要能夠打包應用程式並大規模管理它們的工具。 [Docker](https://www.docker.com/)透過容器化AI應用程式來簡化其部署,確保應用程式在任何環境中順利執行。 [Kubernetes](https://kubernetes.io/)是 Docker 容器的編排系統,可以自動部署、擴展和管理容器化應用程式,這對於需要跨多個伺服器或雲端環境進行擴展的 AI 應用程式至關重要。 8.人工智慧雲端平台 ---------- 如果沒有 AWS、Google 和 Azure 等雲端平台,您就無法擴展任何東西。雖然 AWS 是我最喜歡的,但我也探索了其他選項,並在此提到了所有三個主要雲端供應商。 ### AWS、Google雲端和 Azure ![雲端提供者](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jtvbfzk003t5jxi9ghi.png) Amazon Web Services (AWS)、Google Cloud Platform (GCP) 和 Microsoft Azure 等雲端平台提供了一系列 AI 和機器學習服務,這些服務抽象化了訓練和部署 AI 模型所需的大部分基礎架構。這些平台為機器學習模型訓練、部署和監控提供託管服務,以及可擴展以滿足任何人工智慧專案需求的大量運算資源。 9. 專門的人工智慧開發工具 -------------- 雖然我仍然更喜歡使用 SingleStore Notebook 功能,但我知道大多數人已經在使用 Jupyter Notebook 進行資料探索和分析。我有時會使用 Jupyter Notebooks,另一個更有趣的工具是 MLflow,它將幫助您完成端到端的 ML 工作流程。 ### Jupyter 筆記本 ![Jupyter筆記本](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/411i9cumaafb3un5viqi.png) 對於探索性資料分析、模型開發和文件編制,Jupyter Notebooks 是不可或缺的工具。它們允許開發人員建立和共享包含即時程式碼、方程式、視覺化和敘述文字的文件,使其成為協作人工智慧研究和開發的絕佳工具。 ### ML流 ![毫升流工具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1nabnjklq1e07x8kc1vr.png) [MLflow](https://mlflow.org/)是一個用於管理端對端機器學習生命週期的開源平台。它包括實驗追蹤、模型版本控制和部署等功能,使開發人員能夠追蹤和比較實驗、將模型打包成可重複的執行,以及管理跨多個環境的模型部署。 ### 最後的一些想法 人工智慧/機器學習領域正在像海洋一樣不斷發展。每天我們都會看到一種或另一種語言模型帶著許多期望首次亮相。有許多令人驚嘆的開發工具仍然可以包含在這個清單中,但從我個人的經驗來看,我相信這些工具是每個 AI/ML 工程師開始建立他們的 AI/ML 應用程式的良好開端。 讓我知道您目前在 AI/ML 領域最喜歡的工具是什麼。 --- 原文出處:https://dev.to/pavanbelagatti/my-favorite-devtools-to-build-aiml-applications-3c0c

從頭開始實作 JavaScript 概念

在本文中,我們透過從頭開始建立幾個關鍵元件來探索 JavaScript 的基本建構塊。當我們深入研究這些概念時,我們將應用一系列從基礎到複雜的技術,使這種探索對於 JavaScript 世界的新手和專業人士都很有價值。 大綱 ---- - [`memoize()`](#memoize) - [`Array.map()`](#arraymap) - [`Array.filter()`](#arrayfilter) - [`Array.reduce()`](#arrayreduce) - [`bind()`](#bind) - [`call()` 、 `apply()`](#callapply) - [`setInterval()`](#setinterval) - [`cloneDeep()`](#clonedeep) - [`debounce()`](#debounce) - [`throttle()`](#throttle) - [`Promise`](#promise) - \[ `EventEmitter` ) <a name="memoize"></a> `memoize()` ----------- ### 任務說明 重新建立`memoize`函數(來自“lodash”),該函數透過快取函數呼叫的結果來優化效能。透過傳回快取的結果而不是重新計算,可以確保使用相同參數的重複函數呼叫更快。 ### 執行 ``` function customSerializer(entity, cache = new WeakSet()) { if (typeof entity !== 'object' || entity === null) { return `${typeof entity}:${entity}`; } if (cache.has(entity)) { return 'CircularReference'; } cache.add(entity); let objKeys = Object.keys(entity).sort(); let keyRepresentations = objKeys.map(key => `${customSerializer(key, cache)}:${ customSerializer(entity[key], cache) }` ); if (Array.isArray(entity)) { return `Array:[${keyRepresentations.join(',')}]`; } return `Object:{${keyRepresentations.join(',')}}`; } function myMemoize(fn) { const cache = new Map(); return function memoized(...args) { const keyRep = args.map(arg => customSerializer(arg) ).join('-'); const key = `${typeof this}:${this}-${keyRep}`; if (cache.has(key)) { return cache.get(key); } else { const result = fn.apply(this, args); cache.set(key, result); return result; } }; } ``` ### 實施的關鍵面 1. **快取機制:**它使用`Map`物件`cache`來儲存函數呼叫的結果。選擇`Map`物件是因為其高效率的鍵值配對和檢索功能。 2. **Custom Serializer** : `customSerializer`函數將函數參數轉換為用作快取鍵的字串表示形式。此序列化考慮了基本類型、物件(包括巢狀物件)、陣列和循環參考。對於物件和陣列,它們的鍵經過排序以確保一致的字串表示形式,無論屬性聲明順序如何。 3. **序列化`this`** : `this`的值指的是函數所屬的物件。在 JavaScript 中,方法可以根據呼叫它們的物件(即呼叫它們的上下文)而有不同的行為。這是因為`this`提供了對上下文物件的屬性和方法的存取,並且其值可能會根據函數的呼叫方式而變化。 4. **循環引用**:當物件直接或透過其屬性間接引用自身時,就會發生循環引用。這可能發生在更複雜的資料結構中,例如,物件`A`包含對物件`B`的引用,而物件`B`則直接或間接引用物件`A` 。處理循環引用以避免無限循環至關重要。 5. **使用`WeakSet`進行自動垃圾收集**: `WeakSet`保留對其物件的「弱」引用,這表示如果沒有其他引用, `WeakSet`中物件的存在不會阻止該物件被垃圾收集。此行為在需要臨時追蹤物件存在而又不會不必要地延長其生命週期的情況下特別有用。由於`customSerializer`函數可能只需要在序列化過程中標記物件的存取,而不儲存額外的資料,因此使用`WeakSet`可以確保物件不會僅僅因為它們在集合中的存在而保持活動狀態,從而防止潛在的內存洩漏。 <a name="arraymap"></a> `Array.map()` ------------- ### 任務說明 重新建立`Array.map()` ,它將轉換函數作為參數。此轉換函數將在陣列的每個元素上執行,並採用三個參數:當前元素、目前元素的索引和陣列本身。 ### 實施的關鍵面 1. **記憶體預先分配**: `new Array(this.length)`用於建立預先確定大小的陣列,以優化記憶體分配並透過避免加入元素時動態調整大小來提高效能。 ### 執行 ``` Array.prototype.myMap = function(fn) { const result = new Array(this.length); for (let i = 0; i < this.length; i++) { result[i] = fn(this[i], i, this); } return result; } ``` <a name="arrayfilter"></a> `Array.filter()` ---------------- ### 任務說明 重新建立`Array.filter()` ,它將謂詞函數作為輸入,迭代呼叫它的陣列的元素,將謂詞應用於每個元素。它傳回一個新陣列,僅包含謂詞函數傳回`true`元素。 ### 實施的關鍵面 1. **動態記憶體分配**:它動態地將符合條件的元素加入到`filteredArray`中,從而在很少有元素通過謂詞函數的情況下使該方法更有效地使用記憶體。 ### 執行 ``` Array.prototype.myFilter = function(pred) { const filteredArray = []; for (let i = 0; i < this.length; i++) { if (pred(this[i], i, this)) { filteredArray.push(this[i]); } } return filteredArray; } ``` <a name="arrayreduce"></a> `Array.reduce()` ---------------- ### 任務說明 重新建立`Array.reduce()` ,它對陣列的每個元素執行`reducer`函數,從而產生單一輸出值。 `reducer`函數有四個參數:累加器、currentValue、currentIndex 和整個陣列。 ### 實施的關鍵面 1. **`initialValue` value** : `accumulator`和`startIndex`會根據是否將`initialValue`作為參數傳遞來初始化。如果提供了`initialValue` (意味著`arguments.length`至少為`2` ),則`accumulator`設定為此`initialValue` ,並且迭代從第0個元素開始。否則,如果未提供`initialValue` ,則將陣列本身的第 0 個元素用作`initialValue` 。 ### 執行 ``` Array.prototype.myReduce = function(callback, initialValue) { let accumulator = arguments.length >= 2 ? initialValue : this[0]; let startIndex = arguments.length >= 2 ? 0 : 1; for (let i = startIndex; i < this.length; i++) { accumulator = callback(accumulator, this[i], i, this); } return accumulator; } ``` <a name="bind"></a> `bind()` -------- ### 任務說明 重新建立`bind()`函數,該函數允許將物件以及預先指定的初始參數(如果有)作為呼叫原始函數的上下文傳遞。它還應該支援`new`運算符的使用,從而能夠建立新實例,同時維護正確的原型鏈。 ### 執行 ``` Function.prototype.mybind = function(context, ...bindArgs) { const self = this; const boundFunction = function(...callArgs) { const isNewOperatorUsed = new.target !== undefined; const thisContext = isNewOperatorUsed ? this : context; return self.apply(thisContext, bindArgs.concat(callArgs)); }; if (self.prototype) { boundFunction.prototype = Object.create(self.prototype); } return boundFunction; }; ``` ### 實施的關鍵面 1. **處理`new` Operator** :語句`const isNewOperatorUsed = new.target !== undefined;`檢查是否透過`new`運算子將`boundFunction`作為建構函數呼叫。如果使用`new`運算符,則`thisContext`將設定為新建立的物件 ( `this` ) 而不是提供的`context` ,確認實例化應使用新的上下文而不是綁定期間提供的上下文。 2. **原型保留**:為了維護原始函數的原型鏈, `mybind`有條件地將`boundFunction`的原型設定為繼承自`self.prototype`的新物件。此步驟確保從`boundFunction` (用作建構函數時)建立的實例正確地繼承原始函數原型的屬性。此機制保留了預期的繼承層次結構並維護instanceof 檢查。 ### 將`bind()`與`new`一起使用的範例 讓我們考慮一個簡單的建構函數,它建立代表汽車的物件: ``` function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } ``` 想像一下,我們常常創造「豐田」品牌的`Car`物件。為了讓這個過程更有效率,我們可以使用`bind`為Toyotas建立一個專門的建構函數,預先填入`make`參數: ``` // Creating a specialized Toyota constructor with 'Toyota' // as the pre-set 'make' const ToyotaConstructor = Car.bind(null, 'Toyota'); // Now, we can create Toyota car instances // without specifying 'make' const myCar = new ToyotaConstructor('Camry', 2020); // Output: Car { make: 'Toyota', model: 'Camry', year: 2020 } console.log(myCar); ``` <a name="callapply"></a> `call()` 、 `apply()` -------------------- ### 任務說明 重新建立`call()`和`apply()`函數,它們允許使用給定的 this 值和單獨提供的參數來呼叫函數。 ### 執行 ``` Function.prototype.myCall = function(context, ...args) { const fnSymbol = Symbol('fnSymbol'); context[fnSymbol] = this; const result = context[fnSymbol](...args); delete context[fnSymbol]; return result; }; Function.prototype.myApply = function(context, args) { const fnSymbol = Symbol('fnSymbol'); context[fnSymbol] = this; const result = context[fnSymbol](...args); delete context[fnSymbol]; return result; }; ``` ### 實施的關鍵面 1. **屬性命名的符號用法**:為了防止覆蓋上下文物件上潛在的現有屬性或由於名稱衝突而導致意外行為,使用唯一的`Symbol`作為屬性名稱。這確保了我們的臨時屬性不會幹擾上下文物件的原始屬性。 2. **執行後清理**:函數呼叫執行後,新增到上下文物件中的臨時屬性將被刪除。此清理步驟對於避免在上下文物件上留下修改後的狀態至關重要。 <a name="setinterval"></a> `setInterval()` --------------- ### 任務說明 使用`setTimeout`重新建立`setInterval` 。此函數應以指定的時間間隔重複呼叫提供的回呼函數。它會傳回一個函數,當呼叫該函數時,該函數會停止間隔。 ### 執行 ``` function mySetInterval(callback, interval) { let timerId; const repeater = () => { callback(); timerId = setTimeout(repeater, interval); }; repeater(); return () => { clearTimeout(timerId); }; } ``` ### 實施的關鍵面 1. **取消功能**: `mySetInterval`傳回的函數提供了一種簡單直接的方法來取消正在進行的間隔,而無需在函數範圍之外公開或管理計時器 ID。 <a name="clonedeep"></a> `cloneDeep()` ------------- ### 任務說明 重新建立執行給定輸入的深度複製的`cloneDeep`函數(來自“lodash”)。該函數應該能夠複製複雜的資料結構,包括物件、陣列、映射、集合、日期和正規表示式,並保持每個元素的結構和類型完整性。 ### 執行 ``` function myCloneDeep(entity, map = new WeakMap()) { if (entity === null || typeof entity !== 'object') { return entity; } if (map.has(entity)) { return map.get(entity); } let cloned; switch (true) { case Array.isArray(entity): cloned = []; map.set(entity, cloned); cloned = entity.map(item => myCloneDeep(item, map)); break; case entity instanceof Date: cloned = new Date(entity.getTime()); break; case entity instanceof Map: cloned = new Map(Array.from(entity.entries(), ([key, val]) => [myCloneDeep(key, map), myCloneDeep(val, map)])); break; case entity instanceof Set: cloned = new Set(Array.from(entity.values(), val => myCloneDeep(val, map))); break; case entity instanceof RegExp: cloned = new RegExp(entity.source, entity.flags); break; default: cloned = Object.create( Object.getPrototypeOf(entity)); map.set(entity, cloned); for (let key in entity) { if (entity.hasOwnProperty(key)) { cloned[key] = myCloneDeep(entity[key], map); } } } return cloned; } ``` ### 實施的關鍵面 1. **循環引用處理**:利用`WeakMap`來追蹤已存取的物件。如果遇到已經克隆的物件,則返回先前克隆的物件,有效處理循環參考並防止堆疊溢位錯誤。 2. **特殊物件的處理**:區分幾種物件類型( `Array` 、 `Date` 、 `Map` 、 `Sets` 、 `RegExp` ),以確保每種類型都被適當地克隆,並保留其特定特徵。 ``` - **`Array`**: Recursively clones each element, ensuring deep cloning. ``` ``` - **`Date`**: Copies the date using its numeric value (timestamp). ``` ``` - **Maps and Sets**: Constructs a new instance, recursively cloning each entry (for `Map`) or value (for `Set`). ``` ``` - **`RegExp`**: Clones by creating a new instance with the source and flags of the original. ``` 3. **物件屬性的複製**:當輸入是普通物件時,它會建立一個與原始物件具有相同原型的物件,然後遞歸地複製每個自己的屬性,在保持原型鏈的同時確保深度克隆。 4. **效率和性能**:利用`WeakMap`進行記憶,有效處理具有重複引用和循環的複雜大型結構,透過避免冗餘克隆來確保最佳性能。 <a name="debounce"></a> `debounce()` ------------ ### 任務說明 重新建立`debounce`函數(來自“lodash”),它允許限制給定回調函數觸發的頻率。當在短時間內重複呼叫時,在指定的延遲後僅執行最後一次呼叫。 ``` function myDebounce(func, delay) { let timerId; const debounced = function(...args) { clearTimeout(timerId); timerId = setTimeout(() => { func.apply(this, args); }, delay); }; debounced.cancel = function() { clearTimeout(timerId); timerId = null; }; debounced.flush = function() { clearTimeout(timerId); func.apply(this, arguments); timerId = null; }; return debounced; } ``` ### 實施的關鍵面 1. **取消功能**:引入`.cancel`方法使外部控制能夠取消去抖函數的任何暫停執行。這增加了靈活性,允許響應特定事件或條件而取消去抖功能。 2. **透過 Flush 立即執行**: `.flush`方法允許立即執行去抖函數,而不考慮延遲。這在需要確保立即應用去抖函數的效果的情況下非常有用,例如,在卸載元件或完成互動之前。 <a name="throttle"></a> `throttle()` ------------ ### 任務說明 重新建立`throttle`函數(來自“lodash”),它確保給定的回調函數在每個指定的時間間隔內最多只呼叫一次(在我們的例子中是在開始時)。與去抖動不同,限制保證函數會定期執行,確保進行更新,儘管更新速度是受控的。 ### 執行 ``` function myThrottle(func, timeout) { let timerId = null; const throttled = function(...args) { if (timerId === null) { func.apply(this, args) timerId = setTimeout(() => { timerId = null; }, timeout) } } throttled.cancel = function() { clearTimeout(timerId); timerId = null; }; return throttled; } ``` ### 實施的關鍵面 1. **取消功能**:引入`.cancel`方法可以清除節流計時器的任何計劃重置。這在清理階段非常有用,例如 UI 庫/框架中的元件卸載,以防止過時的執行並有效管理資源。 <a name="promise"></a> `Promise` --------- ### 任務說明 重新建立`Promise`類別。它是為非同步程式設計的構造,允許暫停程式碼的執行,直到非同步進程完成。從本質上講,承諾代表了在其建立時不一定已知的值的代理。它允許您將處理程序與非同步操作的最終成功值或失敗原因相關聯。這使得非同步方法可以像同步方法一樣傳回值:非同步方法不是立即傳回最終值,而是傳回一個在未來某個時刻提供該值的承諾。 `Promise`包含處理已完成和拒絕狀態的方法( `then` 、 `catch` ),以及無論結果如何都執行程式碼的方法( `finally` )。 ``` class MyPromise { constructor(executor) { ... } then(onFulfilled, onRejected) { ... } catch(onRejected) { ... } finally(callback) { ... } } ``` ### `constructor`實現 ``` constructor(executor) { this.state = 'pending'; this.value = undefined; this.reason = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; this.onFulfilledCallbacks.forEach(fn => fn()); } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; this.onRejectedCallbacks.forEach(fn => fn()); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } ``` ### `constructor`實現的關鍵方面 1. **狀態管理**:以「待處理」狀態初始化。解決時切換為“已完成”,被拒絕時切換為“拒絕”。 2. **值和原因**:保存承諾的最終結果( `value` )或拒絕的原因( `reason` )。 - **處理非同步**:接受包含非同步操作的`executor`函數。 `executor`採用兩個函數, `resolve`和`reject` ,當呼叫它們時,將promise轉換到對應的狀態。 3. **回呼陣列**:維護回呼佇列( `onFulfilledCallbacks` 、 `onRejectedCallbacks` ),以用於等待解決或拒絕承諾的延遲操作。 ### `.then`實施 ``` resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError( 'Chaining cycle detected for promise')); } if (x instanceof MyPromise) { x.then(resolve, reject); } else { resolve(x); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }; let promise2 = new MyPromise((resolve, reject) => { if (this.state === 'fulfilled') { setTimeout(() => { try { let x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); } else if (this.state === 'rejected') { setTimeout(() => { try { let x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); } else if (this.state === 'pending') { this.onFulfilledCallbacks.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { let x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); }); } }); return promise2; } ``` ### `.then`實施的關鍵方面 1. **預設處理程序**:將非函數處理程序轉換為標識函數(用於實現)或拋出程序(用於拒絕),以確保承諾鏈中的正確轉發和錯誤處理。 2. **Promise 連結**: `then`方法允許連結 Promise,從而實現順序非同步操作。它會建立一個新的 Promise ( `promise2` ),該 Promise 取決於傳遞給它的回呼函數 ( `onFulfilled` 、 `onRejected` ) 的結果。 3. **處理解決方案和拒絕**:僅在當前承諾解決(履行或拒絕)後才會呼叫所提供的回調。每個回呼的結果 ( `x` ) 可能是一個值或另一個 Promise,決定了`promise2`的解析。 4. **防止連結循環**: `resolvePromise`函數檢查`promise2`是否與結果 ( `x` ) 相同,避免 Promise 等待自身的循環,從而導致`TypeError` 。 5. **支援 MyPromise 和 Non-Promise 值**:如果結果 ( `x` ) 是`MyPromise`的實例, `then`使用其解析或拒絕來解決`promise2` 。此功能支援基於 Promise 的操作的無縫集成,無論是來自`MyPromise`實例還是本機 JavaScript Promise,假設它們具有相似的行為。對於非 Promise 值,或當`onFulfilled`或`onRejected`只是傳回一個值時, `promise2`將使用該值進行解析,從而在 Promise 鏈中實現簡單的轉換或分支邏輯。 6. **非同步執行保證**:透過使用`setTimeout`延遲`onFulfilled`和`onRejected`的執行, `then`確保非同步為。此延遲保持一致的執行順序,確保`onFulfilled`和`onRejected`在執行堆疊清除後呼叫。 7. **錯誤處理**:如果`onFulfilled`或`onRejected`內發生異常, `promise2`會因錯誤而被拒絕,從而允許錯誤處理通過 Promise 鏈傳播。 ### `catch`並`finally`實現 ``` static resolve(value) { if (value instanceof MyPromise) { return value; } return new MyPromise((resolve, reject) => resolve(value)); } catch(onRejected) { return this.then(null, onRejected); } finally(callback) { return this.then( value => MyPromise.resolve(callback()) .then(() => value), reason => MyPromise.resolve(callback()) .then(() => { throw reason; }) ); } ``` ### `.catch`實施的關鍵面向: 1. **簡化的錯誤處理:** `.catch`方法是`.then(null, onRejected)`的簡寫,專門專注於處理拒絕場景。當只需要拒絕處理程序時,它允許更清晰的語法,從而提高程式碼的可讀性和可維護性。 2. **Promise Chaining 支援:**由於它在內部委託給`.then` ,所以`.catch`返回一個新的 Promise,從而保持 Promise 鏈功能。這允許在錯誤恢復或透過重新拋出或返回新的被拒絕的承諾傳播錯誤後繼續進行鏈操作。 3. **錯誤傳播:**如果提供了`onRejected`並且執行時沒有錯誤,則傳回的 Promise 將使用`onRejected`的傳回值進行解析,從而有效地允許 Promise 鏈中的錯誤復原。如果`onRejected`拋出錯誤或傳回被拒絕的 Promise,則錯誤會沿著鏈傳播。 ### `.finally`實現的關鍵面向: 1. **始終執行:** `.finally`方法確保執行提供的`callback` ,無論 Promise 是履行還是拒絕。這對於需要在非同步操作之後發生的清理操作特別有用,與其結果無關。 2. **傳回值保留:**雖然`.finally`中的`callback`不接收任何參數(與`.then`或`.catch`不同),但 Promise 的原始履行值或拒絕原因將被保留並透過鏈傳遞。從`.finally`傳回的 Promise 會以相同的值或原因被解析或拒絕,除非`callback`本身導致被拒絕的 Promise。 3. **錯誤處理與傳播:**如果`callback`執行成功, `.finally`傳回的 Promise 將按照與原始 Promise 相同的方式進行結算。但是,如果`callback`拋出錯誤或返回被拒絕的 Promise,則從`.finally`返回的 Promise 會因這個新錯誤而被拒絕,從而允許錯誤攔截並更改 Promise 鏈中的拒絕原因。 <a name="eventemitter"></a> `EventEmitter` -------------- ### 任務說明 重新建立`EventEmitter`類,該類別允許實現觀察者模式,使物件(稱為「發射器」)能夠發出命名事件,從而導致呼叫先前註冊的偵聽器(或「處理程序」)。這是 Node.js 中用於處理非同步事件的關鍵元件,廣泛用於發出訊號以及管理應用程式狀態和行為。實作自訂`EventEmitter`涉及建立用於註冊事件偵聽器、觸發事件和刪除偵聽器的方法。 ``` class MyEventEmitter { constructor() { this.events = {}; } on(eventName, listener) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(listener); } once(eventName, listener) { const onceWrapper = (...args) => { listener.apply(this, args); this.off(eventName, onceWrapper); }; this.on(eventName, onceWrapper); } emit(eventName, ...args) { const listeners = this.events[eventName]; if (listeners && listeners.length) { listeners.forEach((listener) => { listener.apply(this, args); }); } } off(eventName, listenerToRemove) { if (!this.events[eventName]) { return; } const filterListeners = (listener) => listener !== listenerToRemove; this.events[eventName] = this.events[eventName].filter(filterListeners); } } ``` ### `EventEmitter`實現的關鍵面 1. **EventListener Registration `.on` :**將偵聽器函數新增至指定事件的偵聽器陣列中,如果該事件名稱尚不存在則建立一個新陣列。 2. **一次性事件偵聽器`.once` :**註冊一個偵聽器,該偵聽器在呼叫一次後會自行刪除。它將原始偵聽器包裝在一個函數 ( `onceWrapper` ) 中,該函數也會在執行後刪除包裝器,確保偵聽器僅觸發一次。 3. **發出事件`.emit` :**觸發事件,使用提供的參數呼叫所有已註冊的偵聽器。它將參數應用於每個偵聽器函數,從而允許將資料傳遞給偵聽器。 4. **刪除事件偵聽器`.off` :**從事件偵聽器陣列中刪除特定偵聽器。如果事件在刪除後沒有偵聽器,則可以將其保留為空陣列或可選地進一步清理(此實作中未顯示)。 --- 原文出處:https://dev.to/antonzo/implementing-javascript-concepts-from-scratch-4623

每個 Web 開發人員都應該知道的 10 個 JavaScript 網站

介紹: --- 身為 Web 開發人員,掌握 JavaScript 對於建立動態和互動式 Web 體驗至關重要。為了磨練您的技能並隨時了解最新趨勢和工具,這裡有 10 個您應該了解的 JavaScript 網站。 1. MDN Web 文件(Mozilla 開發者網路): ----------------------------- (https://developer.mozilla.org/) MDN Web Docs 是有關 JavaScript 的綜合文件的首選資源。從初學者教程到高級參考,它涵蓋了您需要了解的有關 JavaScript 的所有內容,包括語法、方法和 API。 2. JavaScript.info: ------------------- (https://javascript.info/) JavaScript.info 提供有關 JavaScript 概念的深入教程和文章,範圍從基礎到高級主題。無論您是學習基礎知識還是探索現代 JavaScript 功能,這個網站都能滿足您的需求。 3. 雄辯的 JavaScript: ------------------ (https://eloquentjavascript.net/) Eloquent JavaScript 是一本線上書籍,以清晰且引人入勝的方式教授 JavaScript 程式設計。透過互動式程式碼範例和練習,它非常適合希望加深對語言理解的初學者和經驗豐富的開發人員。 4.JSFiddle: ----------- (https://jsfiddle.net/) JSFiddle 是一個線上程式碼編輯器,可讓您即時試驗 HTML、CSS 和 JavaScript 程式碼。它是測試想法、除錯程式碼以及與開發人員社區中的其他人共享程式碼片段的寶貴工具。 5. 堆疊溢位: -------- (https://stackoverflow.com/questions/tagged/javascript) Stack Overflow 是一個問答網站,開發人員可以在其中尋求協助、分享知識並就 JavaScript 相關問題進行協作。它是常見編碼問題解決方案的寶庫,也是向經驗豐富的開發人員學習的好地方。 6. 程式碼學院: -------- (https://www.codecademy.com/learn/introduction-to-javascript) Codecademy 提供互動式 JavaScript 課程,引導您了解語言的基礎知識以及非同步程式設計和 API 等更高階的主題。透過動手做專案和測驗,這是按照自己的進度學習 JavaScript 的有效方法。 7. JavaScript 周刊: ----------------- (https://javascriptweekly.com/) JavaScript Weekly 是一份時事通訊,精選 JavaScript 社群的最新新聞、文章和教學。隨時了解塑造 JavaScript 生態系統的最新函式庫、框架和工具。 8. 開發文件: -------- (https://devdocs.io/javascript/) DevDocs 提供對 JavaScript 和其他程式語言文件的快速、離線存取。其簡潔的介面和強大的搜尋功能可讓您輕鬆找到有關 JavaScript API、方法和瀏覽器相容性的資訊。 9.你不懂JS: -------- (https://github.com/getify/You-Dont-Know-JS) You Dont Know JS 是一系列深入探討 JavaScript 內部運作方式的書籍。這些書由 Kyle Simpson 撰寫,探討了範圍、閉包和原型等主題,幫助您掌握 JavaScript 更複雜的概念。 10.JavaScript花園: ---------------- (https://bonsaiden.github.io/JavaScript-Garden/) JavaScript Garden 是有關 JavaScript 陷阱、奇怪之處和最佳實踐的文件集合。它可以幫助開發人員了解語言的棘手方面,並編寫更清晰、更易於維護的程式碼。 結論: --- 透過這 10 個可供您使用的 JavaScript 網站,您將能夠存取豐富的資源、教學和工具來增強您的 JavaScript 技能並成為更熟練的 Web 開發人員。無論您是初學者還是經驗豐富的程式設計師,探索這些網站都將加深您對 JavaScript 的理解,並使您能夠建立更動態和互動的 Web 應用程式。 --- 原文出處:https://dev.to/webdev-mohdamir/10-javascript-sites-every-web-developer-should-know-247b

100% AI 驅動的 Web 開發工作流程,與 Devin 一樣出色:MAGE x Aider

長話短說 ---- [Devin](https://www.youtube.com/watch?v=fjHtjT7GO1c) ,這位自稱「第一個」完全自主的軟體工程師剛剛出現,並引起了很多關注。 它尚未公開,但透過幾個開源工具,您現在可以獲得類似的 Web 開發體驗,而且成本可能只是一小部分。 {% 嵌入 https://www.youtube.com/watch?v=DXunbNBpgZg %} 在其 CLI 中使用[Wasp 的 AI 功能](https://wasp.sh),您可以透過簡單的提示產生全端 Web 應用程式程式碼庫。然後,在[Aider](https://aider.chat)的幫助下透過加入功能和除錯來迭代它。 在這兩個人工智慧代理的幫助下,您可以增強全端應用程式的開發,而無需編寫一行程式碼(如果您不想)。 請繼續閱讀有關如何開始的詳細說明! --- ![星星](https://res.cloudinary.com/practicaldev/image/fetch/s--2jk6M804--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3a8gkl9fcs0a8rl4zsq.gif) 順便說一句,Wasp 是建立全端 Web 應用程式的最快方法,而且它也恰好內建了 AI 生成 - 而且它是免費和開源的! 您可以透過[在 GitHub 上為我們的儲存庫加註星標](https://www.github.com/wasp-lang/wasp)來支持我們。它幫助我們建立更多東西並創造更多像這樣很酷的內容🙏 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hk4emh8rr8q4j35sxud.gif) {% cta https://www.github.com/wasp-lang/wasp %} 連 Ron 也會在 GitHub 上為 Wasp 加註星標 🤩 {% endcta %} --- 德文到底是誰? ------- 您可能已經看到和聽過圍繞 Devin 的炒作,他自稱是「第一個」完全自主的軟體工程師。 如果沒有,請觀看下面的宣傳影片: {% 嵌入 https://www.youtube.com/watch?v=fjHtjT7GO1c %} 儘管 Devin 絕對不是同類中的第一個人工智慧編碼助手,但它的推出仍然引起了許多人的注意。簡而言之,這就是 Devin 所做的: - 接受提示 - 制定逐步計劃 - 在具有程式碼編輯器、終端、瀏覽器和聊天介面的時尚 UI 中展示其工作 - 能夠迭代現有的程式碼庫 儘管有其他類似的人工智慧編碼代理,其中一些像 GPT-Pilot 是開源的,但 Devin 使用內建所有必要工具的流暢 UI 使其脫穎而出。此外,它能夠迭代現有程式碼庫,這使其與大多數類似工具(Aider 除外)區分開來。 那麼,德文真的那麼令人印象深刻嗎? 是和不是。正如著名 AI YouTuber [Matthew Berman](https://www.youtube.com/@matthew_berman)在他關於 Devin 的影片中指出的那樣,Devin 最令人印象深刻的事情可能是他們的發布的成功。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5mrfmizjkew07qrd8qw.png) 但伯曼也指出了一些與他們的行銷主張不一致的地方: 1. Devin 絕對不是同類中的第一個。 [Mage](https://useMage.ai) 、 [Aider](https://aider.chat)和[GPT-Pilot](https://github.com/Pythagora-io/gpt-pilot)等類似工具已經存在。 2. 他們對效能基準的比較(如上圖所示)並不能真正被認真對待,因為Devin 是一個可以迭代和執行多個任務的代理,而它所比較的 LLM,如GPT-4,只是「零樣本」 (即他們嘗試一次才能得到正確的答案)。為了公平比較,Devin 應該與其他代理人進行比較,例如 GPT-Pilot、MetaGPT、Mage 等。 另外,Devin 實際上是建立在 OpenAI 的 GPT-4 API 之上的。所以,是的,他們在其之上建置的一些工具非常令人印象深刻,並且將加快編碼工作流程,但底層模型與像您和我這樣的開發人員可以存取的東西完全相同。 這意味著,透過結合幾個可用的開源工具,您現在可以獲得與 Devin 非常相似的結果,而無需等待早期預覽存取,並且成本可能只是其一小部分。 現在就讓我們來看看吧! Wasp AI x Aider — 全端 Web 應用程式的開源「Devin」替代品 ------------------------------------------ 幾個月前,我們發布了[Mage](https://usemage.ai) ( **Magic** **App** **Generator** ),這是一個實驗平台,用於透過簡單的提示生成全端 Web 應用程式。自發布以來,Mage 已被用來產生超過 40k 個應用程式! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zxzoa3be0u5qghqmvpd8.png) Mage 使用[Wasp(一個全端 React、Node 和 Prisma 框架)](https://wasp.sh)來產生比大多數編碼助理更好的全端應用程式。到底是為什麼呢?這是因為 Wasp 使用聲明性設定檔來定義應用程式的功能。 這個設定檔為Wasp 的編譯器提供了將客戶端和伺服器程式碼「黏合」在一起所需的指令,並處理一堆樣板程式碼,因此您和AI 都不必處理諸如身份驗證、路由、端點、伺服器之類的編碼配置等 ``` // wasp config file app TodoApp { wasp: { version: "^0.13.0" }, auth: { userEntity: User, methods: { usernameAndPassword: {} }, } } entity User {=psl id Int @id @default(autoincrement()) tasks Task[] psl=} // rest of the config file... ``` 查看上面的範例,了解如何使用 Wasp 編寫全端 Auth。很容易,對吧?現在想像一下,對於 Mage 或任何其他人工智慧編碼助理來說,編寫 Wasp 程式碼是多麼容易。 另外,由於 Wasp 設定檔的結構已經類似於一組指令,因此它允許 Mage 以與 Devin 類似的方式建立計劃。 這就是 Mage 真正的閃光點,它可以快速且廉價地建立功能齊全的全端 Web 應用程式原型。 Mage 的唯一缺點是它在終端中不可用,而且您無法進一步迭代生成的程式碼庫。 現在情況改變了。隨著新的 Wasp 更新,Mage 的所有功能都被打包到 CLI 中。您只需[安裝 Wasp](https://wasp-lang.dev/docs/quick-start)並執行`wasp new` ,您就可以透過命令列提示產生一個新的全端應用程式! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uthik90clhytebvyndh0.png) 之後,您可以使用[Aider](https://aider.chat) ,這是一個命令列工具,可讓您與 GPT-3.5/GPT-4 進行配對編程,以迭代生成的程式碼庫並建立一系列很酷的新功能。 還不相信嗎?觀看這個很酷的宣傳影片,向您展示這一切是如何運作的: {% 嵌入 https://www.youtube.com/watch?v=DXunbNBpgZg %} 如果這看起來很酷,並且您想在這些工具的幫助下開始建立自己的全端 Web 應用程式,請按照以下說明進行操作! CLI 中的 Wasp AI -------------- [安裝 Wasp](https://wasp-lang.dev/docs/quick-start)後,前往終端並執行`wasp new` 這樣做將為您提供一個可供選擇的全端入門模板清單。你會想要: - 從選項清單中選擇`[5] ai-generated` - 輸入您的應用程式的描述 - 選擇您想要用於這一代的 GPT 模型和創造力水平 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iyyrvrjg4ykvftutp5k2.png) 使用這些生成設定可能會產生不同的結果,因此,如果生成的應用程式不是您第一次尋找的內容,請調整它們並重試。 並且不必太擔心透過 OpenAI API 產生的成本。由於 Wasp 利用 DSL 並為我們管理大量樣板文件,因此它顯著減少了 GPT 必須產生的程式碼量。 例如,當我們混合使用 GPT4 和 GPT3.5(預設選項)時,一個具有 Wasp AI 的應用程式通常消耗大約 25k 到 60k 代幣,每個應用程式大約消耗**0.1 到 0.2 美元**!如果我們只使用 GPT4 來執行它,那麼成本是 10 倍,這意味著它將花費大約**1 到 2 美元**。這仍然比大多數其他 AI 編碼代理便宜得多,後者每代的成本通常約為 15-40 美元。 🤯 哦,「gpt-4-1106-preview」指的是 OpenAI 的新 GPT-4-turbo 模型。因此,它比完全使用 GPT-4 更快、更便宜。 Wasp AI(和[Mage](https://usemage.ai) )使用 GPT-4 進行規劃 + GPT-3.5-turbo 進行程式碼生成的組合,我們發現它對於簡單的應用程式來說效果出奇的好。如果您的目標是複雜的應用程式,我們建議完全使用 GPT-4,因為它能夠更好地處理更高的複雜性。請注意,GPT-4 將需要更長的時間。 繼續與 AI 迭代…der ------------- 在 Mage 的初始版本中,我們收到了很多問題,詢問是否有“除錯助手”,或者在初始輸出後繼續使用 AI 生成更多功能的方法。 雖然 Wasp AI 無法做到這一點,但我們開始探索其他具有除錯功能的 AI 編碼助手,最終我們非常喜歡[Aider 的](https://aider.chat/)工作流程和效能。另外,除了尚未向公眾發布的 Devin 之外,Aider 是目前唯一允許您迭代現有程式碼庫的 AI 編碼工具。 **所以,這使得 Wasp AI + Aider 成為完美的組合!** --- ![星星](https://res.cloudinary.com/practicaldev/image/fetch/s--2jk6M804--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3a8gkl9fcs0a8rl4zsq.gif) 順便說一句,Wasp 是免費且開源的,所以如果您喜歡我們正在做的事情,請考慮[在 Github 上給我們一顆星](https://github.com/wasp-lang/wasp)! ![黃蜂](https://res.cloudinary.com/practicaldev/image/fetch/s--5pwnEx10--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lz3ok1dpfkscsoo0n2om.gif) {% cta https://www.github.com/wasp-lang/wasp %} ⭐️ 丟黃蜂一顆星星 🙏 {% endcta %} --- 使用 Wasp AI 產生全端應用程式後,您可以透過 Aider 使用自然語言來產生新功能或偵錯目前程式碼中的問題。 就是這樣: 1. 安裝[幫助](https://aider.chat) ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avh771m902u6ukkbd1p5.png) 2. 在 Wasp 專案目錄中的命令列中執行`aider` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ut16cyi6tlouuk9529tb.png) 3. `/add`您希望 Aider 使用的文件 4. 告訴 Aider 你想要它做什麼,例如在表單中加入“小睡次數”字段 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/af0vm9ngfilbgj9170ik.png) 5. 然後,Aider 將規劃一個行動方案,並將這些變更作為 git 提交應用程式。如果您不喜歡更改,請執行`/undo`撤銷提交 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4t0w7txe4xjsealfczke.png) 6. 如果您在嘗試使用`wasp start`執行程式碼時遇到錯誤,請將錯誤複製並貼上到聊天中,讓 Aider 為您解決。確保您已將錯誤引用的文件新增至聊天(請參閱步驟 3)! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u8nc9sty41xbgrm7xwfr.png) 7. 如果您在使用 Aider 時需要更多幫助,請查看他們的[網站](https://aider.chat)或在 Aider 中執行`/help`以獲取命令列表 未來就在這裡 ------ 透過[Wasp AI](https://wasp.sh) ,我們最終將 Mage 的 AI 輔助全端應用腳手架能力加入到 Wasp 的 CLI 中。利用 GPT-4 和其他 OpenAI 模型的強大功能,用它來啟動您的下一個全端應用程式創意。 如果您想在 AI 幫助下繼續產生功能或直接從終端進行偵錯,請使用我們上面概述的 Aider 來保持流程繼續進行。 編碼的未來確實就在這裡。嘗試一下,讓我們知道您的想法! --- 原文出處:https://dev.to/wasp/a-100-ai-driven-workflow-thats-probably-as-good-as-devin-4c67

JavaScript 的 25 個不明顯的特性

通常,作為開發人員,我們會編寫類似類型的程式碼,陷入雖然舒適但有時感覺很平凡的模式。 然而,JavaScript 的世界是廣闊的,充滿了高級功能,當發現和使用這些功能時,可以將我們的開發工作變得更加令人興奮和充實。 在本指南中,我們將揭曉 25 個高級 JavaScript 功能,這些功能不僅能揭示這些隱藏的瑰寶,還能將您對 JavaScript 的掌握提升到前所未有的水平。 讓我們一起踏上這段發現之旅,將 JavaScript 的高級功能整合到我們的編碼庫中,以建立更有效率、更優雅、更強大的應用程式。是時候為我們的開發任務注入新的樂趣和創造力了。 1 — 迴圈和區塊語句的標籤 -------------- JavaScript 允許標記迴圈和區塊語句,從而可以使用`break`和`continue`進行精確控制。 ``` outerLoop: for (let i = 0; i < 5; i++) { innerLoop: for (let j = 0; j < 5; j++) { if (i === 2 && j === 2) break outerLoop; console.log(`i=${i}, j=${j}`); } } ``` 2 - 逗號運算符 --------- 逗號運算子允許按序列計算多個表達式,並傳回最後一個表達式的結果。 ``` let a = (1, 2, 3); // a = 3 ``` 3 — 字串格式化以外的標記範本文字 ------------------ 除了建立字串之外,標記範本還可用於 DSL(域特定語言)、清理使用者輸入或本地化。 ``` function htmlEscape(strings, ...values) { // Example implementation } ``` 4 — 區塊內的函數聲明 ------------ 儘管不推薦,但 JavaScript 允許在區塊內聲明函數,這可能會導致非嚴格模式下的不同行為。 ``` if (true) { function test() { return "Yes"; } } else { function test() { return "No"; } } test(); // Behavior varies depending on the environment ``` 5 — 無效運算符 --------- `void`運算子計算任何表達式,然後傳回未定義的值,這對於 JavaScript 的超連結很有用。 ``` void (0); // returns undefined ``` 6 — 用於快速數學的位元運算符 ---------------- 位運算符,例如`|`和`&` ,可以更快地執行一些數學運算,但會犧牲可讀性。 ``` let floor = 5.95 | 0; // Fast way to do Math.floor(5.95) ``` 7 — with 處理物件的語句 ---------------- `with`語句擴展了區塊的作用域鏈,讓您可以編寫更短的程式碼。但是,出於可讀性和效能方面的考慮,不建議這樣做。 ``` with(document.getElementById("myDiv").style) { background = "black"; color = "white"; } ``` [![Christian Heilmann 的 JavaScript 開發技能分享課程](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h758ymfla96s5md0vyf3.png)](https://skillshare.eqcm.net/QyLx6z) 與 Christian Heilmann 一起提高您的 JavaScript 技能 - 從今天開始編寫更乾淨、更快、更好的程式碼! 8 — 自動分號插入 (ASI) ---------------- JavaScript 嘗試修復缺少的分號,但依賴它可能會導致意外結果。 ``` let x = 1 let y = 2 [x, y] = [y, x] // Without proper semicolons, this could fail ``` 9 — 在屬性檢查操作員中 ------------- 檢查物件是否具有屬性,而無需直接存取其值。 ``` "toString" in {}; // true ``` 10——instanceof 與 typeof ----------------------- `instanceof`檢查原型鏈,而`typeof`傳回一個字串,指示未計算的操作數的類型。 ``` function Person() {} let person = new Person(); console.log(person instanceof Person); // true console.log(typeof person); // "object" ``` 11 — ES6 中的區塊級函數 ---------------- [ES6](https://www.webdevstory.com/mastering-es6-for-react/)允許函數具有區塊作用域,類似`let`和`const` 。 ``` { function test() { return "block scoped"; } } console.log(typeof test); // "function" in non-strict mode, "undefined" in strict mode ``` 12 — 偵錯器語句 ---------- 使用`debugger`語句暫停執行並開啟偵錯器。 ``` function problematicFunction() { debugger; // Execution pauses here if the developer tools are open } ``` **13 —**用於動態程式碼執行的`eval()` -------------------------- `eval`將字串作為 JavaScript 程式碼執行,但會帶來重大的安全性和效能影響。 ``` eval("let a = 1; console.log(a);"); // 1 ``` [![InMotion Hosting 促銷虛擬主機計劃](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vevir51wi5coo4gtq3db.png)](https://partners.inmotionhosting.com/k0EPWv) 利用 InMotion Hosting 的一系列計劃(從共享伺服器到 VPS 以及專用伺服器)為您的專案找到合適的託管解決方案。 **14 — 非標準**`__proto__`屬性 ------------------------- 雖然`__proto__`被廣泛支持用於設定物件的原型,但它是非標準的。請改用`Object.getPrototypeOf()`和`Object.setPrototypeOf()` 。 ``` let obj = {}; obj.__proto__ = Array.prototype; // Not recommended ``` 15 — document.write() 用於直接文件編輯 ------------------------------ `document.write()`直接寫入 HTML 文件,但使用它可能會產生負面影響,特別是同步載入外部腳本。 ``` document.write("<h1>Hello World!</h1>"); ``` 16 — 鍊式分配 --------- JavaScript 允許鍊式賦值,它可以在一個語句中將單一值指派給多個變數。 ``` let a, b, c; a = b = c = 5; // Sets all three variables to the value of 5 ``` 17 — 屬性存在的 in 運算符 ----------------- `in`運算子檢查屬性是否存在於物件中,而不存取屬性值。 ``` const car = { make: 'Toyota', model: 'Corolla' }; console.log('make' in car); // true ``` 18 — 物件屬性簡寫 ----------- 為物件指派屬性時,如果屬性名稱與變數名稱相同,則可以使用簡寫。 ``` const name = 'Alice'; const age = 25; const person = { name, age }; ``` 19 — 預設參數值和解構組合 --------------- 您可以將預設參數值與函數參數中的解構結合起來,以獲得更具可讀性和更靈活的函數定義。 ``` function createPerson({ name = 'Anonymous', age = 0 } = {}) { console.log(`Name: ${name}, Age: ${age}`); } createPerson({ name: 'Alice' }); // Name: Alice, Age: 0 createPerson(); // Name: Anonymous, Age: 0 ``` **20 — 使用**`Array.fill()`初始化陣列 ------------------------------ 使用`fill()`方法使用特定值快速初始化陣列。 ``` const initialArray = new Array(5).fill(0); // Creates an array [0, 0, 0, 0, 0] ``` [![符合人體工學的工作空間設置,辦公桌上放置一台筆記型電腦,由 LED 檯燈照明,35.4 英寸的亮度為 500 勒克斯,周圍擺滿了書籍和辦公用品。](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ly6b54e50pprze3p6lc9.jpg)](https://amzn.to/3VhQFae) 利用可調式 LED 照明優化您的工作空間,提高工作效率和舒適度,為專注的工作會議創造理想的環境。 **21 —** `Array.includes()`用於存在檢查 --------------------------------- 使用`includes()`方法可以輕鬆檢查陣列中是否存在元素,這比使用`indexOf()`更具可讀性。 ``` const fruits = ['apple', 'banana', 'mango']; console.log(fruits.includes('banana')); // true ``` 22 — 解構別名 --------- `destructuring`物件時,可以使用別名將屬性指派給具有不同名稱的變數。 ``` const obj = { x: 1, y: 2 }; const { x: newX, y: newY } = obj; console.log(newX); // 1 ``` 23 — 預設值的空合併運算符 --------------- 使用`??`僅在處理`null`或`undefined`時提供預設值,而不是其他`falsy`值,例如 ``` const count = 0; console.log(count ?? 10); // 0, because count is not null or undefined ``` 24 — 動態函數名稱 ----------- 使用物件字面量中的計算屬性名稱建立具有動態名稱的函數。 ``` const dynamicName = 'func'; const obj = { [dynamicName]() { return 'Dynamic Function Name!'; } }; console.log(obj.func()); // "Dynamic Function Name!" ``` 25 — 私有類別字段 ----------- 使用 hash `#`前綴定義類別中的私有字段,該字段無法從類別外部存取。 ``` class Counter { #count = 0; increment() { this.#count++; } getCount() { return this.#count; } } ``` 簡單總結 --- 當我們結束 25 個 JavaScript 高階功能的探索時,JavaScript 的函式庫既龐大又強大。 我們深入研究的每個功能都為解決編碼挑戰開闢了新途徑,類似於在我們的工具包中加入創新工具。 這不僅增強了我們創造性、有效率地制定解決方案的能力,而且還強調了 JavaScript 的動態多功能性。 這些進階功能凸顯了持續學習在 Web 開發領域的關鍵角色。 接受這些細微差別並將它們整合到我們的日常編碼實踐中,使我們能夠提高我們的技能並為[網路技術的發展](https://www.simplilearn.com/what-is-web-1-0-web-2-0-and-web-3-0-with-their-difference-article)做出貢獻。 請記住,[掌握 JavaScript 的](https://www.webdevstory.com/javascript-essential-terms/)道路是一個持續的旅程,每一行程式碼都提供了發現非凡事物的機會。 讓我們不斷突破 JavaScript 所能實現的極限,保持好奇心並對未來的無限可能性保持開放。 ***支持我們的技術見解*** [![請我喝杯咖啡](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lsm9uucbnw7x9iw0loxr.png)](https://www.buymeacoffee.com/mmainulhasan) [![透過 PayPal 按鈕捐贈](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ipnhbim2ba56kt32zhn3.png)](https://www.paypal.com/donate/?hosted_button_id=GDUQRAJZM3UR8) 注意:此頁面上的某些連結可能是附屬連結。如果您透過這些連結進行購買,我可能會賺取少量佣金,而您無需支付額外費用。感謝您的支持! --- 原文出處:https://dev.to/mmainulhasan/25-unnoticeable-features-of-javascript-15l1

2024 年你需要了解的 Python 函式庫

長話短說 ---- 你正在學習Python嗎?這是一片叢林! 您可以擁有任何您能想到的庫 - 從建立遊戲到建立 Web 應用程式。 透過此列表,無論您是剛剛入門還是想要深化 Python 遊戲,都可以快速了解 50 個標準 Python 庫及其用途。 ![介紹](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/at6swte9i2adqyeni03w.gif) --- 1.**Taipy** -------- Taipy 旨在加快應用程式開發,從最初的原型到生產就緒的應用程式。 這個開源 Python 函式庫專為輕鬆開發前端 (GUI) 和 ML/資料管道而設計。 它程式碼量低,專為任何 pythonista 設計。 ![口服](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scksaelbdhxsyzkv0bdq.png) https://github.com/Avaiga/taipy Star ⭐ Taipy 儲存庫 您的支持意義重大🌱,並在許多方面幫助我們,例如寫文章! 🙏 --- **2.NumPy** ----------- 對於數值計算至關重要,支援大型多維陣列和矩陣。該函式庫是 Python 版稅的一部分。 https://github.com/numpy/numpy Star ⭐ Numpy 儲存庫 --- 3.**Pandas** -------- 資料操作和分析的基石,提供直覺的資料結構和操作來操作數值表和時間序列。又一個Python不可或缺的函式庫,必知的函式庫。 https://github.com/pandas-dev/pandas Star ⭐ Pandas 儲存庫 --- **4.Matplotlib** ---------------- 一種多功能工具,用於建立各種靜態、最小和互動式視覺化。有很多參數可供使用,這個函式庫在繪製 ML 和 AI 圖表時非常有用。 https://github.com/matplotlib/matplotlib Star ⭐ Matplotlib 儲存庫 --- **5.SciPy** ----------- 專注於技術和科學計算,使用 Scipy,您可以進行最佳化、整合、插值等。 https://github.com/scipy/scipy Star ⭐ SciPy 儲存庫 --- **6.Scikit-learn** -------------- 機器學習的首選庫,提供廣泛的監督和無監督學習演算法。開始機器學習時您應該了解的唯一庫。 https://github.com/scikit-learn/scikit-learn Star ⭐ Scikit-learn 儲存庫 --- **7.TensorFlow** ---------------- 機器學習的綜合框架提供了各種工具、庫和社區資源。學習曲線可能有點陡峭,但在 Python 和 ML 領域中了解 TF 很重要。 https://github.com/tensorflow/tensorflow Star ⭐ TensorFlow 儲存庫 --- **8.PyTorch** ------------- 由於其靈活性,提供動態神經網路建立和操作,因此受到學術研究和生產的青睞。 https://github.com/pytorch/pytorch Star ⭐ PyTorch 儲存庫 --- 9.**Keras** -------- 用於建立和訓練深度學習模型的高級 API,旨在促進神經網路的建構和使用。 https://github.com/keras-team/keras Star ⭐ Keras 儲存庫 --- 10.**requests** --------- 簡化了發出 HTTP 請求的過程,使 Web 抓取和 API 消費更容易存取。 https://github.com/psf/requests Star ⭐ 請求儲存庫 --- 11.**Beautiful Soup** ----------- 一種網頁抓取工具,有助於從 HTML 和 XML 文件中提取資料。 https://github.com/waylan/beautifulsoup Star ⭐ Beautiful Soup 儲存庫 --- 12.**Flask** --------- 一個輕量級且可擴展的 Web 框架,非常適合建立中小型 Web 應用程式。 https://github.com/pallets/flask Star ⭐ Flask 儲存庫 --- 13.**Django** --------- 這個高級框架專為快速開發和簡潔、實用的設計而設計。 https://github.com/django/django Star ⭐ Django 儲存庫 --- 14.**Selenium** -------- 該程式庫使 Web 瀏覽器自動化,從而能夠模擬實際使用者操作以測試 Web 應用程式。 https://github.com/SeleniumHQ/selenium Star ⭐ Selenium 儲存庫 --- **15.Pygame** ------------- 提供用於編寫視訊遊戲的 Python 模組,包括圖形和聲音庫。 https://github.com/pygame/pygame Star ⭐ Pygame 儲存庫 --- 16.**Pillow** --------------- 擴充Python圖像庫功能,支援各種圖像檔案格式。 https://github.com/python-pillow/Pillow Star ⭐ Pillow 儲存庫 --- 17.SQL**Alchemy** ------------- 本函式庫提供了一整套透過 Python 處理資料庫的工具,提供了強大的 ORM 層和 SQL 表達式語言。 https://github.com/sqlalchemy/sqlalchemy Star ⭐ SQLAlchemy 儲存庫 --- **18.PySpark** -------------- 從名稱中可以看出,該程式庫將 Apache Spark 的強大功能引入了 Python,透過 Pythonic 方法促進大資料處理和分析。 https://github.com/apache/spark Star ⭐ PySpark 儲存庫 --- 19.**dash** --------- 允許直接在 Python 中建立分析 Web 應用程式,無需深入了解 Web 開發。 https://github.com/plotly/dash Star ⭐ dash 儲存庫 --- 20.**Plotly** --------- 專注於建立適合網路和行動應用程式的互動式且具有視覺吸引力的圖形和圖表。 https://github.com/plotly/plotly.py Star ⭐ Plotly 儲存庫 --- 21. **Nltk** ------------ 該庫使自然語言處理變得易於存取且易於使用。 https://github.com/nltk/nltk Star ⭐ Nltk 儲存庫 --- 22.**SpaCy** ---------- 提供工業級自然語言處理能力以及針對多種語言的預訓練模型。 https://github.com/explosion/spaCy Star ⭐ SpaCy 儲存庫 --- **23.Gensim** ------------- 專注於無監督主題建模和自然語言處理,您可以使用該程式庫來分析文件相似性。 https://github.com/RaRe-Technologies/gensim Star ⭐ Gensim 儲存庫 --- 24.Py**Test** ----------- 一個強大的框架,用於編寫小型到複雜的功能測試,增強測試的可讀性和可維護性。 https://github.com/pytest-dev/pytest Star ⭐ PyTest 儲存庫 --- 25.**單元測試** ----------- 用於建置和執行測試的內建框架,反映了其他語言中的 xUnit 架構。 Unitest 是內建的。 --- 26.**Fabric** --------- 簡化應用程式部署或系統管理任務的 SSH,自動執行遠端 shell 命令。 https://github.com/fabric/fabric Star ⭐ Fabric 儲存庫 --- 27.**Vizzu** -------- Vizzu 旨在動畫資料視覺化和講故事,是建立動態和互動式圖表的首選庫。 https://github.com/vizzuhq/vizzu-lib Star ⭐ Vizzu 儲存庫 --- 28.**Polars** --------- 針對效能和效率進行最佳化的 DataFrame 庫,能夠輕鬆處理大型資料集。 https://github.com/pola-rs/polars Star ⭐ Polars 儲存庫 --- 29.Docker **-Py** ----------------- 提供對 Docker Remote API 的 Pythonic 存取,從而實現 Docker 容器管理的自動化。 https://github.com/docker/docker-py Star ⭐ Docker-Py 儲存庫 --- **30.OpenCV** ------------- 電腦視覺和影像處理的主要內容,提供一整套演算法和工具。 https://github.com/opencv/opencv Star ⭐ OpenCV 儲存庫 --- 31.Scikit**-image** --------------- 它致力於影像處理,將 SciPy 和 NumPy 的功能擴展到視覺領域。 https://github.com/scikit-image/scikit-image Star ⭐ Scikit-image 儲存庫 --- 32.**SymPy** --------- 該庫專為符號計算而設計,提供從代數求解到微積分的各種功能。 https://github.com/sympy/sympy Star ⭐ SymPy 儲存庫 --- 33.**Virtualenv** ----------- 對於建立隔離的 Python 環境和乾淨地管理專案依賴至關重要。 https://github.com/pypa/virtualenv Star ⭐ Virtualenv 儲存庫 --- 34.**Click** --------- 簡化命令列介面的建立,促進可組合且易於擴展的程式碼。 https://github.com/pallets/click 為 Click 儲存庫加註星標 --- 35. **argparse** ---------------- 促進命令列參數的解析,這對於 CLI 應用程式開發至關重要。 Argparse 是內建的。 --- 36.**日誌記錄** ----------- 提供靈活的日誌記錄系統,從簡單的日誌記錄到複雜的每個模組配置。 日誌記錄是內建的。 --- **37.PyYAML** ------------- 處理 YAML 文件,支援 Python 物件與 YAML 之間的序列化和反序列化。 https://github.com/yaml/pyyaml Star ⭐ PyYAML 儲存庫 --- 38.xlrd **/xlwt** ----------------- 非常適合讀取和寫入 Excel 文件,彌補了 Python 和 Excel 文件之間的差距。 https://github.com/python-excel/xlrd Star ⭐ xlrd 儲存庫 https://github.com/python-excel/xlwt Star ⭐ xlwt 儲存庫 --- 39. **Pandas 分析** ----------------- 從 pandas 產生全面的配置文件報告 https://github.com/pandas-profiling/pandas-profiling Star ⭐ Pandas-Profiling 儲存庫 --- 40.**全面品質管理** ------------- Tqdm 是任何循環的包裝器,它將透過進度條追蹤進度。 https://github.com/tqdm/tqdm Star ⭐ TQDM 儲存庫 --- 41.**Faker** --------- 需要看起來真實的假資料嗎? Faker 為你提供支援。 https://github.com/joke2k/faker Star ⭐ Faker 儲存庫 --- 42.**Flake8** ---------- 一個必備的庫,可以使您的程式碼保持簡潔,並輕鬆實現樣式檢查。 https://github.com/PyCQA/flake8 Star ⭐ Flake8 儲存庫 --- 43.**Black** --------- 將您的程式碼格式提升到一個新的水平。 https://github.com/psf/black Star ⭐ Black 儲存庫 --- 44.**Mypy** ---------- 這就像有一位文法老師來教你的程式碼,但教你的類型。 https://github.com/python/mypy Star ⭐ Mypy 儲存庫 --- 45.**Pydantic** ----------- 驗證 Python 腳本所需的函式庫。 https://github.com/samuelcolvin/pydantic Star ⭐ Pydantic 儲存庫 --- **46.FastAPI** -------------- FastAPI 是一個用於建立 RESTful API 的 Web 框架。 https://github.com/tiangolo/fastapi Star ⭐ FastAPI 儲存庫 --- 47.**Catboost** ---------- 為您的機器學習模型提供處理分類資料的方法。 https://github.com/catboost/catboost Star ⭐ Catboost 儲存庫 --- 48.**Seaborn** ---------- 提高資料可視化水準。 https://github.com/mwaskom/seaborn Star ⭐ Seaborn 儲存庫 --- 49.**Turtle graphics ** --------- 透過酷炫的圖形和動畫將程式設計帶入生活。學習並開始使用 Python 的好方法。 Turtle graphics 是內建的。 --- 50.**Asciimatics** ------------ Asciimatics 是一個可讓您建立全螢幕文字 UI 的程式庫。 https://github.com/peterbrittain/asciimatics Star ⭐ Asciimatics 儲存庫 --- 原文出處:https://dev.to/taipy/python-libraries-you-need-to-know-in-2024-37ka

2024 年每個雲端工程師都應該了解的 7 種程式語言!

近年來,在各種程式設計訓練營的指導中,我獲得了獨特的機會來指導和支援眾多熱衷於在雲端工程和 DevOps 領域取得成功的初級開發人員。我注意到這些有抱負的工程師中反覆出現的一個主題是,他們渴望深入了解雲端運算的複雜性,但常常對大量可用的程式語言和工具感到不知所措。這種認識激發了我的想法,即建立一個全面且平易近人的指南,為任何開始雲端工程之旅的人介紹基本的程式語言。 同樣,到 2024 年,每個雲端工程師都應該了解以下七種程式語言,每種語言都因其相關性、功能和在實現現代雲端解決方案中的作用而被選擇。 1. 翼 ---- ![只是一個翅膀](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6syu6oqhs93z0sq77cvf.png) [Wing](https://github.com/winglang/wing)的設計理念強調生產力、安全性和效率,使開發人員能夠在整個開發過程中保持單一、直覺的工作流程。 透過將基礎設施資源視為一等公民,Wing 允許開發人員直接在其應用程式程式碼中定義、互動和管理這些資源。這種整合顯著降低了與管理雲端基礎架構相關的複雜性和潛在錯誤,從而更輕鬆地建置和部署安全、可擴展的應用程式。 Wing 的主要功能之一是它能夠編譯為基礎設施即程式碼 (IaC) 格式,例如 Terraform 和 JavaScript。 Wing 對雲端應用程式本地模擬的支援徹底改變了開發人員的工作效率。在部署之前能夠在本地環境中執行、視覺化、互動和除錯雲端應用程式可以顯著加快開發週期並提高應用程式品質。此功能與易於與 DevOps 實踐整合的語言設計相結合,可確保開發人員能夠更有效地應用持續整合和持續部署 (CI/CD) 方法,從而與現代軟體開發實踐保持一致。 看看[Wing 的互動遊樂場,](https://www.winglang.io/play/)了解 Wing 語言的工作原理。 使用 Wing 非常輕鬆且超級簡單。 您可以在幾秒鐘內安裝 Wing 並開始自動化您的雲端工作流程。 ``` npm install -g winglang ``` 您可以使用以下命令驗證您的安裝。 ``` wing -V ``` 使用 CLI 引導新專案:使用 new 命令,然後修改 main.w 使其具有以下內容: ``` wing new empty ``` ``` bring cloud; // define a queue, a bucket and a counter let bucket = new cloud.Bucket(); let counter = new cloud.Counter(initial: 1); let queue = new cloud.Queue(); // When a message is received in the queue it should be consumed // by the following closure queue.setConsumer(inflight (message: str) => { // Increment the distributed counter, the index variable will // store the value prior to the increment let index = counter.inc(); // Once two messages are pushed to the queue, e.g. "Wing" and "Queue". // Two files will be created: // - wing-1.txt with "Hello Wing" // - wing-2.txt with "Hello Queue" bucket.put("wing-{index}.txt", "Hello, welcome to winglang world!"); log("file wing-{index}.txt created"); }); ``` 使用 wing it 指令透過我們新建立的應用程式啟動控制台: ``` wing it main.w ``` Wing 控制台為您提供雲端應用程式的視圖,使開發人員能夠更快地迭代和熱重載: ![溫朗前衛](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mmrz484dh0fvf220uhg4.png) 透過 Wing 的有關[Wing 入門](https://www.winglang.io/docs/start-here/local)的文件探索更多資訊。 2.Python -------- ![僅限蟒蛇](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7gdgxhcb4mjywdih30u.png) 由於其簡單性、多功能性和強大的生態系統, [Python](https://github.com/python)仍然是雲端工程師不可或缺的語言。其廣泛的庫和框架集合(例如用於 Web 應用程式的 Flask 和用於機器學習的 TensorFlow)使 Python 成為開發各種基於雲端的服務的首選語言。此外,Python 在自動化、腳本編寫和資料分析中的作用確保了它仍然是雲端基礎設施管理、自動化任務和雲端應用程式快速原型設計的關鍵工具。 3. 成長 ----- ![戈蘭](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5ggz0p6ix46uqifhmd7.png) [Go](https://github.com/golang/go)或 Golang 由 Google 設計,在雲端工程師中越來越受歡迎,用於建立高效能和可擴展的雲端服務。它的高效、簡單和內建的並發支援使其成為開發微服務、分散式系統和容器化應用程式的絕佳選擇。 Go 與雲端平台的兼容性及其有效處理繁重網路流量和複雜處理任務的能力有助於其在雲端基礎設施專案中的日益普及。 4. JavaScript(使用 Node.js) ------------------------- ![Node.js 語言](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s5q16t3w3zf8xctgrlvg.png) [JavaScript](https://en.wikipedia.org/wiki/JavaScript) ,特別是與 Node.js 一起使用時,對於專注於建置和部署可擴展且高效的 Web 應用程式的雲端工程師來說至關重要。 Node.js 允許在伺服器端使用 JavaScript,從而能夠開發適合雲端的快速、非阻塞、事件驅動的應用程式。 JavaScript 在客戶端和伺服器端開發中的普遍存在也促進了全端開發能力,使其對於從事基於雲端的 Web 服務和應用程式的工程師來說非常寶貴。 5. 生鏽 ----- ![長時間休息](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3f1w421ksertrrldyod.png) [Rust](https://www.rust-lang.org/)由於強調安全性、速度和無需垃圾收集器的並發性而在雲端運算領域獲得了發展勢頭。這些功能使 Rust 成為尋求開發高效能、安全且可靠的雲端服務和基礎設施的雲端工程師的有吸引力的選擇。 Rust 的記憶體安全保證和機器程式碼的高效編譯使其成為雲端環境中系統級和嵌入式應用程式的理想語言,在雲端環境中,效能和安全性至關重要。 6. Kubernetes YAML ------------------ ![Kubernetes yaml](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mga2ylbbc9g98w4hjkmg.png) 雖然[Kubernetes YAML](https://kubernetes.io/docs/concepts/overview/working-with-objects/) (YAML 不是標記語言)不是傳統意義上的程式語言,但對於使用 Kubernetes(容器編排事實上的標準)的雲端工程師來說至關重要。掌握 Kubernetes YAML 對於跨雲端環境定義、部署和管理容器化應用程式至關重要。了解 Kubernetes 資源檔案和配置的複雜性使工程師能夠利用容器編排的全部功能,確保可擴展、有彈性且高效的雲端原生應用程式。 7.Terraform HCL(HashiCorp配置語言) ------------------------------ ![地形鹽酸鹽](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ke9hjhkw6k2i9zald105.png) [Terraform HCL](https://github.com/hashicorp/hcl) (HashiCorp 配置語言)是 2024 年雲端工程師的必備語言,尤其是那些參與基礎設施即程式碼 (IaC) 實踐的工程師。 HCL 是 Terraform 使用的配置語言,Terraform 是一種廣泛採用的工具,使工程師能夠使用聲明性配置方法定義、配置和管理雲端基礎架構。學習 Terraform HCL 使雲端工程師能夠自動化跨不同服務供應商的雲端資源部署和生命週期管理,確保雲端環境的一致性、可重複性和可擴展性。 ### 包起來 到 2024 年,所有語言都有自己的優勢,我很高興將自己關於雲端工程和 DevOps 的想法放在一起。 如果我能為我的學生提供建議,在這個不斷發展的領域迅速擴展的過程中,掌握 Wing 將成為一個令人信服的選擇。 [Wing](https://www.winglang.io/)為雲端工程師和開發人員提供了獨特的優勢,提供控制臺本地測試、熱重載(對大多數雲端工程師來說是一個挑戰)和增強的可擴展性,更不用說雲端應用程式的安全性了。 --- 原文出處:https://dev.to/pavanbelagatti/7-programming-languages-every-cloud-engineer-should-know-in-2024-1kcd

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

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

我們習慣的前端開發正在消亡

介紹 -- 在 SPA 出現之前,Web 應用程式通常是多頁面的。這意味著每次用戶與應用程式互動時,伺服器都會發送完整的新頁面,然後瀏覽器會再次載入它。每次用戶在頁面之間導航時,都會發生完整的頁面重新加載,這可能會減慢速度並造成不太流暢的用戶體驗。類似的應用程式通常是使用伺服器端技術建立的,例如 PHP、Ruby on Rails、ASP.NET 等,這些技術在伺服器端產生 HTML 程式碼並將其發送到瀏覽器。 ![PHP Web 應用程式如何運作](https://cdn-images-1.medium.com/max/2000/0*Icdswn5CFRcaw39d) Web開發人員是通用專家,他們同時負責前端和後端部分。隨著網路技術的發展和用戶的需求,需要新的解決方案,使他們能夠在沒有任何問題或等待的情況下使用互動式介面。 這就是第一個使用 BackboneJs 或 AngularJs 的 SPA 解決方案的出現。它們使我們能夠減少伺服器的負載(當時伺服器的資源有限),並在透過 JS 處理網頁時提供互動性,因為無需等待伺服器更新的新頁面。 這就是前端和後端部分的劃分。純粹前端開發人員的角色變得更加需求和多樣化。他們開始專注於建立使用者介面、使用 HTML、CSS 和 JavaScript,以及與 API 和伺服器互動。另一方面,後端開發人員變得更加關注資料處理、應用程式業務邏輯、使用資料庫和建立伺服器 API。 這就是我們進入 React、Angular2、Vue 和其他 Web 應用程式開發工具時代的方式。現在我們不再建立簡單的表單和列表,而是有 js 路由、狀態管理、瀏覽器 API、將授權令牌綁定到請求、資料映射等。 > ### 我們開始把簡單的事情複雜化。 透過這種方法,出現了以下問題: - **溝通協調困難**。 Api 合約與通訊方法 — HTTP 1.1、Websocket、GraphQL。 JSON 解析和驗證。 - **理解和認識上的分歧**。例如,您可以開發一個建立許多查詢的前端應用程式,並將其視為正常且最佳化的 SPA。但對於後端來說,這是一個非常危險的情況,因為它現在需要大量的資料庫存取以及對這些資料的適當聚合,這會影響它的效能和維護。 - **重複工作**。後端的大多數 CRUD 操作在前端都有類似的行為。我們不只是從伺服器獲取列表,現在我們將其放入 store() 中,每個用戶操作都透過dispatch() 處理並等待請求執行,之後我們透過reducer() 更新store根據結果——**後端對資料庫所做的一切,我們都會在前端重複**。 (頁面重新加載和從伺服器將 SPA 恢復到當前狀態也值得一提 - 目前是一個單獨的痛苦) - **除錯和測試困難**。現在您需要考慮可能的整合問題並在應用程式雙方的上下文中測試它們。是的,您可以為前端應用程式建立隔離的 e2e 測試,但它們不能保證生產中的可靠性。是的,有 ZoD 用於驗證伺服器回應,但它的使用百分比是多少? - **增加了開發時間和成本**。對 API 合約的任何更改都需要兩個人同時進行。您不能像以前那樣直接將模板變更為伺服器。你需要集會、分成單獨的任務、商業分析專家等等來讓改變順利進行。 - **搜尋引擎優化**。由於我們的應用程式完全是透過 JS 建構的,搜尋引擎無法取得應用程式內容及其導航來正確索引它,因此需要 SSR 和 SSG 解決方案。 - **安全**。在頁面上輸入的任何關鍵資料在傳遞到伺服器之前都需要隱藏。此外,應用程式需要向伺服器請求大量個人訊息,從而洩露存取權杖。 那麼,通常的前端為什麼會消亡呢? ---------------- 只需存取任何資源,您就會看到有多少職位空缺: - Python + Django - PHP + Laravel - NextJs + React - Nuxt + Vue 這些都是用於基於伺服器的 Web 應用程式開發的捆綁包。由於採用 Hydration 和 Resumability 方法,伺服器只能渲染介面的修改部分,而無需重新載入頁面。 他們提供什麼: - 伺服器應用程式現在不需要複雜的 HTTP 或 WS 合約並且雙方都支援它們,它可以使用更好的方法與 gRPC 等其他服務交換資訊。 - 由於缺乏中間批准,更改過程更快,對於 1 人,用戶看到的結果會立即更改。 - 測試可以全面檢查應用程式,消除整合測試並減少錯誤。 - 您僅交換 HTML 標記,所有「請求-回應」邏輯對使用者來說都是隱藏的 - 當您可以傳遞現成的範本時,為什麼還要傳遞大量 JSON 資料來將 SPA 還原到正確的狀態呢? - 你不需要擔心瀏覽器相容性,也不需要使用babel等工具,因為頁面上的JS程式碼很少。 隨著No-Code解決方案的出現、透過AI生成模板、龐大的伺服器資源和SEO需求——目前數量的前端開發人員和工具不再需要只開發前端部分。 企業主有一個合理的問題——“*為什麼我需要雇用一個純粹的前端開發人員和一個純粹的後端開發人員來做一個簡單的應用程式?”* 全端開發人員並不是一種管理時尚,就節省人員配備而言,現在它已成為中流砥柱。你不需要一個純粹的前端開發人員,你需要一個能夠製作整個應用程式、直接對資料庫或其他服務執行簡單操作並顯示結果的開發人員。 是的,毫無疑問仍然會存在需要前端和後端分離的複雜或“無頭”應用程式,但大多數應用程式將脫離 SPA 並沿著已經存在的方式發展,但現在我們有一個解決方案那些問題。隨著 HTMX 的出現,任何具有基礎知識的後端開發人員都可以建立 Web 應用程式。現在你甚至不需要了解 JS 就可以建立一個幾乎沒有邏輯的單頁應用程式。 你可能會問,「*前端開發人員不僅負責 JS 邏輯,還負責 CSS 和適當的選擇器、HTML 及其語義,後端開發人員現在必須知道嗎?* 」 — 不,現在人工智慧或「HTML 佈局設計師」可以根據 Figma 的佈局產生模板。 HTML 範本的邏輯和互動性現在在伺服器上定義。 結論 -- 現在是思考您是否真的需要所有這些複雜的前端開發工具以及您是否應該保持純粹的前端開發人員的好時機。 我預計目前的前端開發人員將採用 60% 前端和 40% 後端的比例轉向全端資格,以保持相關專家的地位。 HTMX 只是開始,NextJs 或 Nuxt 工具的向量將會成長,Angular 類型的框架如果不能適應新的實作就會消亡,儘管 Angular 生態系統已經在 AnalogJs 上有了原型 資源 -- - [**htmx - 強大的 html 工具**](https://htmx.org/) - [**模擬**](https://analogjs.org/) - [按「前端開發人員」角色搜尋職位](https://www.indeed.com/jobs?q=front+end+developer&l=Remote) - [按「全端開發人員」角色搜尋職位](https://www.indeed.com/jobs?q=full+stack+developer&l=Remote) - [**Vercel 的 Next.js - React 框架**](https://nextjs.org/) - [**Nuxt:直覺的 Vue 框架**](https://nuxt.com/) --- 原文出處:https://dev.to/misterion96/the-front-end-development-were-used-to-is-dying-4e19

✨2024 我的決心:更以開源專案為中心思想!

## 簡介 當(幾乎)總是有一個開源替代品可以完成同樣的工作(如果不是更好的話)時,為什麼還要依賴專有軟體和服務呢? 以下是我一直在使用的 10 個開源替代方案,涵蓋從專案管理和通訊到資料分析的所有內容。 ![Gif 簡介](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypv9s82s7843ecb1a36t.gif) --- ## 1- [Taipy](https://github.com/Avaiga/taipy) 而不是 Tableau Tableau 可能是資料視覺化領域的頂級參與者之一,但 Taipy 提供了強大的替代方案。 Taipy 是一個開源 Python 程式庫,可讓您建立全面的 Web 應用程式來展示資料視覺化。 Taipy 程式碼量低、高度可自訂,並且在建立儀表板時提供更大的靈活性。 ![Taipy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lai9u2uqawun2j5mf7ur.gif) --- ![QueenB GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0un08vhstrk6zpst5yti.gif) 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- ## 2- [Cal.com](http://Cal.com) 而非 Calendly Calendly 是簡化日程安排的變革者,但 [Cal.com](http://Cal.com) 成功地將其提升到了一個新的水平。這個開源 gem 有以下功能: - 團隊調度 - 整合視訊會議 - 自動時區偵測 ![Cal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bjea3cr44s86z5deirt.gif) --- ## 3- [Plausible](https://github.com/plausible/analytics) 而非 Google Analytics 當然,Google Analytics 是一個大牌,但有時較小的工具也能提供同樣多的功能,一個很好的例子就是 Plausible。 這個開源工具提供像Google一樣的網站分析功能,不,他們不會損害資料隱私。 ![看似合理](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cmonhrmf5gch5kn6fe0e.gif) --- ## 4- [AppFlowy](https://github.com/AppFlowy-IO/AppFlowy) 而非 Notion Notion 是一個非常適合做筆記和專案管理的工作空間,但如果您想要一個更簡單的選項,請嘗試 AppFlowy。 該工具提供了一種極簡主義的替代方案,專注於簡單地建立和組織清單、註釋和任務。 介面非常人性化;您很快就會成為專業人士。 ![AppFlowy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wko5i9mphadcq1pa6bsh.gif) --- ## 5- [Penpot](https://github.com/penpot/penpot) 而非 Figma Figma 是一個設計巨頭,但它的開源表弟 Penpot 在過去一年中一直在增長勢頭。 以下是 Penpot 的主要功能: - 協同設計能力 - 向量編輯 - 互動式原型 - 成本效益 ![Penpot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pkg8ayeuw0y1q0tme50t.gif) --- ## 6- [Fonoster](https://github.com/fonoster) 而非 Twilio Twilio 是一個通訊平台,提供簡訊、語音、視訊和身份驗證 API,並提供無縫的客戶體驗。 讓我向您介紹 Fonoster,這是一種經濟高效的替代方案。 Fonoster 提供類似的語音和訊息服務。 Fonoster 專注於可擴展性,同時為您提供無縫的客戶體驗。 ![Fonoster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jk20ziqppgcpbfr6e37.gif) --- ## 7- [NextCloud](https://github.com/nextcloud/server) 而不是 Dropbox NextCloud 是 Dropbox 的開源競爭對手。 它提供文件託管、協作和同步功能,同時保持資料的隱私性並處於您的控制之下。 ![NextCloud](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szichu2pjf9xzah9v64y.gif) --- ## 8- [Jitsi](https://github.com/jitsi/jitsi-meet) 而非 Google Meets Jitsi 是 Google Meets 的替代品,提供類似的視訊會議功能。 他們的主要特徵: - 端對端加密 - 螢幕分享 - 並且無需註冊! ![Jitsi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwnxa8hy6a0svqb4yo1d.gif) --- ## 9- [Padloc](https://github.com/padloc/padloc) 與 1Password 1Password 在密碼管理領域享有盛譽,但開源工具 Padloc 同樣注重隱私和安全性。 您可以使用 Padloc 安全地儲存和管理您的敏感和私人訊息,就像 1Password 一樣。 ![Padloc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4st8nymwlf3wlslz029k.gif) --- ## 10- [Crowd.dev](https://github.com/CrowdDotDev/crowd.dev) 而非公共房間 Common Room 在社區建設領域一直勢頭強勁,但不要忽視他們的開源替代方案「crowd.dev」。 無論是專案管理、資金還是協作,「crowd.dev」對於建立和發展線上社群都是不可忽視的。 ![人群](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9j3mxkbk6wuwyt2g1fdh.gif) --- ## 結論 選擇工具時,請記住查看開源選項。 開源帶來了透明度、可自訂性和成本效益,在大多數情況下都是不錯的選擇。 ![GIF 結束](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvimkpxsq91d6m1jfei1.gif) 恭喜你,你已經走到最後了!如果您有任何疑問,請隨時諮詢。 --- 原文出處:https://dev.to/taipy/2024-resolution-be-more-open-source-centric-1jje

全端工具箱🧰:Python🐍版

## 簡介 以下是專注於全端開發不同面向的 Python 函式庫;有些專注於 Web 應用程式開發,有些專注於後端,有些則兩者兼而有之。 ![Gif引言](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8eodxlxdlgr0xh6lrvhz.gif) --- ## 1. [Taipy](https://github.com/Avaiga/taipy) Taipy 是一個開源 Python 庫,用於建立生產就緒的應用程式前端和後端。 它旨在加快應用程式開發,從最初的原型到生產就緒的應用程式。 🔑特點: - 豐富的互動性 - 為您的佈局、樣式等提供更多自訂功能(無需 CSS) - 多頁和多用戶應用程式 - 圖形管道編輯器 - 與 Taipy 前端功能整合以實現端到端部署 - 日程安排 - 筆記型電腦相容 ![Taipy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1rk0w837hwaq0akybw6o.png) --- ![QueenB GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0un08vhstrk6zpst5yti.gif) https://github.com/Avaiga/taipy 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- ## 2.[Prefect](https://github.com/PrefectHQ/prefect) Prefect 是一個提供資料管道開發的框架。 它透過注重簡單性和用戶友好性而與 Airflow 等競爭對手區分開來。 如果您想要一個具有各種功能但比 Airflow 更容易學習的成熟產品,Prefect 是一個很好的中間產品。 🔑特點: - 直覺且使用者友好的控制面板 - 快取等智慧功能 - 以流程為基礎的架構,可輕鬆融入工作流程組織 - 動態參數化與依賴管理 - 混合執行(本地/雲端) ![完美](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p94g40hwv04gkfmvklda.png) --- ## 3. [Streamlit](https://github.com/streamlit/streamlit) Streamlit 是一個遊戲規則改變者,可以快速、簡單地建立 Web 應用程式。 此資料應用程式框架將其從更完整、更複雜的解決方案轉變為快速、用戶友好的解決方案。 🔑特點: - Pythonic框架 - 互動式小部件 - 使用者友善性 ![Streamlit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ddntytwa95tgp37kykcc.png) --- ## 4.[氣流](https://github.com/apache/airflow) Apache Airflow 是一個開源平台,專為調度和監控工作流程而設計。 它是編排複雜資料管道和 ETL 流程的絕佳選擇,因為它在過去十年中一直是管道領域的重要參與者。 該庫的完整性與陡峭的學習曲線有關。 🔑特點: - 基於DAG的工作流程定義 - 包括 DAG 視覺化的完整介面,可追蹤故障並管理重試。 - 各種集成 - 動態任務執行和調度 - 以Python為中心的設計 - 社區支持 ![氣流](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lm89iyieg07c2rgzm2jb.png) --- ## 5. [Brython](https://github.com/brython-dev/brython) Brython 將 Python 帶到了前端,因為這個名字重新組合了「瀏覽器」和「Python」。 它引入了直接在 Web 應用程式中執行 Python 程式碼的獨特概念。 這種創新方法可讓您使用 Python 建立互動式 Web 體驗。 🔑特點: - 易於集成,因為它將 Python 邏輯直接整合到瀏覽器中 - 相容於不同的網頁瀏覽器 ![Brython](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9a7w7lqd9b5rtpahnolr.png) --- ## 6. [達世幣](https://github.com/plotly/dash) Dash 由 Plotly 建立,是一個利用 Plotlys 元件完整性的 Web 應用程式框架。 眾所周知,它是一個完整的解決方案,因此需要更長的時間來掌握。 🔑特點: - 基於元件的架構 - 強大的互動式儀表板 - 即時資料更新 ![破折號](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp5xw24ulak6mnwwos69.png) --- ## 7. [Dagster](https://github.com/dagster-io/dagster) Dagster 是本次編譯中較新的函式庫之一,它是一個雲端原生資料管道編排,旨在統一資料整合、工作流程編排和監控。 與其他工具相比,Dagster 強調工作流程建立和管理的 DataOps 面向。 🔑特點: - 聲明式管道設置 - 固執己見的結構 - 版本控制 - 與 Hadoop 集成 - 全面的元資料跟踪 ![Dagster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hz78m7rein4asbyp9buf.png) --- ## 8. [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy) SQLAlchemy 是一個用於處理資料庫互動的 Python 函式庫。 它是一個連接Python程式設計和關係資料庫的多功能工具包。 掌握這個庫的時間較長,但好處是實實在在的。 🔑特點: - SQL 表達式語言 - 物件關係映射(ORM) - 對資料庫的廣泛支持 - 複雜查詢支持 ![SQL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owtvt0kv5gt45r33ulra.png) --- ## 9. [芹菜](https://github.com/celery/celery) Celery 是一個 Python 函式庫,用作建立後端應用程式的框架。 它處理分散式任務處理、作業執行和工作流程。 它是一個完整的解決方案和廣泛的功能集,具有更陡峭的學習曲線。 🔑特點: - 平行處理 - 可擴展性 - 任務調度 - 非同步處理 ![芹菜](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p50my0xtbncfskb4y1ga.png) --- ## 10. [Peewee](https://github.com/coleifer/peewee) 與 SQAlchemy 一樣,Peewee 是一個簡化資料庫互動的 Python 函式庫。 它與競爭對手的不同之處在於用戶友好且簡單的設定。 該庫是中小型專案的最佳選擇。 🔑特點: - 輕量級框架 - 資料庫支持 - Python式文法 ![Peewee](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8tmvc7y9vkb2mdpj88jq.png) --- ## 11. [Kedro](https://github.com/kedro-org/kedro) Kedro 是一個開源 Python 框架。 它為生產就緒的資料科學管道提供了一個工具箱。 事實上,Kedro 可以輕鬆地與成熟的 Python ML 庫集成,並提供統一的方法來實現端到端框架。 🔑特點: - 資料目錄 - 筆記本集成 - 專案模板 - 有自己的觀點,因為它強制執行特定的約定 ![Kedro](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2z12ofiibpd5c9ggs7s.png) --- ## 結論 Python 被認為是人工智慧和機器學習應用程式的首選語言。 為了簡化和自動化這些應用程式,Python 見證了框架庫的出現。 這些程式庫有助於 Web 應用程式開發、後端服務以及開源全端應用程式的建立。 --- ![新秀圖片](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25oebh36ha622u74kpli.gif) 我剛開始我的內容創作之旅;如果您有任何問題或回饋,請隨時與我們聯繫! --- 原文出處:https://dev.to/taipy/full-stack-toolbox-python-edition-20h2

JS 設計模式:綜合指南

![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vukjahraekzzsj9e6h3x.png) JavaScript 以其廣泛的採用和多功能性,已成為現代 Web 開發的基石。隨著您深入研究 JavaScript 開發,理解和利用模式變得至關重要。在本文中,我們將踏上揭開 JavaScript 模式神秘面紗的旅程,並探索它們如何增強您的程式設計實踐。 ## 先決條件 要理解本文中討論的概念和技術,您需要了解 JavaScript 的基礎知識。熟悉變數、函數、資料類型、物件導向程式設計等概念至關重要。 在繼續之前,讓我們花點時間了解 JavaScript 作為程式語言的重要性。 ### JavaScript 作為程式語言 JavaScript 通常被稱為“網路語言”,是一種動態的高階程式語言。它主要用於 Web 瀏覽器中的客戶端腳本編寫,但隨著 Node.js 的出現,它也在伺服器端獲得了關注。 JavaScript 的主要功能包括操作 DOM、處理事件、為網頁提供互動性等的能力。 話雖這麼說,讓我們簡單討論一下 JavaScript 中模式的重要性和用途。 ### JavaScript 開發中模式的重要性 JavaScript 中的模式可以作為軟體開發過程中遇到的重複問題的經過驗證的解決方案。它們提供結構、改進程式碼組織、增強可維護性並促進可重複使用性。透過理解和應用模式,開發人員可以編寫更清晰、更有效率的程式碼並有效應對複雜的挑戰。 ### 理解 JavaScript 模式的目的 理解 JavaScript 模式不僅僅是記住文法或遵循最佳實踐。它使開發人員能夠批判性地思考軟體設計、選擇適當的解決方案並建立可擴展的應用程式。透過掌握 JavaScript 模式,您可以深入了解該語言及其生態系統,從而能夠編寫健全且可維護的程式碼。 現在我們知道了 JavaScript 模式的重要性和用途,讓我們深入研究 JS 設計模式的基礎知識。 ## 設計模式的基礎知識 在本節中,我們為理解 JavaScript 開發背景下的設計模式奠定了基礎。 ###設計模式的定義與特點 設計模式是可重複使用的模板,封裝了解決重複出現的軟體設計問題的最佳實踐。它們提供了一種結構化的方法來設計軟體系統,並促進模組化、靈活和可維護的程式碼。設計模式的共同特徵包括其目的、結構、參與者和協作。 ###設計模式的類型 設計模式可分為三種主要類型: - 創意 - 結構性 - 行為的 了解這些類別有助於確定給定問題的適當模式。 - **創作模式** 建立模式專注於物件建立機制,提供以靈活且受控的方式實例化物件的方法。 JavaScript 中一些常用的建立模式包括: - 辛格頓 - 工廠 - 建構函數 - 原型 - 建造者 - 模組 **單例模式** 單例模式確保一個類別只有一個實例,並提供對其的全域存取點。當您想要限制類別的實例數量並確保在整個應用程式中可以存取單一共用實例時,此模式非常有用。 ``` // Implementation example of the Singleton Pattern class Singleton { constructor() { if (!Singleton.instance) { // Initialize the instance Singleton.instance = this; } return Singleton.instance; } } const instance1 = new Singleton(); const instance2 = new Singleton(); console.log(instance1 === instance2); // Output: true ``` 在此範例中,Singleton 類別有一個建構函數,用於檢查該類別的實例是否已存在。如果實例不存在(“!Singleton.instance”條件),它將透過將其指派給「Singleton.instance」來初始化該實例。這確保了對建構函數的後續呼叫將傳回相同的實例。 當使用新的 Singleton() 語法建立實例 1 和實例 2 時,這兩個變數都會引用 Singleton 類別的同一個實例。因此,當使用嚴格相等運算子比較實例 1 === 實例 2 時,其計算結果為 true。 **工廠模式** 工廠模式提供了一種建立物件而無需指定其特定類別的方法。它將物件建立邏輯封裝在一個單獨的工廠方法中,允許建立者和建立的物件之間的靈活性和解耦。 ``` // Implementation example of the Factory Pattern class Car { constructor(make, model) { this.make = make; this.model = model; } } class CarFactory { createCar(make, model) { return new Car(make, model); } } const factory = new CarFactory(); const myCar = factory.createCar("Tope", "Model 1"); ``` 在此範例中,使用 new CarFactory() 建立了一個 CarFactory 實例,然後使用參數「Tope」和「Model 1」在工廠上呼叫「createCar」方法。這將建立一個新的 Car 物件,其品牌為“Tope”,型號為“Model 1”,並分配給 `myCar` 變數。 **建構函式模式** 建構函式模式使用“new”關鍵字從建構函式建立物件。它允許您在建構函數中定義和初始化物件屬性。 ``` // Implementation example of the Constructor Pattern function Person(name, age) { this.name = name; this.age = age; } const tope = new Person("Tope", 24); ``` 上面的程式碼定義了一個名為 Person 的建構函數,它帶有兩個參數:姓名和年齡。在函數內部,使用 this 關鍵字將名稱和年齡值指派給新建立的物件的對應屬性。 稍後,透過使用參數“Tope”和 24 呼叫 Person 函數來建立 Person 物件的新實例。這將建立一個新物件,其 name 屬性設為“Tope”,age 屬性設為 24,然後指派給變數top。這段程式碼的輸出是 Tope 持有一個物件,代表一個名為「Tope」、年齡為 24 歲的人。 **原型模式** JavaScript 中的原型模式專注於透過複製或擴展現有物件作為原型來建立物件。它允許我們建立新實例而無需明確定義它們的類別。在此模式中,物件充當建立新物件的原型,從而實現繼承以及在多個物件之間共享屬性和方法。 ``` // Prototype object const carPrototype = { wheels: 4, startEngine() { console.log("Engine started."); }, stopEngine() { console.log("Engine stopped."); } }; // Create new car instance using the prototype const car1 = Object.create(carPrototype); car1.make = "Toyota"; car1.model = "Camry"; // Create another car instance using the same prototype const car2 = Object.create(carPrototype); car2.make = "Honda"; car2.model = "Accord"; car1.startEngine(); // Output: "Engine started." car2.stopEngine(); // Output: "Engine stopped." ``` 在此範例中,汽車實例 car1 和 car2 是使用原型物件 carPrototype 建立的。 car1 的品牌為“Toyota”,型號為“Camry”,而 car2 的品牌為“Honda”,型號為“Accord”。當呼叫 `car1.startEngine()` 時,輸出“Engine started.”,當呼叫 `car2.stopEngine()` 時,輸出“Engine waiting.”。這示範如何利用原型物件在多個實例之間共用屬性和方法。 **建造者模式** 在建構器模式中,建構器類別或物件負責建構最終物件。它提供了一組方法來配置和設定正在建置的物件的屬性。建置過程通常涉及按特定順序呼叫這些方法來逐步建立物件。 ``` class CarBuilder { constructor() { this.car = new Car(); } setMake(make) { this.car.make = make; return this; } setModel(model) { this.car.model = model; return this; } setEngine(engine) { this.car.engine = engine; return this; } setWheels(wheels) { this.car.wheels = wheels; return this; } build() { return this.car; } } class Car { constructor() { this.make = ""; this.model = ""; this.engine = ""; this.wheels = 0; } displayInfo() { console.log(`Make: ${this.make}, Model: ${this.model}, Engine: ${this.engine}, Wheels: ${this.wheels}`); } } // Usage const carBuilder = new CarBuilder(); const car = carBuilder.setMake("Toyota").setModel("Camry").setEngine("V6").setWheels(4).build(); car.displayInfo(); // Output: Make: Toyota, Model: Camry, Engine: V6, Wheels: 4 ``` 在此範例中,「CarBuilder」類別允許建構具有不同屬性的 Car 物件。透過呼叫`setMake`、`setModel`、`setEngine`、`setWheels`方法,設定Car物件的屬性。 build 方法完成建置並傳回完全建置的 Car 物件。 Car 類別代表一輛汽車,並包含一個「displayInfo」方法來記錄其詳細資訊。透過建立「carBuilder」實例並連結屬性設定方法,可以使用特定的品牌、型號、引擎和車輪值來建構汽車物件。呼叫“car.displayInfo()”顯示汽車的資訊。 **模組模式** 模組模式將相關的方法和屬性封裝到單一模組中,提供了一種乾淨的方式來組織和保護程式碼。它允許私有和公共成員,從而實現資訊隱藏並防止全域名稱空間污染。 ``` const MyModule = (function() { // Private members let privateVariable = "I am private"; function privateMethod() { console.log("This is a private method"); } // Public members return { publicVariable: "I am public", publicMethod() { console.log("This is a public method"); // Accessing private members within the module console.log(privateVariable); privateMethod(); } }; })(); // Usage console.log(MyModule.publicVariable); // Output: "I am public" MyModule.publicMethod(); // Output: "This is a public method" "I am private" "This is a private method" ``` 在此範例中,程式碼使用立即呼叫的函數表達式來封裝私人和公共成員。該模組具有私有變數和方法,以及公共變數和方法。存取時,公共成員提供預期的輸出。此模式允許對封裝的私有成員進行受控存取,同時公開選定的公共成員。 - **結構模式** 結構模式著重於組織和組合物件以形成更大的結構。它們促進物件的組合,定義物件之間的關係並提供靈活的方法來操縱其結構。 JavaScript 中一些常用的結構模式包括: - 裝飾模式 - 立面圖案 - 適配器 - 橋 - 合成的 **裝飾器模式** 裝飾器模式可讓您動態新增行為或修改物件的現有行為。它透過用一個或多個裝飾器包裝物件來增強物件的功能,而無需修改其結構。 ``` // Implementation example of the Decorator Pattern class Coffee { getCost() { return 1; } } class CoffeeDecorator { constructor(coffee) { this.coffee = coffee; } getCost() { return this.coffee.getCost() + 0.5; } } const myCoffee = new Coffee(); const coffeeWithMilk = new CoffeeDecorator(myCoffee); console.log(coffeeWithMilk.getCost()); // Output: 1.5 ``` 在此範例中,「CoffeeDecorator」類別包裝了基本「Coffee」物件並新增了附加功能。它有一個「getCost」方法,透過將基礎咖啡的成本與 0.5 的附加成本相結合來計算總成本。 在使用部分,建立了「Coffee」類別的「myCoffee」實例。然後,實例化「CoffeeDecorator」類別的「coffeeWithMilk」實例,並將「myCoffee」作為參數傳遞。當呼叫“coffeeWithMilk.getCost()”時,它會返回咖啡的總成本以及裝飾器加入的成本,從而得到 1.5 的輸出。此範例說明了裝飾器模式如何透過動態新增或修改物件的屬性或方法來擴展物件的功能。 **立面圖案** 外觀模式為複雜子系統提供了一個簡化的接口,充當隱藏底層實現細節的前端接口。它透過提供高級接口,提供了一種與複雜系統互動的便捷方式。 ``` // Implementation example of the Facade Pattern class SubsystemA { operationA() { console.log("Subsystem A operation."); } } class SubsystemB { operationB() { console.log("Subsystem B operation."); } } class Facade { constructor() { this.subsystemA = new SubsystemA(); this.subsystemB = new SubsystemB(); } operation() { this.subsystemA.operationA(); this.subsystemB.operationB(); } } const facade = new Facade(); facade.operation(); // Output: "Subsystem A operation." "Subsystem B operation." ``` 在此範例中,程式碼由三個類別組成:「SubsystemA」、「SubsystemB」和「Facade」。 `SubsystemA` 和 `SubsystemB` 類別代表獨立的子系統,並具有各自的 `operationA` 和 `operationB` 方法。 「Facade」類別作為一個簡化的接口,聚合了子系統的功能。 在使用部分,建立了“Facade”類別的“facade”實例。呼叫「facade.operation()」會觸發「SubsystemA」中的「operationA」和「SubsystemB」中的「operationB」的執行。結果,輸出顯示“子系統 A 操作”。接下來是「子系統 B 操作」。這展示了外觀模式如何提供統一且簡化的介面來與複雜的子系統交互,抽像出它們的複雜性並使它們更易於使用。 **適配器模式** 適配器模式是一種結構設計模式,它允許具有不相容介面的物件透過充當它們之間的橋樑來進行協作。它提供了一種將一個物件的介面轉換為客戶期望的另一個介面的方法。 ``` // Implementation class LegacyPrinter { printLegacy(text) { console.log(`Legacy Printing: ${text}`); } } // Target interface class Printer { print(text) {} } // Adapter class PrinterAdapter extends Printer { constructor() { super(); this.legacyPrinter = new LegacyPrinter(); } print(text) { this.legacyPrinter.printLegacy(text); } } // Usage const printer = new PrinterAdapter(); printer.print("Hello, World!"); // Output: "Legacy Printing: Hello, World!" ``` 在此程式碼中,適配器模式用於彌合「LegacyPrinter」類別和所需的「Printer」介面之間的差距。 `PrinterAdapter` 擴展了 `Printer` 類,並在內部利用 `LegacyPrinter` 來適配 `print` 方法。當呼叫 printer.print("Hello, World!")` 時,它會有效地觸發舊版列印功能,並輸出「Legacy Printing: Hello, World!」。這展示了適配器模式如何透過提供標準化介面來整合不相容的元件。 **橋樑圖案** 橋接模式是一種結構設計模式,它將系統的抽象和實現分開,允許系統獨立發展。它透過使用介面或抽象類別在兩者之間引入了橋樑。下面是一個範例程式碼片段來說明橋接模式: ``` // Example class Shape { constructor(color) { this.color = color; } draw() {} } // Concrete Abstractions class Circle extends Shape { draw() { console.log(`Drawing a ${this.color} circle`); } } class Square extends Shape { draw() { console.log(`Drawing a ${this.color} square`); } } // Implementor class Color { getColor() {} } // Concrete Implementors class RedColor extends Color { getColor() { return "red"; } } class BlueColor extends Color { getColor() { return "blue"; } } // Usage const redCircle = new Circle(new RedColor()); redCircle.draw(); // Output: "Drawing a red circle" const blueSquare = new Square(new BlueColor()); blueSquare.draw(); // Output: "Drawing a blue square" ``` 在此範例中,我們有由 Shape 類別表示的抽象,它具有顏色屬性和繪製方法。具體抽象(圓形和方形)繼承自 Shape 類別並實現其特定的繪製行為。 「Implementor」由 Color 類別表示,該類別聲明了「getColor」方法。具體的「Implementors」、「RedColor」和「BlueColor」繼承自 Color 類別並提供各自的顏色實作。 在使用部分,我們建立具體抽象的實例,傳遞適當的具體實現者物件。這允許抽象化將與顏色相關的功能委託給實現者。當我們呼叫draw方法時,它會從Implementor存取顏色並相應地執行繪圖操作。 **複合模式** 組合模式是一種結構設計模式,可讓您統一處理單一物件和物件組合。它使您能夠建立層次結構,其中每個元素都可以被視為單個物件或物件集合。此模式使用通用介面來表示單一物件(葉節點)和組合(複合節點),允許客戶端與它們統一互動。 ``` // Implementation class Employee { constructor(name) { this.name = name; } print() { console.log(`Employee: ${this.name}`); } } // Composite class Manager extends Employee { constructor(name) { super(name); this.employees = []; } add(employee) { this.employees.push(employee); } remove(employee) { const index = this.employees.indexOf(employee); if (index !== -1) { this.employees.splice(index, 1); } } print() { console.log(`Manager: ${this.name}`); for (const employee of this.employees) { employee.print(); } } } // Usage const john = new Employee("John Doe"); const jane = new Employee("Jane Smith"); const mary = new Manager("Mary Johnson"); mary.add(john); mary.add(jane); const peter = new Employee("Peter Brown"); const bob = new Manager("Bob Williams"); bob.add(peter); bob.add(mary); bob.print(); ``` 在此範例中,我們有 Component 類別 Employee,它代表個別員工。 Composite 類 Manager 擴展了 Employee 類,並且可以包含員工的集合。它提供了在集合中新增和刪除員工的方法,並重寫 print 方法以顯示經理的姓名及其下的員工。 在使用部分,我們建立一個複合層次結構,其中 Manager 物件可以包含單一員工 (Employee) 和其他經理 (Manager)。我們將員工加入經理中,建構了一個層次結構。最後,我們呼叫頂級經理的 print 方法,該方法遞歸地列印層次結構,顯示經理及其各自的員工。 - **行為模式** 行為模式關注物件之間的互動和職責分配。它們為物件之間的通訊、協調和協作提供解決方案。以下是行為模式的類型。 - 觀察者模式 - 策略模式 - 命令模式 - 迭代器模式 - 調解者模式 **觀察者模式** 觀察者模式在物件之間建立一對多關係,其中多個觀察者會收到主體狀態變化的通知。它支援物件之間的鬆散耦合並促進事件驅動的通訊。 ``` // Implementation example of the Observer Pattern class Subject { constructor() { this.observers = []; } addObserver(observer) { this.observers.push(observer); } removeObserver(observer) { const index = this.observers.indexOf(observer); if (index !== -1) { this.observers.splice(index, 1); } } notifyObservers() { this.observers.forEach((observer) => observer.update()); } } class Observer { update() { console.log("Observer is notified of changes."); } } const subject = new Subject(); const observer1 = new Observer(); const observer2 = new Observer(); subject.addObserver(observer1); subject.addObserver(observer2); subject.notifyObservers(); // Output: "Observer is notified of changes." "Observer is notified of changes." ``` 在此範例中,「Subject」類別表示一個主題,它維護觀察者清單並提供新增、刪除和通知觀察者的方法。 「Observer」類別透過其「update」方法定義觀察者的行為。在使用部分,建立了「Subject」類別的「subject」實例。也使用“addObserver”方法建立兩個“observer”實例並將其新增至主題。 當呼叫“subject.notifyObservers()”時,它會觸發每個觀察者的“update”方法。結果,輸出「觀察者收到更改通知」。被記錄兩次,顯示觀察者已被告知主題的變化。 **策略模式** 策略模式可讓您將可互換的演算法封裝在單獨的策略物件中。它支援在執行時動態選擇演算法,從而提高靈活性和可擴展性。 ``` // Implementation example of the Strategy Pattern class Context { constructor(strategy) { this.strategy = strategy; } executeStrategy() { this.strategy.execute(); } } class ConcreteStrategyA { execute() { console.log("Strategy A is executed."); } } class ConcreteStrategyB { execute() { console.log("Strategy B is executed."); } } const contextA = new Context(new ConcreteStrategyA()); contextA.executeStrategy(); // Output: "Strategy A is executed." const contextB = new Context(new ConcreteStrategyB()); contextB.executeStrategy(); // Output: "Strategy B is executed." ``` 在此範例中,「Context」類別表示封裝不同策略的上下文,具有「strategy」屬性和「executeStrategy」方法。有兩個特定策略類,“ConcreteStrategyA”和“ConcreteStrategyB”,每個類別都有自己的“execute”方法來輸出特定訊息。 在使用部分,使用“ConcreteStrategyA”作為策略來建立“Context”類別的“contextA”實例。呼叫 `contextA.executeStrategy()` 會呼叫 `ConcreteStrategyA` 的 `execute` 方法,導致輸出「策略 A 已執行」。類似地,以「ConcreteStrategyB」為策略建立「contextB」實例,呼叫「contextB.executeStrategy()」會觸發「ConcreteStrategyB」的「execute」方法,從而輸出「策略 B 已執行」。這演示了策略模式如何透過將行為封裝在不同的策略物件中來允許在執行時動態選擇行為。 **命令模式** 命令模式將請求封裝為物件,允許您使用不同的請求對客戶端進行參數化、對請求進行排隊或記錄請求,並支援撤銷操作。它將請求的發送者與接收者解耦,從而促進鬆散耦合和靈活性。 ``` // Implementation class Receiver { execute() { console.log("Receiver executes the command."); } } class Command { constructor(receiver) { this.receiver = receiver; } execute() { this.receiver.execute(); } } class Invoker { setCommand(command) { this.command = command; } executeCommand() { this.command.execute(); } } const receiver = new Receiver(); const command = new Command(receiver); const invoker = new Invoker(); invoker.setCommand(command); invoker.executeCommand(); // Output: "Receiver executes the command." ``` 在此範例中,「Receiver」類別在呼叫時執行命令,「Command」類別封裝命令並將執行委託給接收者。 `Invoker` 類別設定並執行命令。在使用部分,建立了接收者、命令和呼叫者。此指令是為呼叫者設定的,呼叫「invoker.executeCommand()」會執行該指令,從而產生輸出「接收者執行該指令」。 **迭代器模式** 迭代器模式是一種行為設計模式,它提供了一種順序存取聚合物件的元素而不暴露其底層表示的方法。它允許您以統一的方式遍歷物件集合,而不管集合的具體實現如何。該模式將遍歷邏輯與集合分開,從而促進了一種乾淨而靈活的方法來迭代元素。 ``` // Implementation class Collection { constructor() { this.items = []; } addItem(item) { this.items.push(item); } createIterator() {} } // Concrete Aggregate class ConcreteCollection extends Collection { createIterator() { return new ConcreteIterator(this); } } // Iterator class Iterator { constructor(collection) { this.collection = collection; this.index = 0; } hasNext() {} next() {} } // Concrete Iterator class ConcreteIterator extends Iterator { hasNext() { return this.index < this.collection.items.length; } next() { return this.collection.items[this.index++]; } } // Usage const collection = new ConcreteCollection(); collection.addItem("Item 1"); collection.addItem("Item 2"); collection.addItem("Item 3"); const iterator = collection.createIterator(); while (iterator.hasNext()) { console.log(iterator.next()); } ``` 在此程式碼中,我們有由 Collection 類別表示的 Aggregate,它定義了用於建立迭代器物件的介面。具體聚合「ConcreteCollection」擴展了 Collection 類別並提供了迭代器建立的具體實作。 Iterator 由 Iterator 類別表示,它定義了存取和遍歷元素的介面。具體迭代器“ConcreteIterator”擴展了迭代器類別並提供了迭代邏輯的具體實作。在使用部分,我們建立一個 Concrete Aggregate 的實例“ConcreteCollection”,並向其中新增專案。然後我們使用 createIterator 方法建立一個迭代器。透過使用迭代器的“hasNext”和 next 方法,我們迭代集合併列印每個專案。 **調解者模式** 中介者模式透過引入充當協調物件之間互動的中心樞紐的中介者物件來簡化物件溝通。它封裝了通訊邏輯,並為物件提供了註冊、發送和接收訊息的方法。 ``` // Implementation class Mediator { constructor() { this.colleague1 = null; this.colleague2 = null; } setColleague1(colleague) { this.colleague1 = colleague; } setColleague2(colleague) { this.colleague2 = colleague; } notifyColleague1(message) { this.colleague1.receive(message); } notifyColleague2(message) { this.colleague2.receive(message); } } class Colleague { constructor(mediator) { this.mediator = mediator; } send(message) { // Send a message to the mediator this.mediator.notifyColleague2(message); } receive(message) { console.log(`Received message: ${message}`); } } // Usage const mediator = new Mediator(); const colleague1 = new Colleague(mediator); const colleague2 = new Colleague(mediator); mediator.setColleague1(colleague1); mediator.setColleague2(colleague2); colleague1.send("Hello Colleague 2!"); // Output: "Received message: Hello Colleague 2!" ``` 在此範例中,我們有一個 Mediator 類,它充當兩個 Colleague 物件之間的中介。中介者保存對同事的引用並提供在他們之間發送訊息的方法。 每個Colleague物件都有一個對中介者的引用,並且可以透過通知中介者來發送訊息。調解員又將訊息轉發給適當的同事。在這種情況下,同事 1 會向同事 2 發送訊息,後者接收並記錄該訊息。 ### 結論 我們探索了 JavaScript 中的一系列基本設計模式,包括建立模式、結構模式和行為模式。建立模式使我們能夠以靈活且高效的方式建立物件。結構模式有助於器官的靈活性和可擴展性。行為模式支援 JavaScript 物件之間的有效溝通和互動。透過利用這些設計模式,JavaScript 開發人員可以提高程式碼的可重複使用性、可維護性和整體系統效能。有了這些知識,我們就可以建立健壯且高效的 JavaScript 應用程式,以滿足現代軟體開發的需求。 --- 原文出處:https://dev.to/topefasasi/js-design-patterns-a-comprehensive-guide-h3m

您必須在業餘專案中使用的 11 個免費且有趣的 API

開始一個新專案就像一次冒險起航——對開發人員來說充滿了興奮和挑戰。當您集思廣益並為您的下一件大事規劃功能時,有一個遊戲規則改變者可以讓您的旅程更加順利:API。 ![](https://media1.tenor.com/m/31nachzhSKQAAAAd/did-you-say-free.gif) 為了在不減少預算的情況下為您的專案提供所需的推動力,這裡精選了一系列最佳免費 API。它們就像您值得信賴的伙伴,可以無縫地融入您的工作中,讓您的編碼之旅更加愉快和高效。 ------------------- ### 開源API測試平台 [Firecamp](https://firecamp.dev) 是開源 API 測試工具,可協助您比以往更快地測試 API。 如果您能花 5 秒給我們一顆星,我將非常感激💜 ![octacat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5kjqmny5y0c4k4gyqcxs.png) ----- 讓我們深入探討一下: 1.[JSONPlaceholder API](https://jsonplaceholder.typicode.com/) - 幫助開發人員在使用真正的程式之前測試他們的程式。它允許您使用 HTTP 請求建立、變更和刪除虛假資料。 - 可以根據您的需求使用它可以是 JSON、CSV 和 YAML ![JSON 佔位](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x660agyk72r429p8kv2p.png) -------- 2.[OpenWeatherMap API](https://openweathermap.org/api) - 全球任何地點的即時天氣資料。 - 存取目前天氣狀況、預報和歷史資料。 - 非常適合涉及天氣預報、氣候分析或旅行計劃的應用。 -------- 3.[新聞API](https://newsapi.org/) - 總結來自世界各地各種來源的新聞文章。 - 提供即時和歷史資料,包括標題、來源和文章摘要。 - 非常適合需要即時新聞更新、內容聚合或情緒分析的應用程式。 -------- 4.[Unsplash API](https://unsplash.com/developers) - 用於應用程式和網站的高品質、免版稅圖像。 - 存取大量專業照片。 - 非常適合涉及視覺內容、設計或使用者參與的專案。 ------------ 5.[REST國家API](https://restcountries.com/) - 檢索有關國家的訊息,包括人口、面積等。 - 對於涉及地理、教育或文化探索的應用程式很有用。 ![國家 API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghsa3b5eev6xnydsgo6s.png) ------------ 6.[Randomuser.me API](https://randomuser.me/) - 產生隨機用戶資料,包括姓名、地址和個人資料圖片。 - 非常適合在不使用真實用戶資料的情況下測試和原型應用程式。 ------------ 7.[JokeAPI](https://jokeapi.dev/) - 透過大量笑話將幽默融入您的專案中。 - 非常適合娛樂應用程式或為您的網站加入輕鬆的感覺。 ------------ 8.[匯率-API](https://www.exchangerate-api.com/) - 存取各種貨幣的即時和歷史匯率。 - 對於涉及電子商務、金融或旅遊的專案至關重要。 ------------ 9.【NASA開放API】(https://api.nasa.gov/) - 從 NASA 的大量收藏中檢索資料,包括圖像、影片和天文學資料。 - 非常適合教育計畫、太空愛好者或任何對宇宙探索感興趣的人。 ------------ 10.[COVID-19資料API](https://covid19api.com/) - 隨時了解全球 COVID-19 即時統計資料。 - 對於專注於健康、資料視覺化或流行病監測的應用程式很有用。 ------------ 11.[圖書API](https://openlibrary.org/developers/api) - 開放式庫提供了一套 API 來幫助開發人員啟動並執行我們的資料。其中包括 RESTful API,它使 Open Library 資料可以採用 JSON、YAML 和 RDF/XML 格式。 ------------ 這些 API 涵蓋了廣泛的功能,可讓您為專案加入不同的功能,而不會產生額外的成本。 請務必瀏覽他們的文件,以便無縫整合到您的開發工作流程中。 您還記得您為有趣的專案嘗試的第一個 API 嗎?在下面評論並與社區分享。 下週見!! 🙏 --- 原文出處:https://dev.to/firecampdev/11-free-and-fun-apis-you-must-use-in-your-side-project-219m

Supabase Studio:AI 助理和使用者模擬

在上一個發布週期間,我們在 Supabase Studio 的 SQL 編輯器中引入了文字到 SQL。這是我們邁向完整人工智慧助理的第一步。 今天,我們將介紹 Supabase Assistant,這是儀表板內的人工智慧助手,以及一些新功能,可幫助您更快地從創意到生產。 https://youtu.be/hu2SQjvCXIw 這是鳥瞰圖: - **行級安全策略:** 透過 AI 輕鬆實現 - **Postgres 角色:** 更改工作室的 Postgres 角色 - **使用者模擬:**視覺化您的安全策略 - **即時檢查器:**檢查和除錯即時請求 - **功能預覽:** 查看 Studio 中的熱門新聞 ## 介紹 Supabase 助手 我們很高興能夠透過新的 **Supabase Assistant 擴展 Studio 的 AI 功能。** 開發人員告訴我們,SQL 編輯器中的文字到 SQL 功能大大提高了他們的速度(以及他們的 SQL 能力)。當人工智慧與基於模式的資料庫(如 Postgres)結合使用時,它的功能非常強大,因為它可以從模式中推斷出大量上下文,並且資料庫為生成的程式碼提供了更嚴格的保證。我們先前的版本堅定了我們的信念,即人工智慧將成為未來資料庫開發的關鍵部分。 今天,我們在行級安全編輯器中推出了 Assistant 支持,並且很快就會擴展到 Studio 中的其他位置:表編輯器、Postgres 函數、無伺服器函數等。 讓我們先進入行級安全性。 ![ai 動畫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fisvxtbux1awm6j169zt.gif) ## 透過 AI 實現簡單的 RLS 策略 在我們收到的所有功能請求中(而且我們收到了很多!),編寫[行級安全性](https://supabase.com/docs/guides/auth/row-level-security)策略的更簡單方法是其中之一最頻繁的。 行級安全性 (RLS) 是 Postgres 的一項功能,可提供對資料庫的細粒度存取。雖然 RLS 很強大,但編寫策略可能是一件苦差事。今天,我們發布了一款基於 AI 的 RLS 編輯器,讓編寫安全策略變得簡單。 新的 RLS 編輯器將 SQL 置於中心位置。我們希望讓開發人員能夠充分發揮 Postgres 的潛力,而不是將其抽象化。這個編輯器其實是兩個工具: 1. SQL 編輯器:如果您非常了解 SQL,那麼有一個新的編輯器可以讓您快速編寫策略。 2. 助手:如果您是 RLS 新手並需要幫助,您可以使用助手並透過它進行聊天。 ![範例 SQL 編輯器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p943tvovzrdvq4g5sh4p.jpg) 此助手經過調整,可產生用於行級安全性的 SQL,以便快速、輕鬆地按照您需要的方式設定策略。 我們探索了 RLS 編輯器的各種方法和設計。這種 SQL 優先的方法在人工智慧的幫助下,感覺就像我們一直在尋找的解決方案。現在可以透過功能預覽啟用新的 RLS 編輯器(更多資訊請見下文)。我們很樂意[聽到您的回饋。](https://github.com/orgs/supabase/discussions/19594) ## Postgres 角色 您可能從未想過這一點,但 Studio 就像任何其他 Postgres 用戶端一樣連接到您的資料庫。 它使用預設的[Postgres角色](https://supabase.com/docs/guides/database/postgres/roles),`postgres`。 「postgres」角色的功能類似於「服務角色」金鑰,授予它對資料庫的管理權限。它具有管理員讀寫權限,並繞過行級安全性。 如果您使用我們的客戶端程式庫,您將熟悉「anon」和「service_role」 API 金鑰。這些鍵實際上解析為 Postgres 角色,也稱為“anon”和“service_role”。這些密鑰實際上是包含 Postgres 角色的 JWT 令牌: ``` { "role": "service_role", // the Postgres role "iss": "supabase" // the issuer of the JWT "exp": 1445385600, // the time the JWT will expire } ``` 如果您可以使用在應用程式中使用的相同 Postgres 角色在 Studio 中執行查詢會怎麼樣?如果您可以讓 Studio 假裝使用與預設「postgres」角色不同的角色怎麼辦?今天,您可以: ![儀表板螢幕截圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xkzq8ij94q3dainfu7fh.jpg) 您可以使用新的角色下拉清單為 Studio 中的查詢選擇不同的 Postgres 角色。這是一個強大的工具,用於測試行級安全策略並確定每個角色可以存取哪些資料。 讓我們建立一個 Twitter/X 克隆來進行說明。在 Twitter 克隆中,您: - 有一個包含「user_id」和「content」等欄位的推文表。 - 可以設定行級安全性,以便只有推文的作者才能存取和修改自己的推文。 - 只能查看和編輯您撰寫的推文。 當我們使用“postgres”角色進行查詢時,我們可以看到所有資料。當我們使用“anon”查詢時,不會傳回任何資料。這是有道理的,因為我們尚未建立允許「匿名」存取此表的策略。 角色下拉清單解鎖了另一個方便的功能:與 Supabase Auth 結合使用時,它甚至可以假裝是不同的使用者。 ## 使用者模擬 還記得上面的 API 金鑰嗎?它們可以包含一個附加字段:“sub”。這是用戶的 ID。當您使用「authenticated」角色時,「sub」欄位是登入您的應用程式的使用者的ID: ``` { "sub": "348b-some-user-uuid", // the ID of the user "role": "authenticated", // the Postgres role "iss": "supabase" // the issuer of the JWT "exp": 1445385600, // the time the JWT will expires } ``` 我們可以透過使用使用者 ID「建立」JWT,然後使用該 JWT 執行查詢來模擬 Studio 中的使用者。 在我們編寫 RLS 策略以允許用戶查看自己的推文後,讓我們看看它的實際效果。在這裡,我們可以選擇「已驗證」角色,並選擇特定用戶以僅查看他們的推文。以下是我們所有用戶的推文: ![模擬](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h75mldhwms2dphazxbz4.jpg) 表編輯器現在正在模擬我們的用戶。 您可以模擬專案中的任何用戶,並按照他們的方式查看事物。您的 RLS 政策中的任何條件都會自動反映在表中。 ✨ 魔法 ✨ 您可以直接從 Studio 建立 RLS 策略並測試它們是否完全按照您的預期運作。 表格編輯器的樂趣不止於此。我們還為 SQL 編輯器和 GraphiQL 新增了角色支援。讓我們透過嘗試在 SQL 編輯器中選擇我們自己的推文清單來重複上面所做的事情: ![模擬](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0z3x5on9e12iykj5ep6r.jpg) 在 GraphiQL 中: ![範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cd34tao8o2e17ln7ut3u.jpg) 將此功能與新的 RLS 編輯器結合,您可以在幾分鐘內使用真實資料編寫和測試 RLS 策略。這使得編寫 RLS 策略的過程變得更快、更容易。如果您有回饋,[我們很樂意聽到。](https://github.com/orgs/supabase/discussions/19595) ## 即時檢查器 Supabase [Realtime](https://supabase.com/realtime) 非常適合建立協作應用程式。您可以透過 Websocket 接收資料庫更改,儲存和同步有關使用者狀態的資料,以及透過「通道」向客戶端廣播任何資料。 今天,我們發布了 Realtime Inspector:一種直接在 Studio 中進行 Realtime 原型設計、檢查和除錯的簡單方法。您可以使用即時檢查器查看通道中發送和接收的訊息。您可以按類型篩選訊息:狀態、廣播和資料庫變更。 ![即時範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9uaha9mddogmufvv8dnq.jpg) 當然,我們也在這裡新增了「角色」下拉清單。您可以按角色查看事件並模擬用戶,就像表和 SQL 編輯器一樣。 如果您使用 Realtime,您會發現新的檢查器非常方便。 ## 功能預覽 今天,我們發布了**功能預覽**,這是我們用於推出新功能的工具。在普遍可用之前,我們會以預覽版的形式發布 Beta 功能。您可以看到可用於預覽的功能清單以及螢幕截圖和簡要說明。每個功能都包含一個指向 Github 討論以獲取反饋的連結。 我們對功能預覽有幾個目標。我們想: - 更快地向您提供功能 - 讓您更輕鬆地向我們提供回饋 - 縮短迭代循環 我們越快地迭代您的回饋,我們就能越快將功能發佈到普遍使用中。 雖然我們認為這些功能是測試版,但請注意,我們非常重視您的安全、隱私和資料完整性。我們發佈到預覽版的任何內容都會考慮到這一點進行測試,並且處於我們正在尋找 UX/UI 回饋的階段。 您可以在左下角的使用者頭像選單下找到我們的功能預覽: ![畫面範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4wmylco7j28jydqtssfx.jpg) 目前我們有兩個預覽功能: 1. 我們之前看到的新 RLS 助手: ![RLS 範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vyrme13gh3hel13e76sq.jpg) 2. 以及修改後的 API 側面板: ![API 面板](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nlmbk8xcs2rjh2d6t0pm.jpg) 我們將積極關注 Github 討論並回覆您的回饋。 ## 總結 在此更新中,我們在增強您的 Supabase 體驗方面取得了巨大進展。 1. **行級安全策略:** 在新助理的幫助下,我們比以往任何時候都更容易建立行級安全策略。此功能極大地簡化了定義對資料的細粒度存取的過程。 2. **Postgres 角色和使用者模擬:** 我們的新角色選擇器可讓您直接在 Studio 中視覺化安全策略的影響。這使您可以了解不同角色如何與資料交互,從而為測試存取控制提供強大的工具。 3. **即時檢查器:** 使用即時檢查器,您可以原型設計、檢查和偵錯即時訊息。這個工具對於使用 Supabase Realtime 的人來說非常有用。 4. **功能預覽:** 我們推出了功能預覽,為您帶來測試階段的新工具和功能,讓您更輕鬆地提供回饋並塑造開發流程。 這些更新反映了我們對 SQL 優先方法和以使用者為中心的開發的承諾。我們期待您的回饋,我們將繼續努力讓 Supabase 更快、更輕鬆地讓您的想法付諸實現。 ## 更多發布第 X 週 - [Postgres語言伺服器:實作解析器](https://supabase.com/blog/postgres-language-server-implementing-parser) - [Supabase 設計如何運作](https://supabase.com/blog/how-design-works-at-supabase) - [Supabase 專輯](https://www.youtube.com/watch?v=r1POD-IdG-I) - [Supabase 啟動週 X 黑客松](https://supabase.com/blog/supabase-hackathon-lwx) - [啟動週 X 社群聚會](https://supabase.com/blog/community-meetups-lwx) --- 原文出處:https://dev.to/supabase/supabase-studio-ai-assistant-and-user-impersonation-22mn

如何成為 10 倍速明星開發人員

如今,每個人都想成為我們所謂的「10 倍開發人員」。然而,這個術語經常被誤解和高估。 從本質上講,在我看來,高效或10 倍開發人員是指能夠利用所有可用工具來發揮其優勢的人,讓這些工具處理冗餘和重複性的任務,並使他能夠專注於複雜和創造性的工作。以下是成為 10 倍開發人員的一些提示和技巧: ## 使用腳本自動執行重複任務: 對於尋求優化工作流程的開發人員來說,透過腳本自動執行重複任務是一個遊戲規則改變者。 透過弄清楚哪些任務可以自動化,例如測試和部署,然後讓腳本處理它們,開發人員可以專注於工作中更具挑戰性的部分,並在過程中節省大量時間。 例如,此腳本建立一個新的專案資料夾,由使用者輸入命名,並在檔案總管中開啟它: ``` import os import subprocess def create_project_folder(project_name): # Create a new folder for the project os.makedirs(project_name) # Open the project folder in the file explorer subprocess.run(['explorer', project_name]) # Get the project name from the user project_name = input("Enter the name of your new project: ") # Call the function to create and open the project folder create_project_folder(project_name) ``` ## 鍵盤快速鍵掌握: 掌握程式碼編輯器或 IDE 中的鍵盤快速鍵對於加快編碼工作流程至關重要。 VS 程式碼的一些快捷方式範例: `Ctrl + P`:快速檔案導航,讓您可以按名稱開啟檔案。 `Ctrl + Shift + L`:選取目前單字的所有出現位置。 `Ctrl + /`:切換行註釋 `Ctrl + A`:選擇目前檔案中的所有行 `Ctrl + F`:尋找程式碼中的特定文本 `Ctrl + Shift + P`:開啟各種指令的指令面板。 `Alt + 向上/向下箭頭`:向上或向下移動目前行。 `Shift + 右箭頭 (→)`:選擇遊標右側的字元。 `Shift + 向左箭頭 (←)`:選擇遊標左側的字元。 「Alt + 點擊」:按住 Alt 鍵並點擊程式碼中的不同位置以建立多個遊標,從而允許您同時在這些位置進行編輯或鍵入。 ## 不要過度設計: 避免過度設計解決方案的誘惑。加入不必要的程式碼或架構複雜性是許多工程師和程式設計師遇到的常見陷阱。 然而,保持簡單不僅有利於您目前的工作流程,而且還可以讓其他人在將來更容易理解您的程式碼並就您的程式碼進行協作。 ## 掌握版本控制工作流程: 善於使用版本控制工作流程(例如使用 Git)將極大地提高您的工作效率,並幫助您的團隊在不妨礙彼此的情況下協同工作。 特別是使用 GitKraken 等工具或任何其他 GUI 替代品,提供直覺的介面,簡化分支、合併和追蹤變更等任務,使協作更加順暢。 ![GitKraken 網站圖片](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggegydp0qnryv7cbszuk.png) 如果出現問題,您可以輕鬆恢復到先前的狀態。這就像有一個安全網,可以確保每個人的工作順利配合,從而使建立軟體的整個過程更快、壓力更小。 ## 利用現有元件和函式庫: 不要重新發明輪子,而是使用經過嘗試和測試的可用解決方案。這不僅節省時間,而且使您的程式碼更加可靠和有效率。 這種方法使您能夠更多地關注專案的獨特方面。這是一種明智的策略,可以提高生產力並建立強大的軟體,而無需從頭開始。 ## 採用 HTML Emmet 進行快速原型設計: Emmet 是一個針對 Web 開發人員的工具包,可透過縮寫快速且有效率地進行編碼。 如果您使用 HTML,Emmet 可以顯著加快建立 HTML 結構的過程。 例子: ``` div>(header>ul>li*2>a)+footer>p ``` 輸出: ``` <div> <header> <ul> <li><a href=""></a></li> <li><a href=""></a></li> </ul> </header> <footer> <p></p> </footer> </div> ``` ## 利用人工智慧協助: - **GitHub 副駕駛:** 是 GitHub 與 OpenAI 合作開發的人工智慧驅動的程式碼補全工具。它透過在開發人員鍵入時產生智慧建議和自動完成來改變開發人員編寫程式碼的方式。這是迄今為止我嘗試過的最好的人工智慧工具之一。 ![GitHub Copilot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/822ubh3qe2lyezubbva5.png) - **標籤九:** 是一個人工智慧驅動的程式碼編輯器自動完成擴充。它超越了傳統的自動完成功能,使用機器學習模型來預測和建議整行或程式碼區塊。 用戶可以選擇免費使用 TabNine,但有一些限制,也可以透過訂閱來選擇專業版以獲得高級功能。 [TabNine](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68un8zingjmsvnuk5pyl.png) - **聊天gpt :** ChatGPT 可以真正改變您的工作效率。例如,它可以提供有用的範例,例如建議用於測試的陣列或幫助重建程式碼片段。 ![Chatgpt 範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hi8hskndin82w2vgx10l.png) 如果您在程式設計概念上遇到困難或需要澄清,ChatGPT 可以提供快速且易於理解的解釋。這就像擁有一位知識淵博的編碼夥伴,24/7 全天候幫助您應對編碼挑戰,使您的開發過程更加順暢和高效。 ## VS 程式碼中的擴充: VS Code 中的擴充功能可以透過加入功能、自動化任務和增強開發環境來顯著提高工作效率: - **更漂亮:** Prettier 是一個固執己見的程式碼格式化程序,它會自動格式化您的程式碼,使其看起來乾淨且一致,從而使您免於手動格式化的麻煩。有了 Prettier,您的程式碼變得更加賞心悅目,您可以更加專注於編寫邏輯,而不必擔心樣式。 ![更漂亮的擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gurx061173zhqjd8lvvq.png) - **自動重新命名標籤:** 自動重命名標籤擴充就像 HTML 或 XML 的編碼助手。當您變更開始標記的名稱時,此擴充功能會自動更新結束標記以符合。 ![自動重新命名標籤擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q31o7ljpjl3ciysch7b5.png) - **更好的評論:** Better Comments 擴充功能將幫助您在程式碼中建立更人性化的註解。透過此擴展,您將能夠對註釋進行分類。 ![更好的評論擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4f45e3cjl34mcs94rx6.png) - **智慧感知:** IntelliSense 是您的程式設計助手,可在您鍵入時提供智慧程式碼補全和建議。它預測您的需求並提供相關選項,使編碼更加有效率。一些範例: ![Tailwind CSS IntelliSense 擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kcjdqgwg5n6dgn4naeuz.png) ![路徑智慧感知擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9c1hvrb4l60mx6l2mp32.png) ![npm Intellisense 擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yo40qrvwsplnbvzc2wn3.png) - **孔雀:** 當您處理大量專案並在 VSCode 視窗之間跳轉時,Peacock 非常有用。它允許您將顏色連結到每個專案,因此每當您打開它時,您都可以透過顏色快速查看您所在的視窗。 ![孔雀擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gncbyqxup6iwa353q3vt.png) --- **總而言之**,結合這些策略和工具可以真正徹底改變您的編碼方法,將您轉變為更有效率、更有效率的開發人員。擁抱 10 倍思維不僅可以提高個人生產力,還可以為您的團隊做出積極貢獻。因此,繼續實施這些技巧,並觀察您的編碼之旅進入一個全新的水平。 --- 原文出處:https://dev.to/idboussadel/how-to-become-a-10x-dev-ake

大資料模型 📊 與電腦記憶體 💾

資料管道是任何資料密集型專案的支柱。 **隨著資料集的成長**超出記憶體大小(「核心外」),**有效處理它們變得具有挑戰性**。 Dask 可以輕鬆管理大型資料集(核心外),提供與 Numpy 和 Pandas 的良好相容性。 ![管道](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m6nswebbzlo96ml1ofeb.png) --- 本文重點介紹 **Dask(用於處理核心外資料)與 Taipy** 的無縫集成,Taipy** 是一個用於 **管道編排和場景管理** 的 Python 庫。 --- ## Taipy - 您的 Web 應用程式建構器 關於我們的一些資訊。 **Taipy** 是一個開源程式庫,旨在輕鬆開發前端 (GUI) 和 ML/資料管道。 不需要其他知識(沒有 CSS,什麼都不需要!)。 它旨在加快應用程式開發,從最初的原型到生產就緒的應用程式。 ![QueenB 星星](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bvt5qn1yadra3epnb07v.gif) https://github.com/Avaiga/taipy 我們已經快有 1000 顆星了,沒有你就無法做到這一點🙏 --- ## 1. 範例應用程式 透過範例最好地演示了 Dask 和 Taipy 的整合。在本文中,我們將考慮包含 4 個任務的資料工作流程: - **資料預處理與客戶評分** 使用 Dask 讀取和處理大型資料集。 - **特徵工程和分割** 根據購買行為對客戶進行評分。 - **細分分析** 根據這些分數和其他因素將客戶分為不同的類別。 - **高價值客戶的總統計** 分析每個客戶群以獲得見解 我們將更詳細地探討這 4 個任務的程式碼。 請注意,此程式碼是您的 Python 程式碼,並未使用 Taipy。 在後面的部分中,我們將展示如何使用 Taipy 對現有資料應用程式進行建模,並輕鬆獲得其工作流程編排的好處。 --- 該應用程式將包含以下 5 個檔案: ``` algos/ ├─ algo.py # Our existing code with 4 tasks data/ ├─ SMALL_amazon_customers_data.csv # A sample dataset app.ipynb # Jupyter Notebook for running our sample data application config.py # Taipy configuration which models our data workflow config.toml # (Optional) Taipy configuration in TOML made using Taipy Studio ``` --- ## 2. Taipy 簡介 - 綜合解決方案 [Taipy](https://docs.taipy.io/) **不只是另一個編排工具**。 Taipy 專為 ML 工程師、資料科學家和 Python 開發人員設計,帶來了幾個基本且簡單的功能。 以下是**一些關鍵要素**,使 Taipy 成為令人信服的選擇: 1. **管道執行註冊表** 此功能使開發人員和最終用戶能夠: - 將每個管道執行註冊為「*場景*」(任務和資料節點圖); - 精確追蹤每個管道執行的沿襲;和 - 輕鬆比較場景、監控 KPI 並為故障排除和微調參數提供寶貴的見解。 2. **管道版本控制** Taipy 強大的場景管理使您能夠輕鬆調整管道以適應不斷變化的專案需求。 3. **智能任務編排** Taipy 讓開發人員可以輕鬆地對任務和資料來源網路進行建模。 此功能透過以下方式提供對任務執行的內建控制: - 並行執行您的任務;和 - 任務“跳過”,即選擇要執行的任務並 要繞過哪個。 4. **任務編排的模組化方法** 模組化不僅僅是 Taipy 的一個流行詞;這是一個核心原則。 設定可以互換使用的任務和資料來源,從而產生更乾淨、更易於維護的程式碼庫。 --- ## 3. Dask 簡介 Dask 是一個流行的分散式運算 Python 套件。 Dask API 實作了熟悉的 Pandas、Numpy 和 Scikit-learn API - ,這使得許多已經熟悉這些 API 的資料科學家更愉快地學習和使用 Dask。 如果您是 Dask 新手,請查看 Dask 團隊撰寫的精彩 Dask [10 分鐘簡介](https://docs.dask.org/en/stable/10-minutes-to-dask.html)。 --- ## 4. 應用:顧客分析 (*algos/algo.py*) ![DAG 架構](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ru69b6jmhl73s9xxx2n.png) *我們的 4 項任務的圖表(在 Taipy 中可視化),我們將在下一節中對其進行建模。* 我們現有的程式碼(不含 Taipy)包含 4 個函數,您也可以在上圖中看到: - 任務 1:*預處理和評分* - 任務 2:*特徵化與細分* - 任務 3:*分段分析* - 任務 4:*high_value_cust_summary_statistics* 您可以瀏覽以下定義了 4 個函數的 *algos/algo.py* 腳本,然後繼續閱讀每個函數的簡要說明: ``` ### algos/algo.py import time import dask.dataframe as dd import pandas as pd def preprocess_and_score(path_to_original_data: str): print("__________________________________________________________") print("1. TASK 1: DATA PREPROCESSING AND CUSTOMER SCORING ...") start_time = time.perf_counter() # Start the timer # Step 1: Read data using Dask df = dd.read_csv(path_to_original_data) # Step 2: Simplify the customer scoring formula df["CUSTOMER_SCORE"] = ( 0.5 * df["TotalPurchaseAmount"] / 1000 + 0.3 * df["NumberOfPurchases"] / 10 + 0.2 * df["AverageReviewScore"] ) # Save all customers to a new CSV file scored_df = df[["CUSTOMER_SCORE", "TotalPurchaseAmount", "NumberOfPurchases", "TotalPurchaseTime"]] pd_df = scored_df.compute() end_time = time.perf_counter() # Stop the timer execution_time = (end_time - start_time) * 1000 # Calculate the time in milliseconds print(f"Time of Execution: {execution_time:.4f} ms") return pd_df def featurization_and_segmentation(scored_df, payment_threshold, score_threshold): print("__________________________________________________________") print("2. TASK 2: FEATURE ENGINEERING AND SEGMENTATION ...") # payment_threshold, score_threshold = float(payment_threshold), float(score_threshold) start_time = time.perf_counter() # Start the timer df = scored_df # Feature: Indicator if customer's total purchase is above the payment threshold df["HighSpender"] = (df["TotalPurchaseAmount"] > payment_threshold).astype(int) # Feature: Average time between purchases df["AverageTimeBetweenPurchases"] = df["TotalPurchaseTime"] / df["NumberOfPurchases"] # Additional computationally intensive features df["Interaction1"] = df["TotalPurchaseAmount"] * df["NumberOfPurchases"] df["Interaction2"] = df["TotalPurchaseTime"] * df["CUSTOMER_SCORE"] df["PolynomialFeature"] = df["TotalPurchaseAmount"] ** 2 # Segment customers based on the score_threshold df["ValueSegment"] = ["High Value" if score > score_threshold else "Low Value" for score in df["CUSTOMER_SCORE"]] end_time = time.perf_counter() # Stop the timer execution_time = (end_time - start_time) * 1000 # Calculate the time in milliseconds print(f"Time of Execution: {execution_time:.4f} ms") return df def segment_analysis(df: pd.DataFrame, metric): print("__________________________________________________________") print("3. TASK 3: SEGMENT ANALYSIS ...") start_time = time.perf_counter() # Start the timer # Detailed analysis for each segment: mean/median of various metrics segment_analysis = ( df.groupby("ValueSegment") .agg( { "CUSTOMER_SCORE": metric, "TotalPurchaseAmount": metric, "NumberOfPurchases": metric, "TotalPurchaseTime": metric, "HighSpender": "sum", # Total number of high spenders in each segment "AverageTimeBetweenPurchases": metric, } ) .reset_index() ) end_time = time.perf_counter() # Stop the timer execution_time = (end_time - start_time) * 1000 # Calculate the time in milliseconds print(f"Time of Execution: {execution_time:.4f} ms") return segment_analysis def high_value_cust_summary_statistics(df: pd.DataFrame, segment_analysis: pd.DataFrame, summary_statistic_type: str): print("__________________________________________________________") print("4. TASK 4: ADDITIONAL ANALYSIS BASED ON SEGMENT ANALYSIS ...") start_time = time.perf_counter() # Start the timer # Filter out the High Value customers high_value_customers = df[df["ValueSegment"] == "High Value"] # Use summary_statistic_type to calculate different types of summary statistics if summary_statistic_type == "mean": average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].mean() elif summary_statistic_type == "median": average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].median() elif summary_statistic_type == "max": average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].max() elif summary_statistic_type == "min": average_purchase_high_value = high_value_customers["TotalPurchaseAmount"].min() median_score_high_value = high_value_customers["CUSTOMER_SCORE"].median() # Fetch the summary statistic for 'TotalPurchaseAmount' for High Value customers from segment_analysis segment_statistic_high_value = segment_analysis.loc[ segment_analysis["ValueSegment"] == "High Value", "TotalPurchaseAmount" ].values[0] # Create a DataFrame to hold the results result_df = pd.DataFrame( { "SummaryStatisticType": [summary_statistic_type], "AveragePurchaseHighValue": [average_purchase_high_value], "MedianScoreHighValue": [median_score_high_value], "SegmentAnalysisHighValue": [segment_statistic_high_value], } ) end_time = time.perf_counter() # Stop the timer execution_time = (end_time - start_time) * 1000 # Calculate the time in milliseconds print(f"Time of Execution: {execution_time:.4f} ms") return result_df ``` --- ### 任務 1 - 資料預處理與客戶評分 Python 函數:*preprocess_and_score* 這是管道中的第一步,也許也是最關鍵的一步。 它使用 **Dask** 讀取大型資料集,專為大於記憶體的計算而設計。 然後,它根據“*TotalPurchaseAmount*”、“*NumberOfPurchases*”和“*AverageReviewScore*”等各種指標,在名為 *scored_df* 的 DataFrame 中計算“*Customer Score*”。 使用 Dask 讀取和處理資料集後,此任務將輸出一個 Pandas DataFrame,以供其餘 3 個任務進一步使用。 --- ### 任務 2 - 特徵工程與分割 Python 函數:*featureization_and_segmentation* 此任務採用評分的 DataFrame 並新增功能,例如高支出指標。 它還根據客戶的分數對客戶進行細分。 --- ### 任務 3 - 細分分析 Python 函數:*segment_analysis* 此任務採用分段的 DataFrame 並根據客戶細分執行分組分析以計算各種指標。 --- ### 任務 4 - 高價值客戶的總統計 Python 函數:*high_value_cust_summary_statistics* 此任務對高價值客戶群進行深入分析並傳回匯總統計資料。 --- ## 5. 在 Taipy 中建模工作流程 (*config.py*) ![工作室中的 DAG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5kyz7k3akkcbs48psodi.png) *Taipy DAG — Taipy「任務」為橘色,「資料節點」為藍色。* 在本節中,我們將建立對變數/參數進行建模的Taipy 配置(表示為[“資料節點”](https://docs.taipy.io/en/latest/manuals/core/concepts/data-node/ ))和 Taipy 中的函數(表示為 [“Tasks”](https://docs.taipy.io/en/latest/manuals/core/concepts/task/))。 --- 請注意,以下 *config.py* 腳本中的此配置類似於定義變數和函數 - 只不過我們定義的是「藍圖變數」(資料節點)和「藍圖函數」(任務)。 我們通知 Taipy 如何呼叫我們之前定義的函數、資料節點的預設值(我們可能會在執行時覆蓋)以及是否可以跳過任務: ``` ### config.py from taipy import Config from algos.algo import ( preprocess_and_score, featurization_and_segmentation, segment_analysis, high_value_cust_summary_statistics, ) # -------------------- Data Nodes -------------------- path_to_data_cfg = Config.configure_data_node(id="path_to_data", default_data="data/customers_data.csv") scored_df_cfg = Config.configure_data_node(id="scored_df") payment_threshold_cfg = Config.configure_data_node(id="payment_threshold", default_data=1000) score_threshold_cfg = Config.configure_data_node(id="score_threshold", default_data=1.5) segmented_customer_df_cfg = Config.configure_data_node(id="segmented_customer_df") metric_cfg = Config.configure_data_node(id="metric", default_data="mean") segment_result_cfg = Config.configure_data_node(id="segment_result") summary_statistic_type_cfg = Config.configure_data_node(id="summary_statistic_type", default_data="median") high_value_summary_df_cfg = Config.configure_data_node(id="high_value_summary_df") # -------------------- Tasks -------------------- preprocess_and_score_task_cfg = Config.configure_task( id="preprocess_and_score", function=preprocess_and_score, skippable=True, input=[path_to_data_cfg], output=[scored_df_cfg], ) featurization_and_segmentation_task_cfg = Config.configure_task( id="featurization_and_segmentation", function=featurization_and_segmentation, skippable=True, input=[scored_df_cfg, payment_threshold_cfg, score_threshold_cfg], output=[segmented_customer_df_cfg], ) segment_analysis_task_cfg = Config.configure_task( id="segment_analysis", function=segment_analysis, skippable=True, input=[segmented_customer_df_cfg, metric_cfg], output=[segment_result_cfg], ) high_value_cust_summary_statistics_task_cfg = Config.configure_task( id="high_value_cust_summary_statistics", function=high_value_cust_summary_statistics, skippable=True, input=[segment_result_cfg, segmented_customer_df_cfg, summary_statistic_type_cfg], output=[high_value_summary_df_cfg], ) scenario_cfg = Config.configure_scenario( id="scenario_1", task_configs=[ preprocess_and_score_task_cfg, featurization_and_segmentation_task_cfg, segment_analysis_task_cfg, high_value_cust_summary_statistics_task_cfg, ], ) ``` 號 您可以在[此處的文件](https://docs.taipy.io/en/latest/manuals/core/config/)中閱讀有關配置場景、任務和資料節點的更多資訊。 --- ### Taipy Studio [Taipy Studio](https://docs.taipy.io/en/latest/manuals/studio/config/) **是來自Taipy 的VS Code 擴充功能**,讓您**透過簡單的方式建置和視覺化您的管道拖放互動**。 Taipy Studio 提供了一個圖形編輯器,您可以在其中建立 Taipy 配置**存儲在 TOML 文件中**,您的 Taipy 應用程式可以加載並執行這些配置。 編輯器將場景表示為圖形,其中節點是資料節點和任務。 --- *作為本節中 config.py 腳本的替代方案,您可以使用 Taipy Studio 產生 config.toml 設定檔。 本文的倒數第二部分將提供有關如何使用 Taipy Studio 建立 config.toml 設定檔的指南。* --- ## 6. 場景建立與執行 執行 Taipy 場景涉及: - 載入配置; - 執行 Taipy Core 服務;和 - 建立並提交場景以供執行。 這是基本的程式碼模板: ``` import taipy as tp from config import scenario_cfg # Import the Scenario configuration tp.Core().run() # Start the Core service scenario_1 = tp.create_scenario(scenario_cfg) # Create a Scenario instance scenario_1.submit() # Submit the Scenario for execution # Total runtime: 74.49s ``` --- ### 跳過不必要的任務執行 Taipy 最實用的功能之一是,如果任務的輸出已經計算出來,它能夠跳過任務執行。 讓我們透過一些場景來探討這一點: --- #### 更改付款閾值 ``` # Changing Payment Threshold to 1600 scenario_1.payment_threshold.write(1600) scenario_1.submit() # Total runtime: 31.499s ``` *發生了什麼事*:Taipy 夠聰明,可以跳過任務 1,因為付款閾值只影響任務 2。 在這種情況下,透過使用 Taipy 執行管道,我們發現執行時間減少了 50% 以上。 --- #### 更改細分分析指標 ``` # Changing metric to median scenario_1.metric.write("median") scenario_1.submit() # Total runtime: 23.839s ``` *會發生什麼事*:在這種情況下,只有任務 3 和任務 4 受到影響。 Taipy 巧妙地跳過任務 1 和任務 2。 --- #### 更改總計統計類型 ``` # Changing summary_statistic_type to max scenario_1.summary_statistic_type.write("max") scenario_1.submit() # Total runtime: 5.084s ``` *發生了什麼事*:這裡,只有任務 4 受到影響,Taipy 僅執行此任務,跳過其餘任務。 Taipy 的智慧任務跳過功能不僅能節省時間,還能節省時間。它是一個資源優化器,在處理大型資料集時變得非常有用。 --- ## 7. Taipy Studio 您可以使用 Taipy Studio 建置 Taipy *config.toml* 設定檔來取代定義 *config.py* 腳本。 ![Studio 內的 DAG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct0bcisreqmg56mk4fgm.png) 首先,使用擴展市場安裝 [Taipy Studio ](https://marketplace.visualstudio.com/items?itemName=Taipy.taipy-studio)擴充。 --- ### 建立配置 - **建立設定檔**:在 VS Code 中,導覽至 Taipy Studio,然後透過點擊參數視窗上的 + 按鈕啟動新的 TOML 設定檔。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8jqe1fq87jaauf56b7hg.png) - 然後右鍵單擊它並選擇 **Taipy:顯示視圖**。 ![配置顯示視圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7rkyipli0oq13iw8mxc.png) - **新增實體**到您的 Taipy 配置: 在 Taipy Studio 的右側,您應該會看到一個包含 3 個圖示的列表,可用於設定管道。 ![配置圖示](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tyxvv15nu9xr87n5y7q1.png) 1. 第一項是新增資料節點。您可以將任何 Python 物件連結到 Taipy 的資料節點。 2. 第二項用於新增任務。任務可以連結到預先定義的 Python 函數。 3. 第三項是新增場景。 Taipy 讓您在一個配置中擁有多個場景。 --- #### - 資料節點 **輸入資料節點**:建立一個名為“*path_to_data*”的資料節點,然後導航到“詳細資料”選項卡,新增屬性“*default_data*”,並將“*SMALL_amazon_customers_data.csv*”貼上為您的資料的路徑資料集。 --- **中間資料節點**:我們需要再增加四個資料節點:「*scored_df*」、「*segmented_customer_df*」、「*segment_result*」、「*high_value_summary_df*」。透過 Taipy 的智慧設計,您無需為這些中間資料節點進行任何配置;系統會巧妙地處理它們。 --- **具有預設值的中間資料節點**:我們最終定義了另外四個中間資料節點,並將「*default_data*」屬性設為以下內容: - payment_threshold: “1000:int” ![資料節點檢視](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odkrz0pq2dhqpm0gnta2.png) - 分數閾值:“1.5:浮動” - 測量:“平均值” -summary_statistic_type:“中位數” --- #### - 任務 點擊新增任務按鈕,您可以配置新任務。 新增四個任務,然後**將每個任務連結到「詳細資料」標籤下的對應函數**。 Taipy Studio 將掃描您的專案資料夾並提供可供選擇的分類函數列表,並按 Python 檔案排序。 --- **任務 1** (*preprocess_and_score*):在 Taipy studio 中,您可以按一下「任務」圖示以新增任務。 您可以將輸入指定為“*path_to_data*”,將輸出指定為“*scored_df*”。 然後,在「詳細資料」標籤下,您可以將此任務連結到 *algos.algo.preprocess_and_score* 函數。 ![任務流程及評分](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnc57wbxafjh2s3m6fat.png) --- **任務 2** (*featurization_and_segmentation*):與任務 1 類似,您需要指定輸入 (“*scored_df*”、“* payment_threshold*”、“*score_threshold*”) 和輸出 (“*segmented_customer_df*”) ” )。將此任務連結到 *algos.algo.featurization_and_segmentation* 函數。 ![任務特徵化](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbtm200u9meq1x1rcy2w.png) --- **任務 3** (*segment_analysis*):輸入為“*segmented_customer_df*”和“*metric*”,輸出為“*segment_result*”。 連結到 *algos.algo.segment_analysis* 函數。 ![任務片段分析](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnnl1w1q0blebzbyawvt.png) --- **任務 4** (high_value_cust_summary_statistics):輸入包含「*segment_result*」、「*segmented_customer_df*」和「*summary_statistic_type*」。輸出為“*high_value_summary_df*”。連結到 *algos.algo.high_value_cust_summary_statistics* 函數。 ![任務統計](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tynu6e718z1dwf8id05m.png) --- ## 結論 Taipy 提供了一種**智慧方式來建立和管理資料管道**。 特別是可跳過的功能使其成為優化運算資源和時間的強大工具,在涉及大型資料集的場景中特別有用。 Dask 提供了資料操作的原始能力,而 Taipy 增加了一層智能,使您的管道不僅強大而且智能。 --- 其他資源 如需完整程式碼和 TOML 配置,您可以存取此 [GitHub 儲存庫](https://github.com/Avaiga/demo-dask-customer-analysis/tree/develop)。若要深入了解 Taipy,請參閱[官方文件](https://docs.taipy.io/en/latest/)。 一旦您了解 Taipy 場景管理,您就可以更有效率地為最終用戶建立資料驅動的應用程式。只需專注於您的演算法,Taipy 就會處理剩下的事情。 --- ![很多](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ua3x4t3yttba6g25jjqo.gif) 希望您喜歡這篇文章! --- 原文出處:https://dev.to/taipy/big-data-models-vs-computer-memory-4po6