🔍 搜尋結果:lara

🔍 搜尋結果:lara

使用 Typescript 和 Jest 進行單元測試

--- 標題:使用 Typescript 和 Jest 進行單元測試 發表:真實 描述: 標籤: typescript、javascript、玩笑、單元測試 --- ![vscode-is](https://thepracticaldev.s3.amazonaws.com/i/gd97g4kdyk1bpdeyfqst.png) *原文發佈於<https://muhajirframe.com/writing/unit-test-typescript-jest/>* 在本文中,我們將嘗試介紹 Typescript + jest 中的簡單單元測試。 我們將建立一個簡單的實用程式來檢測 url 是內部連結還是外部連結。 例如`https://www.google.com`是外部連結,而`/page1`是內部連結。我們將專案命名為`is-internal-link` ,但您可以將其命名為任何名稱。 先決條件 ---- - NodeJS - VSCode + Jest 外掛程式(可選) 建立新目錄 ``` mkdir is-internal-link ``` 初始化 npm ``` npm init ``` 安裝依賴項 ``` npm install --save-dev @types/jest @types/node jest ts-jest typescript ``` 建立`jest.config.js` ``` module.exports = { roots: ['<rootDir>/src'], transform: { '^.+\\.tsx?$': 'ts-jest', }, testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$', moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], } ``` 建立`tsconfig.json` ``` { "compilerOptions": { "target": "es5", "module": "commonjs", "lib": ["es2015"], "strict": true, "declaration": true, "outDir": "dist", "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules", "**/*.spec.ts"] } ``` 好了,我們準備好要寫程式碼了。建立檔案`src/main.ts`和`src/main.spec.ts` 您的文件樹現在應該如下所示 ``` . ├── node_modules ├── package-lock.json ├── package.json ├── src │ ├── main.spec.ts │ └── main.ts └── tsconfig.json ``` 在您最喜歡的編輯器中打開它。 (VSCode / Atom / Sublime / 等)。 我個人使用VSCode ``` import { isInternalLink } from './main' test('should return false given external link', () => { expect(isInternalLink('https://google.com')).toBe(false) }) test('should return true given internal link', () => { expect(isInternalLink('/some-page')).toBe(true) }) ``` 現在有辦法測試這一點。 ### 方式一 打開你的`package.json` 。並將其替換為您的`scripts` ``` "scripts": { "test": "jest" }, ``` 執行`npm run test` 。 現在您應該看到錯誤,因為我們還沒有實作程式碼,對嗎? ### 方式2 使用您的編輯器外掛程式。我比較喜歡這種方式。我只會在 VSCode 上展示它。您最喜歡的編輯器可能也有它。 安裝[vscode - 是](https://github.com/jest-community/vscode-jest) ![vscode-is](https://github.com/jest-community/vscode-jest/raw/master/images/vscode-jest.gif) 這個 GIF 應該是一個很好的解釋 vscode-jest 是如何運作的 我們繼續吧。 ![vscode-is](https://thepracticaldev.s3.amazonaws.com/i/38h9s3601vnvzl75wouf.png) 您的 VSCode 現在可能如下所示。 ### 實施程式碼 讓我們實作我們的`main.ts` ``` export const isInternalLink = (link: string) => /^\/(?!\/)/.test(link) ``` 切換回`main.spec.ts` 。現在您應該看到錯誤消失了,並且它變成了綠色。 專業提示:使用[VSCode 分割編輯器](https://code.visualstudio.com/docs/getstarted/userinterface#_side-by-side-editing)同時檢視程式碼 ( `main.ts` ) 和規格 ( `main.spec.ts` )。 長話短說 在第一面開啟`main.ts` `cmd+1` `cmd+p` `main.ts` 打開第二面的`main.spec.ts` `cmd+2` `cmd+p1` `main.spec.ts` *附註:我是 VSCode 和 Vim 的忠實粉絲,我有很多關於如何使用 VSCode 提高工作效率的技巧。如果你們有興趣的話請在評論中告訴我,我可以在這裡寫下來* 恭喜! 您剛剛使用 Typescript 和 Jest 進行了單元測試 --- 原文出處:https://dev.to/muhajirdev/unit-testing-with-typescript-and-jest-2gln

如果我可以重新開始,我會這樣學習 DevOps 🐳

你好,我是拉拉。我是 EngioTech 的高級 DevOps 和雲端工程師和架構師。如果您想成為 DevOps 和雲端工程師,請按照以下步驟操作。他們肯定會受益匪淺。 如果我有機會重新開始我的 DevOps 和雲端之旅,我會這樣做 😻 ![我們走吧 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jw6easshgt9niiucxrda.gif) --- 1. 透過免費的 Microsoft 課程學習並獲得認證 ---------------------------- ![微軟學習](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlbedpirx5qvf6zgbf0f.jpeg) 我首先要採取的步驟之一是透過獲得**雲端和 DevOps**認證來**鞏固我的知識**和技能。 Microsoft Learn 等平台提供了大量量身訂製的資源和課程,可協助您掌握這些技術。透過註冊此類課程,您可以獲得對 DevOps 和雲端世界的堅實基礎和實用見解。查看這些[有關 DevOps 和雲端的免費 Microsoft Learn 課程](https://learn.microsoft.com/training?wt.mc_id=studentamb_366508)。 --- 2. 實際專案實踐 --------- 通過認證建立了堅實的理論基礎後,我將深入實踐。從事現實世界的專案,無論是個人還是透過實習,對於應用所學和獲得實務經驗至關重要。這種實踐方法不僅可以加深您的理解,還可以幫助您培養 DevOps 和雲端領域中必不可少的解決問題的技能。 4. 一切自動化 -------- 自動化是 DevOps 的核心。我會盡可能專注於流程自動化,以簡化工作流程、提高效率並減少錯誤。 Ansible、Puppet 和 Jenkins 等工具對於自動化任務和部署、騰出時間進行更具策略性的工作來說非常寶貴。 --- 概括 -- 就是這個。我們傾向於把事情複雜化。透過實踐學習。參加[這些課程](https://learn.microsoft.com/training?wt.mc_id=studentamb_366508),您就已經做好了 10 倍的準備,成為工程師。 ![再見表情符號](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w1vhhdpw0nk4babg7r6r.gif) --- 原文出處:https://dev.to/larastewart_engdev/how-i-would-learn-devops-if-i-could-start-over-5amp

超新手資料庫簡介

無論您**剛開始**學習程式設計還是**已經有**一些經驗,我很確定您已經問過自己(或其他人)資料庫到底是什麼,如何處理它,關聯式資料庫和資料庫之間有什麼區別?和非關聯式資料庫及其用途。 當談到程式設計時,感覺我們的疑慮無窮無盡,有時我們會在資訊的海洋中迷失。我將討論每個初學者在建立第一個資料庫時應該了解的一些概念。我希望至少能教您一些有關資料庫的知識,資料庫是軟體最重要的部分之一。 - [什麼是 SQL?](#what-is-sql) 什麼是資料庫? ------- 在一切之前,了解什麼是**資料**很重要。嗯,它是一個值,例如 21。但是除非我們對其進行組織並建立訊息,否則該資料將沒有意義。例如,這個數字可以是年齡,可以是登入您網站的總人數,甚至可以是您所在州的號碼。現在,如果我告訴你我們有資料: `age = 21` ,我們幾乎可以理解值 21 是某人的年齡。這就是我們所說的**訊息**。 知道了這一點,我可以告訴你資料庫是有組織的資訊的集合。我喜歡把資料庫想像成類似搬到新家的過程。例如,當我們搬家時,將東西裝進盒子裡是很正常的。我們會有一個盒子裝書,一個盒子裝衣服,另一個盒子裝電子產品。最後,我們把所有東西都裝進卡車,運到我們的新家。 在此範例中,我們的資料庫將是卡車,因為我們有許多特定物品的盒子 - 有組織的資訊的集合。該資訊是結構化的並且通常儲存在電腦系統中。 (我們使用資料庫來儲存、存取和維護資料。) 為了控制資料庫,我們將使用所謂的資料庫管理系統(DBMS),該軟體用於可視化資料庫的表、其訊息,以及我們還可以執行查詢(對資料庫執行操作的命令)和許多功能。其他事情。它基本上是用戶(使用資料庫的人)和資料庫本身之間的介面。 可以說,每次建立、刪除、更新和讀取等等,我們都會處理 DBMS。 ![顯示資料庫管理系統如何運作的圖像](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wmyuwc2x8ovlc5w376im.jpg) 資料庫管理系統範例: - MySQL - SQL伺服器 - 甲骨文資料庫 有很多選擇,我們應該選擇更適合我們和專案的一種。 資料庫類型 ----- 每個初學者都應該了解的最重要的資料庫類型是: - 關係型資料庫 - 非關係型資料庫 ### 關係型 這種類型的資料庫是使用具有列和行的表來建構的,如下圖所示,我們使用 SQL 來處理這種結構。 在表格中,我們將有: - 列,定義每條資料是什麼(ID、姓名、年齡...)及其類型; - 行,保存給定的資料。 ![學生資料庫表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f4qx9y567xoz1kasayqc.png) 表中的每一行都是一筆具有唯一 ID 的記錄,我們稱之為**鍵**。例如,在這個表中,鍵是數字1、2、3…我們可以看到每筆記錄都有自己的鍵,用來標識自己。 每個初學者都應該了解至少三種類型的密鑰: - **鍵**:它基本上是表中的一列或多列,負責以獨佔方式辨識行。 - **主鍵**:這種類型將確保暫存器的**唯一性**,將在表之間的關係上引用暫存器並對其**進行索引**,這提高了 DBMS 的效率。 - **外鍵**:它是一個使用每個表的主鍵連接表的列。我們使用這種類型的鍵來建立表之間的關係。重要的是要理解,具有外鍵的表稱為**引用表**,而被引用的表稱為**引用表**或**父表**。 ### 非關係型 非關聯式資料庫,也稱為NoSQL(現在是Not Only SQL),是一種不使用表格及其列和行作為組織方案的資料庫。它提供了更大的靈活性,因為您不必像我們在關聯式資料庫上所做的那樣擔心建立表。 NoSQL 上的儲存經過最佳化,可以自我調整以滿足各種需求。例如,可以將資料儲存為鍵/值、JSON 文件或圖形。 NoSQL 資料庫的建立是為了解決人們直到 90 年代末期才遇到的問題,即難以設計能夠滿足使用關聯式資料庫所需的規模和敏捷性的資料庫,而當時無法做到這一點。 ![SQL 與 NoSQL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f8ox9vms8ld9ebo1vpv.png) NoSQL 最重要的功能之一是: - 更高的可擴展性 - 沒有複雜的關係 - 降低成本 非關係型資料庫也有類型,其中兩種是: - **鍵值**:最常見的一個。資料庫中的每個專案都將儲存為屬性名稱(或“鍵”)及其值。例如: `{"name": "Maria"}` 。鍵是“name”,值是“Maria”。在這些情況下最常使用的資料庫是**Redis** 、 **DynamoDB**和**Berkeley DB** 。 - **文件**:將每個金鑰與其文件一起存儲,其主要特徵是將所有資訊包含在一個文件中。該文件通常是 JSON,但也可以是 XML。最著名的文件資料庫是 MongoDB 關於此類資料庫的更多資訊有很多,但這是您開始之前必須了解的基礎知識!除此之外,不要讓這個開始阻止您深入挖掘以了解更多資訊。 什麼是 SQL? -------- SQL 代表**結構化查詢語言**,這是一種用於處理 70 年代左右在 IBM 實驗室建立的資料庫的程式語言。一段時間後,它成為資料管理的模式。 我們使用這種程式語言在資料庫上執行查詢,並且可以使用各種參數從資料庫中檢索、建立或刪除資訊。我們只需要遵循語法,就像任何其他程式語言一樣。 SQL 有許多**指令**,但最重要的是: - **SELECT** :搜尋資料庫表中的行。 - **INSERT** :在表中插入新行。 - **UPDATE** :用於更新表中已存在的資料。 - **DELETE** :刪除一個暫存器。 重要的是,我們將此命令與其他參數一起使用,以便我們可以使查詢非常具體。在 Capslock 上使用 SQL 是一種約定。 SQL 還具有一些我們可以在查詢中新增的條件,以便修改將傳回的暫存器,例如: - **FROM** :用於表示將查詢哪個表。 - **ORDER BY** :用於以特定順序組織傳回的資料。 - **WHERE** :用於**指定傳回資料的條件**。例如,如果我們想查看表中年齡超過 18 歲的用戶,我們將使用「where」。 SQL 中還有許多其他命令,但這是我們建立第一個表並學習建立第一個 CRUD(代表建立、讀取、更新和刪除)所需的基本命令。 就是這樣! ----- 透過這篇文章我們了解了資料庫的基礎知識,例如它是什麼、它的類型以及什麼是 SQL。現在,我們必須學習如何建立一個主題,該主題將在本系列的下一篇文章中介紹。 這個內容是根據我在 100 天的程式碼中的筆記建立的,在這段期間我了解了資料庫、PHP 和 Laravel,所以我真的很自豪,因為在開始挑戰之前我對此幾乎一無所知。另外,如果需要的話,請隨時向我提問! 感謝那些審查我的文章並幫助我到達這裡的人: - @danielhe4rt - @cherryramatis - @reenatoteixeira --- 原文出處:https://dev.to/basementdevs/database-for-newbies-n46

Rust 中的 Laravel?我這樣做是有原因的。

大家都怎麼啦! 過去幾個月我一直在研究 Rust,並且總是試圖接近 Laravel 環境中的實際堆疊。 對於我來說,作為一名 PHP 開發人員,跳入 Rust 確實是一項艱鉅的任務,因為我以前從未接觸過函數式編程,但是我找到了一種方法讓這變得「更容易」。 銹據我所知 ----- 整個生態系統由不同的套件組成,您應該根據需要加入它,這與 Laravel 不同,Laravel 圍繞框架有一個非常強大的環境。 所以我的第一印像是我必須學習如何使用基礎包: - 多滕維 - 時空 - 時間 - Uuid - 等等。 但是當涉及到 Web 開發(主要是 API)時,您必須從眾多現有框架中選擇一個。喜歡: - Actix(目前使用) - 阿克蘇姆(評估中) - Rocket(人們總是告訴我不要使用它,仍然不知道為什麼) 而且它們都沒有 Laravel 那種固執己見的“結構”,所以我決定建立我的。 Rust 中的 Laravel --------------- 我為什麼要談 Laravel?因為它為我們提供的“MVC”結構對於使用 Rust Web 的小型專案來說足夠優雅。 當我使用固定的 Laravel 框架編寫 Rust 程式碼時,事情開始變得有意義。這是我正在談論的內容的結構: ``` ./src ├── app.rs ├── config.rs ├── http │   ├── controllers │   │   ├── leaderboard_controller.rs │   │   ├── mod.rs │   │   └── submissions_controller.rs │   ├── mod.rs │   └── requests │   ├── leaderboard_request.rs │   ├── mod.rs │   └── submission_request.rs ├── main.rs ├── models │   ├── leaderboard.rs │   ├── mod.rs │   └── submission.rs └── repositories ├── leaderboard_repository.rs ├── mod.rs └── submission_repository.rs ``` 該專案目前正在使用中: - [阿克泰克斯](https://actix.rs/docs/) - [卡律布狄斯 ORM](https://github.com/nodecosmos/charybdis) 你可以在這個[Pull Request](https://github.com/DanielHe4rt/leaderboard-rust/pull/1)中檢查我的混亂情況 問題是:在使用 Rust 時遵循這個想法會是一件好事嗎?簡單性和良好的維護結構是我在專案中一直追求的目標。 另外,我正在考慮寫一些關於我的流程如何從 PHP 遷移到 Rust 的系列文章,您有興趣閱讀類似的內容嗎? 希望在這裡看到您的想法,謝謝! --- 原文出處:https://dev.to/danielhe4rt/laravel-inside-rust-i-have-a-reason-for-that-ke3

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

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

介紹 -- 在 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

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

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

為什麼我從 Visual Studio Code 切換到 Sublime Text

最近,我改用[Sublime Text](https://www.sublimetext.com/)作為我的主要程式碼編輯器。一年多來,我一直使用[Visual Studio Code](https://code.visualstudio.com/)來編寫程式碼。這兩個編輯器非常相似,但也有足夠的差異,我想分享一下是什麼讓我全職使用 Sublime。 *注意:這篇文章並不是要為了一項技術而抨擊另一項技術。我嘗試根據我的個人經驗進行誠實的比較,但選擇程式碼編輯器是一個主觀過程,因此每個人都會對自己的最愛有不同的看法。* 是什麼讓我跳槽 ------- ### 偉大的符號分析 當您在 Sublime Text 中開啟一個專案時,它會自動啟動一個稱為「符號分析」的過程,這是在程式碼中尋找關鍵字的一個奇特術語。符號分析的好處在於,我可以輸入 Cmd + Shift + R 來調出符號搜尋選單,並在整個程式碼中快速找到類別名稱和方法。我主要使用 PHP,因此如果我已經知道我正在處理的類別名稱是`PostController` ,我可以在符號搜尋中搜尋它並立即在編輯器中開啟我的 PHP 類別檔案。 VS Code 也支援符號搜尋,但是,它只支援幾種開箱即用的語言。有一個與 VS Code 一起使用的第三方 PHP 符號分析器,但是,我發現它在處理大型程式碼庫時遇到困難,而 Sublime 則沒有問題。 ### 超快 Sublime Text 是可用於編寫程式碼的最快的文字編輯器。它幾乎立即打開並執行非常快速的搜尋。 Microsoft 在保持 VS Code 效能方面做得很好,但是 VS Code 是基於[Electron](https://electronjs.org/)的。 Electron 是一個用於捆綁 Chromium 實例和用 JavaScript/Node.js 編寫的程式碼的框架。它使編輯器具有很強的可擴展性,但使用 Chromium 的整個實例作為文字編輯器會使應用程式啟動緩慢並使用更多記憶體。 Sublime Text 是一個用 C++ 編寫的本機應用程式,因此其佔用空間要少得多。 ### 更好的 Vim 綁定 我非常喜歡在編寫程式碼時使用 Vim 鍵綁定。儘管我喜歡 Vim 鍵盤快捷鍵,但我仍然喜歡使用標準文字編輯器來利用側邊欄文件清單和文件標籤等現代功能。我發現 Sublime 的 Vim 支援比 VS Code 更準確,這有助於我更快地編寫程式碼。 Sublime 支援開箱即用的 Vim 綁定,但如果您使用[Vintageous](https://github.com/guillermooo/Vintageous)插件,您可以獲得更多功能。 我在 Visual Studio Code 中懷念的事情 ---------------------------- ### 功能豐富的側邊欄 VS Code 有一個非常好的側邊欄,可以更靈活地建立和移動檔案。 Sublime 有一個更好的側邊欄插件,還有其他鍵盤快捷鍵插件(例如[AdvancedNewFile)](https://github.com/skuroda/Sublime-AdvancedNewFile)可以使轉換更容易,但有時我會懷念 VS Code 側邊欄的開箱即用功能。 ### 內建偵錯工具 VS Code 有一個內建的偵錯器,適用於多種程式語言。它使得使用 PHP 的 xdebug 變得非常簡單。儘管 Sublime 有除錯插件,但它們並不像 VS Code 提供的開箱即用的那樣可靠。在這種情況下,如果我正在除錯一些棘手的東西,我仍然會打開 VS Code。 結論 -- 最後,文字編輯器完全取決於個人喜好和工作要求。對於我的用例來說,Sublime 是一次非常愉快的體驗,它幫助我更快地編寫程式碼。如果您想了解有關 Sublime Text 的更多訊息,Jeffrey Way 在 Laracasts 上開設了相關[課程](https://laracasts.com/series/sublime-text-mastery),Wes Bos 也寫了一本相關[書籍](http://wesbos.com/sublime-text-book/)。 請在評論中告訴我您最喜歡的編輯器是什麼! --- 原文出處:https://dev.to/restoreddev/why-i-switched-from-visual-studio-code-to-sublime-text-28k0

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

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

從 Next.js 到 Rails 再到 Elixir:我的 React.js 倦怠之旅

我自 2019 年以來一直是 Web 開發人員。我使用 React.js 和基於 React 的框架,如 Gatsby、Next、Remix、Astro 和 Hydrogen。我從來沒有對這些工具感到完全滿意,但是,作為一個深入 JS 生態系統的初學者,我從同行那裡聽到的都是這樣的話:「這就是方式,任何其他程式語言要么慢,要么老」。 ![就是這樣](https://media.giphy.com/media/stnjSj2vpLcM4rwmEH/giphy.gif) 結果,我習慣了巨大的複雜性:多個獨立的儲存庫、數千個函式庫和框架來實現簡單的事情、GraphQL、微服務、無伺服器、靜態網站產生、增量靜態再生、部分水化、 redux 、redux-thunk、babel、webpack、react 伺服器元件、伺服器操作等。這個清單還可以再持續 10 分鐘。 直到有一天我說**受夠了!** 讓我們來看看我慢慢發瘋的完整時間線。這需要一段時間,在閱讀長篇文章之前,請隨意煮點咖啡! --- ## 倦怠的時間表 ### [Gatsby.js](https://www.gatsbyjs.com/) 我記得完成我的訓練營並想:“我終於能夠建立我的作品集了!”,所以我做到了。只有一個小問題,我想在 Google 上建立索引,但是使用舊的「create-react-app」使這項任務幾乎不可能完成。很快我了解了 SEO 和 React 的水合循環,這讓我找到了這個問題的「解決方案」:Gatsby.js。靜態網站產生的想法對當時的我來說簡直是革命性的,畢竟沒有什麼比預先渲染 HTML 檔案更快了,對吧? 我決定透過閱讀文件來學習這個新框架,讓我告訴你,這**不是**一次有趣的體驗。我以前從未聽說過 GraphQL,顯然,您需要它來產生所有靜態檔案(到底是什麼???)。我問我的一些網友,很難學習這些過度設計的廢話是否正常,他們回答說「技能問題,再努力一點!」。於是我更加努力,終於學會了之後,我把我的個人網站移植到了Gatsby上。 ![再努力一點](https://media.giphy.com/media/gzRiZROEyDCznPofKj/giphy.gif) 我的大部分頁面都成功在 Google 上建立了索引,幾個月來,我對結果非常滿意。然後另一個問題出現了:我的**很多**開發者朋友開始說“Gatsby 死了!建立 Next 是為了簡化靜態站點生成並提供伺服器端渲染”。 ### [Next.js](https://nextjs.org/) 我快速瀏覽了 Next 文件並**立即**愛上了它。我能夠在沒有 GraphQL 的情況下用三分之一的程式碼做與 Gatsby 相同的事情!我再次將我的作品集移植到另一個框架:Next。 這次我確實有一次美好的經驗。部署到 Vercel 輕而易舉,「getStaticProps」和「getServerSideProps」功能很簡單,但功能非常強大,我可以選擇每個頁面的渲染樣式,整體來說非常靈活。 不幸的是,我透過慘痛的教訓學到了一些東西:在 JavaScript 生態系統中,所有美好的事情都會結束。 ### [混音](https://remix.run/) 我清楚記得 Remix 發佈時的情景。多名科技影響者開始發布有關它的內容(一如既往)。然而,當時我在主頁上看到它不支援靜態網站生成,只支援伺服器端渲染,所以我想「等一下,這些年來投資於 [JAMstack](https://jamstack.org/) 都被扔在這裡了嗎?不可能,這個框架不會長久」。然而,令我驚訝的是,Remix 不僅生存了下來,而且還被 Shopify 收購 https://shopify.engineering/remix-joins-shopify ,並成為 Next 的重要競爭對手。 幾個月過去了,我決定嘗試看看。我再一次感到驚訝,Remix 的主要座右銘是使用 Web 基礎知識,而不是像 Next 這樣過於複雜的快取系統。因此,在Remix 中編碼時,我腦中需要的思維模型要簡單10 倍:沒有全域狀態管理器,只需使用URL,更少的客戶端狀態,將所有邏輯移至伺服器,並使用cookie,無需使用完整堆疊中間的 REST API 非常簡單,只需將資料庫查詢移至「loader」函數即可。 ### 離開矩陣 ![離開矩陣](https://media.giphy.com/media/11e0gEWxYoSYTK/giphy.gif) 然後,突然間,真相呈現在我面前,我服下了紅色藥丸。我的腦海中開始浮現出多個問題:Remix 不就像所有其他「古老而無聊」的框架(如 Rails、Laravel 和 Django)一樣嗎?幾十年來,我們一直在使用伺服器端渲染進行全端 Web 開發,但 JavaScript 黑手黨集體認為這種方法是垃圾,將所有內容移至客戶端才是未來。難道同一個黑手黨認為 Rails 一直都是對的嗎?用 JS 框架做所有那些過度設計的怪物不是正確的舉動嗎?我開始質疑一切。這種「新」的 Web 開發方式更加簡單、快速。 ### 我已經完成了 Next 和 Vercel 我透過 [Next.js 應用程式路由器](https://nextjs.org/docs/app) 達到了臨界點。以下是 Vercel 向 Next 推送的所有錯誤的完整清單: - 曾經簡單的:「getStaticProps」和「getServerSideProps」函數現在變得複雜而麻煩。目前,沒有特定的位置來新增 API 呼叫或資料庫查詢,您可以將它們寫入任何您想要的位置!在多年前使用 PHP 犯了同樣的錯誤之後,我們開始再次將業務邏輯與 UI 混合。難道前端開發者不吸取過去的教訓嗎?如果我刪除按鈕會發生什麼事?這是否會破壞我的使用者身份驗證流程,因為資料庫呼叫位於其中?您的前端應該 100% 可廢棄且可更換。你相對於競爭對手的競爭優勢在於業務邏輯,它應該與 UI 層完全隔離。 ![可怕的 Next.js 程式碼](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kp41ds14loo21xgimcza.png) - 接下來是伺服器優先。這聽起來沒那麼糟吧?畢竟,這解決了 SEO 問題並立即向用戶展示新鮮內容。問題在於,大多數現有的 Next 程式碼庫都依賴客戶端程式庫,例如樣式元件和一些全域狀態管理器。這是什麼意思?隨著此類重大變化的不斷發生,您的應用程式將在幾週而不是幾年內變成遺留軟體。更多的時間花在保持所有依賴項最新上,而不是做重要的事情:發布功能。 - Vercel 從 Meta 聘請了多名 React 核心團隊成員。這帶來了嚴重的利益衝突,因為這些工程師現在(據稱)正在發布有利於 Next 的功能,而不是優先考慮那些可以幫助所有基於 React 的框架(如 Remix)的功能。 ![Vercel 正在破壞 React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ye40ykjgrd3z10t5nx7.png) 我再也受不了了。我對自己說:你知道嗎?我厭倦了一遍又一遍地重新學習相同的框架,我完全不同意這種新的範式。 毫不奇怪,其他內容創作者也經歷了類似的情況: https://youtu.be/zkCBSz353fc?si=z3-FDVgcB3xfp06h https://youtu.be/Zt8mO_Aqzw8?si=10fy1d-ZoB7t3Uc_ --- ## 啟蒙之路 我非常累。在厭倦了所有的 React 工具後,我開始了尋找更簡單的 Web 框架的旅程。以下是我一直在尋找的先決條件: - 含電池 - 約定優於配置 - 良好的開發體驗 - 現代化且高性能的前端 我的第一個反應是查看 [Stack Overflow Survey 2023](https://survey.stackoverflow.co/2023/#section-most-popular-technologies-web-frameworks-and-technologies) 中的頂級框架。我立即從清單中刪除了所有與 JS、C# 和 Java 相關的內容。我從來沒有興趣學習後兩個,它們看起來醜陋且冗長。所以剩下的選項是:Laravel (PHP)、Django (Python)、Rails (Ruby) 和 Phoenix (Elixir)。 Python 是我在網路工程學位期間使用的語言,我獲得了非常愉快的體驗。 Django 似乎遵循約定優於配置的理念,但最終讓我放棄它的是沒有一個好的內建工具來在前端工作。論壇上的大多數人都說他們使用[HTMX](https://htmx.org/) 和[Alpine](https://alpinejs.dev/),但是,兩者都是您需要安裝的外部依賴項。 放棄Laravel 是非常困難的,因為它具有驚人的成本效益,有數百個官方軟體包可以處理新創公司可能需要的幾乎所有內容,例如託管、身份驗證、條紋支付等。對於前端,他們創造了[慣性。Node.js](https://inertiajs.com/),這是一種非常簡單而優雅的方式,可以在前端使用 React 的同時保持 Laravel 的高生產力和強大功能。百分之百誠實地說,我沒有選擇 Laravel 的唯一原因是 PHP 的語法,它看起來很難看,到處都是一堆 `$` 和 `->`。 ### Ruby on Rails Ruby on Rails 無需介紹。它是 Web 開發框架的元年,其革命性的「15 分鐘建立部落格」至今仍令人印象深刻。在我開始抱怨我發現的所有問題之前,讓我們先從好的方面開始。 與 Python 類似,Ruby 是一種可以向非技術人員展示的語言,他們會理解該軟體想要做什麼。它是**迄今為止**我見過的最容易閱讀和最美麗的語言。我很快就意識到,[編寫視覺上令人愉悅的程式碼](https://world.hey.com/dhh/a-writer-s-ruby-2050b634) 是Rails 團隊的首要任務,這對我來說來說是新的。 更不用說 Rails 幾乎發明了「包含電池」和「約定優於配置」的哲學,所以這不會是一個問題。在一份文件中,我提供了任何類型的 Web 應用程式所需的一切。 在前端,有 [Hotwire](https://hotwired.dev/),這是一種非常簡單且輕量級的方法,可以實現 SPA 框架提供的所有 UX 改進。我一直很好奇測試這個庫的極限,它看起來非常有前途。 好吧,Rails 在紙面上滿足了我想要的框架的所有先決條件。我們來試試吧!我在本地測試的第一件事是“railsscaffold”命令。我立即感到震驚。一個指令就能產生 CRUD 所需的一切?決不! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58lbioexmot9412kojr5.png) 在 Node + React 領域,要實現相同的目標,我需要手動編寫所有程式碼(這裡沒有生成器)並安裝一堆程式庫,例如:Vite、prisma、express、react router、redux、redux-thunk 、 vitest、cypress 、react 測試庫、zod、typescript、eslint、prettier、1000 個不同的插件,甚至可能還有GraphQL 或tRPC。基本上就是一個已經有 900 個依賴項的 package.json。 在“railsscaffold”最初的震驚之後,當我從控制器打開程式碼時,我再次震驚了: ``` class ArticlesController < ApplicationController def index @articles = Article.all end def show @article = Article.find(params[:id]) end def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to @article else render :new, status: :unprocessable_entity end end def edit @article = Article.find(params[:id]) end def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render :edit, status: :unprocessable_entity end end def destroy @article = Article.find(params[:id]) @article.destroy redirect_to root_path, status: :see_other end private def article_params params.require(:article).permit(:title, :body) end end ``` 這是所有後端程式碼嗎?只需幾行?這不可能!這非常簡單,看起來就像一個「低程式碼」工具。它簡單、優雅、可讀性極強,這是我們在 JS 領域很少見的。 好吧,好吧,你現在一定在想:「這個來自網路的瘋狂 React 開發者說他最終使用了 Elixir,所以 ruby 一定有問題!」。你是對的,我的匿名朋友,有些事情讓我很惱火,讓我們談談。 首先,我們需要解決房間裡的大象:從 React + Typescript 轉向動態類型語言並不容易。從我開始編寫程式碼的那一刻起,我的 VScode 上就沒有出現智慧感知或充滿程式碼建議的下拉式選單,我感到盲目和迷失。這是一種可怕的感覺,我可能會在函數名稱上輸入錯誤,直到網站投入使用時才意識到!我知道我們可以編寫測試,但這是我希望在 IDE 上立即辨識的錯誤類型,而不是在測試或部署期間辨識。 另一件我以為我會喜歡但最終討厭它的事情是:太多的魔法。在 Typescript 程式碼庫中,我可以點擊任何類別或函數的頂部,前往原始程式碼並查看其實作方式。在 Rails 上,我到底在哪裡進行驗證(例如)?我是否在控制器內建立私有函數?有專門的資料夾嗎?不,正確的位置是在模型內部。為什麼?因為這就是它的工作原理,所以您要么採用該約定,要么很難編寫 Ruby 程式碼。我根本無法對一切在幕後如何運作產生“直覺”,我必須盲目地相信維護者在組織一切方面做得很好。 為了解決我的挫折感,我開始寫前端程式碼。如何建立元件? [部分](https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials)。如何定義該元件的 prop 類型?沒有辦法做到這一點,您需要打開它並直觀地查找其中的所有變數。做一些互動怎麼樣?建立國家?嗯,有帶有 [Stimulus](https://stimulus.hotwired.dev/) 的 Hotwire,但是正如您所看到的,您需要手動建立“重新渲染”功能,它沒有找到一種方法像React 這樣改變狀態後自動重新渲染頁面。 ``` // src/controllers/slideshow_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = [ "slide" ] initialize() { this.index = 0 this.showCurrentSlide() } next() { this.index++ this.showCurrentSlide() } previous() { this.index-- this.showCurrentSlide() } showCurrentSlide() { this.slideTargets.forEach((element, index) => { element.hidden = index !== this.index }) } } ``` 我再一次感到沮喪。我非常接近找到完美的框架!如果 Rails 失敗,我想嘗試的下一個框架是什麼?靈丹妙藥。 ### 長生不老藥和鳳凰 我必須說實話,我已經沒有耐心了。我嘗試了多種不同的生態系統,我幾乎確信要堅持使用 Ruby on Rails,並放棄對完美的追求。直到我的 YouTube 推薦部分出現了一個影片: https://www.youtube.com/live/bfrzGXM-Z88?si=Xsa7yCKeVSY5R3sT 堅持,稍等!在這裡我們可以看到一位 React 開發人員說了很多關於函數式程式設計、Elixir 和 Phoenix Live View 的好話。也許我應該嘗試一下! 我做的第一件事就是打開Elixir 和Phoenix 的文件,我真的很喜歡這樣一個事實:所有包都使用[Hex Docs](https://hexdocs.pm/) 以相同的方式進行記錄,您只需要取得習慣於單一介面以學習新事物。 另一個好處是,您只需閱讀文件即可真正學習 Elixir,無需昂貴的課程!在其他所有生態系統中,我必須透過付費課程學習語言,然後透過閱讀文件來學習框架。 然後是時候開始編寫程式碼了。很快我就明白函數式程式設計與 OOP 有很大不同。我們來做一個小小的比較: ``` // JS const obj = {name: "daniel"} obj.age = 25 // result: obj = {name: "daniel", age: 25} ``` ``` # Elixir obj = %{name: "daniel"} obj = Map.put(obj, :age, 25) # result: obj = %{name: "daniel", age: 25} ``` 或者您可以使用管道運算子透過更簡單的語法實現相同的效果: ``` # Elixir with pipe operator obj = %{name: "daniel"} |> Map.put(:age, 25) # result: obj = %{name: "daniel", age: 25} ``` 最初,您可能會發現它的可讀性較差且更複雜,但我保證隨著時間的推移它會變得有意義!嗯,至少對我來說是這樣。身為 React 開發人員,我已經習慣了到處都可以看到多個函數,甚至前端元件也是函數!更不用說建立類別有時被 JavaScript 黑手黨視為一種程式碼味道。我的大腦已經針對這種新範式進行了“塑造”,這對我來說很自然。自從我在大學獲得網路工程學位以來,我上過幾門關於物件導向程式設計的課程,但它從來沒有「受歡迎」。我無法將複雜的問題建模為類別和物件。隨著時間的推移,使用多個函數來「改變」一個變數是我在腦海中建模的方式。 主要框架怎麼樣?包含鳳凰電池嗎?約定優於配置? **是的!** 老實說,生態系統與 Rails 不在同一水平,但已經達到了 95%。除非您需要非常具體的功能,Phoenix 都能滿足您的需求。 我幾乎被 Elixir 迷住了,我的清單中缺少兩件事:良好的開發人員體驗和現代/高效能的前端程式碼。 José Valim 宣布他正在嘗試為該語言加入類型,但 Elixir 目前還沒有這些類型,所以我很擔心。如何在沒有類型的情況下獲得智能感知和自動完成?很快我發現這些功能不一定相關。在 VScode 上安裝 [ElixirLS 擴充功能](https://marketplace.visualstudio.com/items?itemName=JakeBecker.elixir-ls) 後,我感到很驚訝。可以在隨機資料夾的隨機模組內定義函數,將其導入其他位置,並取得它的智慧感知和文件!我從靜態類型語言中獲得了這些好處,而無需編寫類型的麻煩,簡直太棒了! https://elixir-lang.org/blog/2022/10/05/my-future-with-elixir-set-theoretic-types/ 我對前端的最後一個擔憂是由 Phoenix [Live View](https://hexdocs.pm/phoenix_live_view/welcome.html) 解決的。在程式碼方面,這正是文件主頁中讓我信服的部分: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5sjzj90khytebnk523fm.png) 您可以為每個元件定義“props”,如果類型不匹配,您的 IDE 中會出現錯誤,就像 React 一樣!感人的! 使用者體驗怎麼樣?每當使用者點擊連結時是否會載入整個頁面?一定不行!即時視圖與客戶端建立 WebSocket 連接,然後每次頁面轉換只是透過 Websocket 進行內容交換,不會發出新的 HTTP 請求。此外,所有狀態都在伺服器端進行管理,這意味著 Trello 等豐富的用戶體驗過去由於加載過多的 JavaScript 而在客戶端非常卡頓,現在變得非常快! Elixir 處理所有複雜的狀態邏輯並將頁面的更新部分傳送到前端。看看這裡的完整解釋: https://youtu.be/wrmVk2czqMg?si=ZoWAlPjQC-svmV3Y 由於我們使用 WebSocket 來建立 UI,因此建立像 Twitter 這樣的「即時」應用程式只需要幾行程式碼! https://youtu.be/MZvmYaFkNJI?si=gAow6oIjgf8_OTkg ## 結論 可以肯定地說,「完美的技術堆疊」並不存在。解決所有問題的靈丹妙藥是我們在腦中創造的幻覺,以不斷尋找和建構最優化的工具。 然而,在個人層面上,完美的堆疊確實存在。因為每個開發人員都有偏好,您可以輕鬆找到適合您標準的工具。如果你有和我類似的旅程,完美的可能就是長生不老藥和鳳凰!所以試試看吧,也許你會像我現在一樣喜歡它。 如果您讀到了這篇文章的結尾,那您就太棒了!非常感謝您抽出寶貴的時間,希望我能為您的職業生涯帶來一些價值。 ![結束](https://media.giphy.com/media/lD76yTC5zxZPG/giphy.gif) --- 原文出處:https://dev.to/danielbergholz/from-nextjs-to-rails-then-elixir-my-journey-through-reactjs-burnout-h8d

Laravel + GraphQL 接案心得&範例分享 Part 2:前端 Query/Mutation 與 React 串接範例

在上一篇文章,我簡單介紹了 GraphQL 的好處,以及如何在 laravel 中實作 這一篇文章,接著介紹一下如何在前端使用 React 進行整合 # 實務範例與 API 線上試玩 上一篇文章我用 graphql + laravel 實作了簡單的電商後台 api https://graphql-laravel-example.tw/graphiql 這次我用 Next.js 開發了簡單的電商前端 web app https://graphql-react-example.vercel.app/ 歡迎試玩看看!可以瀏覽商品、輸入信箱訂閱電子報 --- 在前端發送 query 的程式碼,可以參考 https://github.com/howtomakeaturn/graphql-react-example/blob/main/app/page.js 在前端發送 mutation 的程式碼,可以參考 https://github.com/howtomakeaturn/graphql-react-example/blob/main/app/newsletter.js 我使用原生的 fetch 函數呼叫 graphql api,所以您用任何一款 http 函式庫也都可以做到 狀態管理我用 Next.js 社群的 swr 當作範例,您完全可以自由使用任何 state manager # 優點介紹 我認為前端可以自主決定,要撈取哪些資料,是 graphql 最強大的功能! 後端設計好各種 type 之後,前端就可以自行根據 playground 試玩 api! https://graphql-laravel-example.tw/graphiql 可以彈性、自由撈取資料,連關聯資料都可以巢狀撈取! ``` const gql = `query { products { id name description featured_image price comments { content user { name } } }, }`; ``` 大幅減低後端開發時間、前後端溝通時間、以及處理不同情境需要新增多組類似 api 的時間! # 完整程式碼 前端完整程式碼請參考 https://github.com/howtomakeaturn/graphql-react-example 上次的後端 graphql 試玩 https://graphql-laravel-example.tw/ 後端完整程式碼 https://github.com/howtomakeaturn/graphql-laravel-example # 結論 上面 graphql + laravel + react 的範例 我認為原始碼非常單純、易讀,容易開發、也容易維護 您應該可以根據我提供的範例,在專案中試著導入使用 我在替客戶導入 graphql + laravel + react 的時候,發現網路上教學雖然很多,但是缺少範例 所以我製作這些 sample project 方便大家參考&入門 大家有機會的話一定要試試看 graphql 的威力! (此為系列文章,更多內容會在近期發佈) --- # 系列文章 - [Laravel + GraphQL 接案心得&範例分享 Part 1:強大優點、API 線上試玩、工具介紹](https://codelove.tw/@howtomakeaturn/post/yx08mx) - [Laravel + GraphQL 接案心得&範例分享 Part 2:前端 Query/Mutation 與 React 串接範例](https://codelove.tw/@howtomakeaturn/post/2an0Gx)

最漂亮的 50 個 VS Code 主題

原文出處:https://dev.to/softwaredotcom/50-vs-code-themes-for-2020-45cc 如果您正在尋找新的主題來在新的一年裡改變您的程式碼編輯器,我隨時為您提供協助!看看具有獨特調色板的各種時尚主題 - 從時尚到時髦到充滿活力以及介於兩者之間的一切 - 看看什麼最適合您。我甚至加入了一些有趣的圖標包來進一步自訂 VS Code。 我將這些 VS Code 主題分為以下部分: * [熱門](#trending) (1-20) * [深色](#dark) (21-30) * [光](#光) (31-40) * [多彩](#colorful) (41-50) * [獎勵:圖示](#icons) (51-56) 要在 VS Code 中安裝主題,只需存取市場並選擇您想要下載的主題。若要在已安裝的主題之間切換,請使用「CMD/CTRL + SHIFT + P」開啟命令調色板,然後輸入「首選項:顏色主題」。然後您可以在菜單中瀏覽您的主題。 ## 熱門 發現越來越流行的 VS Code 新趨勢主題。 ### 1. [激進](https://marketplace.visualstudio.com/items?itemName=dhedgecock.radical-vscode) ![](https://raw.githubusercontent.com/DHedgecock/radical-vscode/master/assets/editor.jpg) ### 2.[礦箱材質](https://marketplace.visualstudio.com/items?itemName=sainnhe.mine.box-material) ![](https://user-images.githubusercontent.com/37491630/69468770-671d3400-0d85-11ea-85a7-cf7ffedab468.png) ### 3. [Merko](https://marketplace.visualstudio.com/items?itemName=merko.merko-green-theme) ![](https://github.com/merko30/merko-green-theme/raw/master/img/s.png) ### 4. [東京之夜](https://marketplace.visualstudio.com/items?itemName=enkia.tokyo-night) ![](https://raw.githubusercontent.com/enkia/tokyo-night-vscode-theme/master/static/ss_tokyo_night.png) ### 5. [補救措施](https://marketplace.visualstudio.com/items?itemName=robertrossmann.remedy) ![](https://raw.githubusercontent.com/robertrossmann/vscode-remedy/master/resources/screenshots/gui.png) ### 6. [最小](https://marketplace.visualstudio.com/items?itemName=dawranliou.minimal-theme-vscode) ![](https://github.com/dawran6/minimal-theme-vscode/raw/master/screenshot.png) ### 7. [Aurora X](https://marketplace.visualstudio.com/items?itemName=marqu3s.aurora-x) ![](https://github.com/marqu3s10/Aurora-X/raw/master/images/screenshot.png) ### 8. [大西洋之夜](https://marketplace.visualstudio.com/items?itemName=mrpbennett.atlantic-night) ![](https://github.com/mrpbennett/atlantic-night-vscode-theme/raw/master/imgs/first-screen.png) ### 9. [玻璃使用者介面](https://marketplace.visualstudio.com/items?itemName=aregghazaryan.glass-ui) ![](https://user-images.githubusercontent.com/38076644/62824174-54eb0180-bbab-11e9-975e-2baf0e8cf33f.png) ### 10. [淡淡的丁香](https://marketplace.visualstudio.com/items?itemName=alexnho.a-touch-of-lilac-theme) ![](https://raw.githubusercontent.com/alexnho/vscode-a-touch-of-lilac-theme/master/images/workbench.png) ### 11. [FireFly Pro](https://marketplace.visualstudio.com/items?itemName=ankitcode.firefly) ![](https://raw.githubusercontent.com/ankitmlive/firefly-theme/master/assets/second-demo.png) ### 12. [ReUI](https://marketplace.visualstudio.com/items?itemName=barrsan.reui) ![](https://raw.githubusercontent.com/barrsan/react-italic-theme-vscode/master/sc.png) ### 13. [史萊姆](https://marketplace.visualstudio.com/items?itemName=smlombardi.slime) ![](https://github.com/smlombardi/theme-slime/raw/master/screenshots/screenshot.png) ### 14. [Signed Dark Pro](https://marketplace.visualstudio.com/items?itemName=enenumxela.signed-dark-pro) ![](https://raw.githubusercontent.com/alex-munene/vscode-signed-dark-pro/master/images/signed-dark-pro.png) ### 15. [黑暗](https://marketplace.visualstudio.com/items?itemName=wart.ariake-dark) ![](https://github.com/a-wart/ariake-dark/blob/master/misc/screenshot_frag.png?raw=true) ### 16. [時髦燈](https://marketplace.visualstudio.com/items?itemName=loilo.snazzy-light) ![](https://raw.githubusercontent.com/loilo/vscode-snazzy-light/master/screenshots/javascript.png) ### 17. [Spacegray](https://marketplace.visualstudio.com/items?itemName=ionutvmi.spacegray-vscode) ![](https://raw.githubusercontent.com/ionutvmi/spacegray-vscode/master/screenshots/eighties.png) ### 18. [Celestial](https://marketplace.visualstudio.com/items?itemName=apvarun.celestial) ![](https://github.com/apvarun/celestial-theme/raw/master/Preview.png) ### 19. [藍莓黑](https://marketplace.visualstudio.com/items?itemName=peymanslh.blueberry-dark-theme) ![](https://raw.githubusercontent.com/peymanslh/vscode-blueberry-dark-theme/master/screenshot.png) ### 20. [熊](https://marketplace.visualstudio.com/items?itemName=dahong.theme-bear) ![](https://raw.githubusercontent.com/shaodahong/theme-bear/master/bear-theme-snap.png) ## 深色 您喜歡在黑暗中工作嗎?發現 VS Code 的一些最佳深色主題。 您也可以透過安裝我們的[最佳深色主題包](https://marketplace.visualstudio.com/items?itemName=thegeoffstevens.best-dark-themes-pack)來安裝所有這些深色主題。 ### 21. [一暗專業版](https://marketplace.visualstudio.com/items?itemName=zhuangtongfa.Material-theme) ![](https://raw.githubusercontent.com/Binaryify/OneDark-Pro/master/static/screenshot2.png) ### 22. [德古拉官方](https://marketplace.visualstudio.com/items?itemName=dracula-theme.theme-dracula) ![](https://github.com/dracula/visual-studio-code/raw/master/screenshot.png) ### 23. [Nord](https://marketplace.visualstudio.com/items?itemName=arcticicestudio.nord-visual-studio-code) ![](https://raw.githubusercontent.com/arcticicestudio/nord-docs/develop/assets/images/ports/visual-studio-code/ui-overview-jsx.png) ### 24. [Palenight](https://marketplace.visualstudio.com/items?itemName=whizkydee.material-palenight-theme) ![](https://i.imgur.com/1mYWEP4.png) ### 25. [One Monokai](https://marketplace.visualstudio.com/items?itemName=azemoh.one-monokai) ![](https://github.com/azemoh/vscode-one-monokai/raw/master/screenshot-v0.2.0.png) ### 26. [夜貓子](https://marketplace.visualstudio.com/items?itemName=sdras.night-owl) ![](https://github.com/sdras/night-owl-vscode-theme/raw/master/first-screen.jpg) ### 27. [仙女座](https://marketplace.visualstudio.com/items?itemName=EliverLara.andromeda) ![](https://github.com/EliverLara/Andromeda/raw/master/images/andromeda.png) ### 28. [Darcula](https://marketplace.visualstudio.com/items?itemName=rokoroku.vscode-theme-darcula) ![](https://github.com/rokoroku/vscode-theme-darcula/raw/master/screenshot.png) ### 29. [地平線主題](https://marketplace.visualstudio.com/items?itemName=jolaleye.horizon-theme-vscode) ![](https://i.imgur.com/y0gi1ez.png) ### 30. [Cobalt2](https://marketplace.visualstudio.com/items?itemName=wesbos.theme-cobalt2) ![](https://raw.githubusercontent.com/wesbos/cobalt2-vscode/cobalt2-updates/images/ss.png) ## 光 想要程式碼編輯器更輕一些嗎?看看這些時尚的淺色主題。 您也可以透過安裝我們的[最佳淺色主題包](https://marketplace.visualstudio.com/items?itemName=thegeoffstevens.best-light-themes-pack)來安裝所有這些淺色主題。 ### 31. [原子一燈](https://marketplace.visualstudio.com/items?itemName=akamud.vscode-theme-onelight) ![](https://raw.githubusercontent.com/akamud/vscode-theme-onelight/master/screenshots/preview.png) ### 32. [Bluloco Light](https://marketplace.visualstudio.com/items?itemName=uloco.theme-bluloco-light) ![](https://raw.githubusercontent.com/uloco/theme-bluloco-light/master/screenshots/js.png) ### 33. [Brackets Light Pro](https://marketplace.visualstudio.com/items?itemName=fehey.brackets-light-pro) ![](https://raw.githubusercontent.com/EryouHao/brackets-light-pro/master/static/screenshot.png) ### 34. [作家](https://marketplace.visualstudio.com/items?itemName=xaver.theme-writer) ![](https://github.com/xaverh/theme-yscritwr/raw/master/screenshot.png) ### 35. [NetBeans Light](https://marketplace.visualstudio.com/items?itemName=obrejla.netbeans-light-theme) ![](https://github.com/obrejla/vscode-netbeans-light-theme/raw/master/images/vscode-netbeans-light-theme.png) ### 36. [安靜的燈光](https://marketplace.visualstudio.com/items?itemName=onecrayon.theme-quietlight-vsc) ![](https://github.com/onecrayon/theme-quietlight-vsc/raw/master/images/screenshot.png) ### 37. [跳燈](https://marketplace.visualstudio.com/items?itemName=bubersson.theme-hop-light) ![](https://raw.githubusercontent.com/bubersson/hop-theme-vscode/master/hop-light.png") ### 38. [NotepadPlusPlus Remixed](https://marketplace.visualstudio.com/items?itemName=sh4dow.theme-notepadplusplusremixed) ![](https://raw.githubusercontent.com/s-h-a-d-o-w/NotepadPlusPlus-Remixed-Theme/master/screenshot.png) ### 39. [GitHub Light](https://marketplace.visualstudio.com/items?itemName=Hyzeta.vscode-theme-github-light) ![](https://github.com/Hyzeta/vscode-theme-github-light/raw/master/screenshot/0.png) ### 40. [GitHub Plus](https://marketplace.visualstudio.com/items?itemName=thenikso.github-plus-theme) ![](https://github.com/thenikso/github-plus-theme/raw/master/screenshot.jpg) ## 多彩 厭倦了單色主題和沈悶的調色板?使用這些豐富多彩的主題為您的編輯器加入一些顏色。 您也可以透過安裝我們的[最佳彩色主題包](https://marketplace.visualstudio.com/items?itemName=thegeoffstevens.best-colorful-themes-pack)來安裝所有這些彩色主題。 ### 41. [紫色陰影](https://marketplace.visualstudio.com/items?itemName=ahmadawais.shades-of-purple) ![](https://raw.githubusercontent.com/ahmadawais/shades-of-purple-vscode/master/images/markdown.png) ### 42. [SynthWave](https://marketplace.visualstudio.com/items?itemName=RobbOwen.synthwave-vscode) ![](https://github.com/robb0wen/synthwave-vscode/raw/master/theme.jpg) ### 43. [藍色程式碼](https://marketplace.visualstudio.com/items?itemName=Sujan.code-blue) ![](https://i.imgur.com/JLCnwvi.jpg) ### 44. [賽博龐克](https://marketplace.visualstudio.com/items?itemName=max-SS.cyberpunk) ![](https://github.com/max-SS/cyberpunk/raw/master/assets/preview.png) ### 45. [LaserWave](https://marketplace.visualstudio.com/items?itemName=jaredkent.laserwave) ![](https://github.com/Jaredk3nt/laserwave/raw/master/screenshot.png) ### 46. [Zeonica](https://marketplace.visualstudio.com/items?itemName=andrewvallette.zeonica) ![](https://zeonicacom.files.wordpress.com/2018/09/zeonica_9502.png) ### 47. [潮人](https://marketplace.visualstudio.com/items?itemName=ModoNoob.vscode-hipster-theme) ![](https://github.com/ModoNoob/vscode-hipster-theme/raw/master/screenshot.png) ### 48. [野莓](https://marketplace.visualstudio.com/items?itemName=joebayer1340.wildberry-theme) ![](https://github.com/geoffstevens8/best-colorful-themes-pack/blob/master/images/wildberry.png?raw=true) ### 49. [Qiita](https://marketplace.visualstudio.com/items?itemName=Increments.qiita) ![](https://qiita-image-store.s3.amazonaws.com/0/6598/e054a4bb-cea1-8fc9-e193-fbb8376ed93d.png) ### 50. [軟體時代](https://marketplace.visualstudio.com/items?itemName=soft-aesthetic.soft-era-theme) ![](https://github.com/soft-aesthetic/soft-era-vs-code/raw/master/screenshot.png) ## 下一步是什麼? 想找更多主題?試試[搜尋 VS Code 市場](https://marketplace.visualstudio.com/search?target=VSCode&category=Themes&sortBy=Installs) 並依「主題」排序。開發人員已經建立了超過 2,500 個主題,您可以從中選擇來自訂 VS Code。 ___ 我喜歡建立讓開發人員滿意的工具。如果您喜歡這篇文章,您還應該查看我的其他專案: * [Code Time](https://www.software.com/code-time):自動程式設計指標和時間追蹤的免費擴展,就在您的編輯器中 * [SRC](https://www.software.com/src):在十分鐘或更短的時間內提供開發者世界的策略摘要 - 每週一次,直接發送到您的收件匣

開發人員的十大 Discord 伺服器

原文出處:https://dev.to/htnguy/top-10-discord-servers-for-developers-559o --- ### [Discord](https://discordapp.com/company) 到底是什麼? Discord 是一款基於社群的聊天應用程式,可讓您直接與您所在領域的其他人聯繫。儘管 Discord 最初是為遊戲玩家建置的,但隨著它的發展,各行各業的人們開始使用它來增強連接能力。 這些社區之一顯然是開發者社群。我說 **communities** ,複數,因為有多個子社區。一個人可能專注於網頁開發,而另一個人可能專注於遊戲開發。 ### 這是我加入開發者的 10 個最值得加入的 Discord 伺服器 1. [程式設計師聚會](https://discord.me/coding) 2. [Devcord](https://discord.me/devcord) 3. [編碼巢穴](https://discordapp.com/invite/code) 4. [SpeakJS](https://discord.me/speakjs) 5. [程式碼支援](https://discord.me/codesupport) 6. [Nodeiflux](https://disboard.org/server/425824580918181889) 7. [懶惰開發者](https://discordsl.com/server/4837/lazy-developers) 8. [TensorFlow](https://disboard.org/server/395520812347686912) 9. [程式設計師幽默](https://discordapp.com/invite/ph) 10. [Python](https://discordapp.com/invite/python) ### 我錯過了一個嗎? 伺服器有很多,所以將範圍縮小到少數是一項相當困難的任務,所以如果我錯過了一個非常有信譽的伺服器,請原諒我😥並將其發佈在下面的評論中。 以下是像您這樣的貢獻者提出的其他建議: [Reactiflux](https://www.reactiflux.com/) [Vue 土地](https://vue.land/) [打字稿](https://discordapp.com/invite/typescript) [Laravel](https://discordapp.com/invite/mPZNm7A) [Qovery](https://discordapp.com/invite/Bed5FRa)

使用 API Platform 來寫出優質的 API

原文出處:https://dev.to/juststevemcd/making-apis-the-right-way-with-api-platform-565p https://www.youtube.com/watch?v=NpfnnXi1CHI 我要坦白:直到最近有一個獨特的機會與 API Platform 的建立者進行直播,我才意識到我已經錯誤地建立了 API 太久了!最重要的是,這次經驗讓我希望自己多年前就曾使用 API Platform。現在,為什麼要猶豫使用它呢?答案在於一個潛在的誤解。 ## 打破誤解:PHP 與 Symfony 關於 API Platform 最常見的誤解通常源自於您需要深入了解 Symfony 才能開始的信念。這與事實相差甚遠。事實上,API 平台基本上是基於 PHP 的。它是如何交付的?現在這就是 Symfony 的用武之地。所以方向性很重要,API 平台不是 Symfony 的擴展,而是 Symfony 促進了 API Platform 的交付。 ## API Platform 專案剖析 如果您查看 API 來源實體,您會發現該平台提供了開箱即用的完整建立、讀取、更新和刪除 (CRUD) 功能。不需要額外的段。 ## 制勝因素:易於使用 簡單性和效率最終讓我選擇了 API 平台。只需三到四個命令,您就可以啟動、執行並準備啟動您的 API。結合更多命令,您就可以獲得一些強大的端點。只要一點點努力,一切就準備好了。無需採取進一步行動。 ## 癥結點:記住指令 作為 Laravel 開發人員,我習慣於“PHP artisan this”和“PHP artisan that”,因此 API 平台的挑戰來自於記住其不同的命令格式。在 API 平台中,任務是使用 Symfony 控制台在 Docker 中執行的,類似於 Laravel 中的完成方式 - 我們呼叫不同的東西。差別在於命令的用法。 ## 你為何還不試試看 API Platform? 那麼,回到我們最初的問題──你們為什麼還不使用 API Platform?是因為你跟我一樣,曾經錯誤地認為它需要紮實的 Symfony 知識才能開始? > 如果是這樣的話,我告訴你:事實並非如此。 API Platform 是一個強大的、使用者友善的環境,使用 PHP 建立 API 變得輕而易舉。因此,讓我們嘗試更多地使用 API 平台,因為如果您在 PHP 中建立 API,那麼您沒有理由不使用 API Platform。

您的下一個專案,可以試試看 HTMX 技術!

原文出處:https://dev.to/turculaurentiu91/why-you-should-choose-htmx-for-your-next-project-o7j 在本文中,我們將旨在了解為什麼您下次為 Web 應用程式選擇技術堆疊時應該考慮 HTMX 作為 React 的替代品。我們將研究傳統 HTTP JSON API + React 帶來的複雜性和挑戰,以及如何透過使用 HTMX 輕鬆避免它們。 **注意**:在本文中,我將討論 React,但它可以替換為任何其他前端框架,如 Angular、Vue、Svelte 或 Solid,但我談論 React 是因為它是大多數 Web 的預設技術開發人員預設為。 ### HTMX 到底是什麼 如果您還不知道,[HTMX](https://htmx.org/) 是一個小型瀏覽器 (JS) 庫,它使用一些屬性擴展了 HTML,允許您使用來自伺服器。它還使 HTML 能夠對所有動詞發出 HTTP 請求,而不僅僅是 GET 和 POST。 ## React 解決了什麼問題 React 是一個 JavaScript 程式庫,可協助您透過保持使用者介面與狀態同步來編寫高度互動的應用程式。您告訴它如何渲染給定的狀態,每次更新狀態時,它都會重新渲染(盡可能有效率)UI 以反映狀態變更。 每次狀態發生變化時,您都會通知庫它發生了變化,並提供新的狀態,它將處理 UI 更新。 需要本地記憶體狀態的高互動應用程式的範例可以是您可以在網路上找到的各種文字編輯器(VSCode)之一、拖放看板(如 Trello 或 JIRA)、視訊播放器或聊天室。 什麼不是此類應用程式的範例?您正在建立的待辦事項清單、您正在閱讀的新聞網站、您發布的部落格以及周圍的大多數網站。如果我們看一下 [80/20 規則](https://en.wikipedia.org/wiki/Pareto_principle) >80% 的結果來自 20% 的原因,80% 的結果來自 20% 的努力。 你可以說 80% 使用 React 的 Web 應用程式不需要本地狀態。對於那 20% 需要它的人來說,你可以說它只是應用程式的一小部分(大約 20%),其餘部分只能用 HTML 來表達。 **這些數字是編造的,我沒有任何研究來支持這一點** ## React 也解決了哪些問題,使其被現代網站廣泛採用 HTML 已經過時了。使用 HTML 製作應用程式的舊方法涉及頁面、連結和表單的集合,這些頁面、連結和表單向使用者描述給定資源的當前狀態以及他們可以執行哪些操作來更改它。 每次使用者與資源互動時,應用程式只能重新載入整個頁面以顯示資源的新狀態。 幾年後,FaceBook 推出了 React,這是一個 JS 程式庫,可讓開發人員建立單頁應用程式 (SPA)。導航時不再需要重新加載整個頁面,狀態更新的酷過渡、對用戶的有趣反饋以及其他使 Web 開發人員在其網站中採用 SPA 框架的細節。 ## 複雜性問題 ![AI 產生圖像,透過 next.js 展示現代應用程式的瘋狂複雜性](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpk0v0nz0d45hv91i166.png) 如果你不理解上面的架構,不用擔心,沒有什麼好理解的。我要求 ChantGPT 為我生成它,由於它過於複雜且沒有任何意義,它完美地反映了現代 Web 應用程式目前的預設基礎架構。 一個很酷的程式設計原則是**KISS**,它代表“保持簡單,愚蠢”,或者有些人可能喜歡開玩笑,“保持簡單,愚蠢!” 現代開發人員預設建立 Web 應用程式的當前基礎設施和技術堆疊極其複雜,做了很多不必要的事情,只是因為它很酷! 當您自己建立第一個 POC 時,效果很好,但下一刻您加入了更多團隊成員,並且使用多次迭代和「擁抱」更改的敏捷方式,它有點崩潰,原因是我們將往下看一下。 ## 傳統 HTTP JSON API + React 的狀態管理問題 在 Web 應用程式中,您經常要做的就是從資料庫中獲取資源的狀態並將其呈現給使用者。讓我們以任務管理應用程式為例。使用者有一個任務列表,每個任務都有一個狀態: - 任務的標題 - 說明 - 任務完成時的標誌 - 截止日期(可選) 我們通常將此狀態儲存在資料庫中,並將此資訊呈現給用戶,您必須: - 從使用者有權存取的資料庫中取得所有任務。 - 可以選擇轉換資料(也許您儲存完成的日期並從中計算「is_completed」標誌)。 - 將資料序列化為 JSON。 - 透過 HTTP 請求取得資料。 - (可選但通常)根據模式驗證資料,可能使用 YUP 或 ZOD。 - 使用 Redux、Zustand、react-query 或其他狀態管理庫將 JSON 轉換為狀態並將其儲存在快取中。 - 轉換 HTML 中的狀態,通常會決定使用者可以使用資料做什麼。 簡而言之,我們正在描述如何在 JavaScript 中渲染所有資源的所有可能狀態,在瀏覽器中下載所述 JavaScript,然後 JavaScript 下載一堆 JSON 格式的資料並將其渲染(如果它知道如何)瀏覽器顯示為HTML! 向使用者顯示任務清單需要做大量工作,特別是當任務僅在使用者變更時才更改時,應用程式必須將應用程式置於載入狀態,發出另一個 HTTP 請求(以PUT 或PATCH 或DELETE)使快取值(狀態)無效並重新獲取它以顯示更改的任務。 或者更糟的是,當用戶更改某些任務時,樂觀地更新本地狀態並立即顯示更改,並在幕後執行更新請求,僅在他們成功更新後通知用戶更新失敗。 這是非常容易出錯的。對於這個待辦事項應用程式來說,它可能會很有效,因為您是唯一的開發人員,並且該應用程式足夠大,您可以在腦海中保留正在發生的所有事情的地圖。但是當你的團隊規模更大時,尤其是當你將團隊分成前端和後端時,溝通不良可能會導致很多問題。 後端可能使用“is_completed”標誌,而前端可能需要“is_active”標誌。後端可能會將經過 Markdown 處理的「描述」傳送到 HTML,而前端可能希望它不被處理。後端可能會將“描述”設為可選,以允許使用者在前端不同步時保存草稿,並且您會看到許多“未捕獲的類型錯誤:無法讀取未定義的屬性(讀取“toLowerCase” )” 另一方面,在 HTMX 上,您可以直接在範本上呈現 HTML,只要後端語言允許,就可以確保類型安全。您僅向瀏覽器發送相關訊息,向使用者提供對資源的適當控制,並指示瀏覽器或 HTMX 如何解釋使用者操作以及後端對這些操作的回應。所有應用程式狀態都是 HTML,這個概念稱為 [HATEOAS](https://htmx.org/essays/hateoas/) ## 傳統 HTTP JSON API + React 對文件的需求 為了讓兩個團隊(後端和前端)獨立工作並透過 HTTP JSON API 進行通信,您需要擁有適當的 API 文件。您還需要記錄如何計算使用者可以對給定資源執行哪些操作以顯示控制項。 大多數此類文件寫起來都很痛苦,特別是因為通常需要在實作之前編寫,而開發人員尚未完全理解問題的範圍,因此前端可以並行開發。這通常會在開發過程中進行許多更新,以適應開發過程中出現的問題,並可能導致團隊之間的版本不一致。 您還需要對 API 進行版本控制,並注意不要在非主要版本變更中引入重大變更。您無法再在不變更主要版本的情況下變更欄位名稱。您還需要保持 API 的多個版本運作或強制前端團隊進行調整。 大多數時候,文件已經過時了。有些必須緊急修復,有些新要求是在發布前一天提出的,現在您的文件已經過時,即使在很短的時間內。而且您必須記住更新它,或者更糟的是,您建立了一張票來記住它,而其他人拿起它,但沒有完整的圖片並記錄了錯誤! ## 重複的邏輯問題 對於每個資源,您必須實施授權策略。您必須確定目前使用者是否可以將任務 **46234** 標記為已完成。您必須在後端程式碼的某個位置編寫此檢查。否則,您的應用程式將開放給_不安全的直接物件參考_,或任何使用 Postman 的人都可以將您的任務標記為已完成。 您還必須在前端實現相同的邏輯,僅當用戶有權標記已完成時才顯示標記按鈕(讓我們假設您可以與其他用戶共享您的任務,但只有您可以更改它們)。 現在每次這個邏輯改變時,你都必須在兩個應用程式中實作它,並同時發布它或擁有多個版本的API。 ## 效能問題 為了使用 React 在瀏覽器中呈現網站,您需要將佔用大量內存和解析/處理影響的 React 程式碼、狀態管理庫程式碼、腳趾 UI 庫程式碼、CSS-IN- 捆綁在一起。JS 庫程式碼、應用程式程式碼以及我們透過NPM 安裝和使用的任何js 程式庫(我們並不羞於安裝新套件,請參閱[leftpad 問題](https://www.theregister.com/2016/03/23/npm_left_pad_chaos/))。這通常會導致透過網路傳送大塊的 JavaScript 資源。當然,您可以在瀏覽器中緩存,但在現代敏捷開發中,每個衝刺至少部署一次,因此這無法解決任何問題。這會消耗網路流量和電池,這對行動裝置來說是一個經常被忽視的問題。 上述JavaScript需要由瀏覽器來解釋,消耗處理能力和電池。 JavaScript,尤其是 ReactDOM,需要追蹤 DOM 的鏡像。在其之上加入普通 DOM 和本地狀態緩存,以及所有渲染函數,以及所有“useMemo”、“useCallback”和“useState”。也要加入需要在記憶體中保存所有上下文變數的所有閉包。 JavaScript 引擎並不以其記憶體效率而聞名!您會聽到人們抱怨瀏覽器消耗了多少內存,但他們低估了他們存取的網站所消耗的內存量。 所有這些加起來,最終會耗盡用戶的電池和記憶體。當然,您可以付出努力並優化所有這些,或使用其他程式庫(如 Svelte),但所有這些努力都可以用於為您的用戶提供更有意義的功能。 ## 服務端渲染的需要 近年來,我們播種了伺服器端渲染專用框架(如「Next.js」)的興起。它們的流行凸顯了對以 HTML 格式交付內容的需求,特別是出於可存取性優化、效能和搜尋引擎優化的原因。 你不想等待瀏覽器下載 JavaScript 來渲染頁面,然後等待 JavaScript 發出 HTTP 請求來獲取內容然後渲染它,你希望它立即渲染,特別是對於上面的情況折疊內容。 這又增加了一層複雜性,包括: - 基礎設施,現在您還需要另一台伺服器用於前端應用程式 - 程式碼更複雜,包括什麼程式碼在伺服器上執行以及什麼在瀏覽器上執行的思維導圖 - 部署管道現在更加複雜 - 測試基礎設施現在更加複雜 - 現在解決問題變得更加困難,您需要了解問題是在瀏覽器上、在客戶端應用程式伺服器上還是在 API 伺服器上 ## 解決這些問題 Web 開發社群各自使用自己的語言或開發技術,以不同的方式解決這些問題: - Next.js(以及 Nuxt 等) - 反應伺服器元件 - 拉維爾 - 慣性.JS - 活線 - 點網 - Blazor 頁面 - 靈藥 - 鳳凰即時查看 - 鐵鏽 - 樂浦伺服器功能 還有許多我忘記或從未聽說過的其他解決方案! 無論如何,此類解決方案的存在和流行證明了這些問題是有效的並且在 Web 開發人員的日常生活中遇到過。否則他們不會不遺餘力地解決這些問題,尤其是以開源的方式! 還有 [Turbo](https://turbo.hotwired.dev/) 以及採用它們的框架、Ruby on Rails、PHP Symphony 以及其他可能以與 HTMX 相同的方式解決相同問題的框架。選擇 HTMX 只是個人喜好,但你絕對應該了解這一點,這和 HTMX 一樣酷! 在所有這些中,HTMX 脫穎而出,不僅因為它不會將您鎖定到特定技術,您可以透過對模板進行微小更改來從 PHP 切換到 Rust,而且還因為它完全消除了對有狀態元件的需求,或者需要追蹤與資源無關的應用程式的某種狀態。 例如,讓我們採用確認對話方塊模式。您通常最終要做的是,您有一個本地記憶體狀態(如果它是開啟的),並根據該狀態將其顯示給使用者。在 HTMX 中,狀態 **IS THE HTML** 意味著當您按一下開啟模式時,您 **GET** `tasks/{taskId}/confirm-delete` 並將回應 HTML 嵌入到 DOM 中。當它被刪除時,您就完全刪除了模式和任務!這以一種獨特且極其簡單的方式解決了上述所有問題,您不需要: - 追蹤狀態 - 知道如何渲染對話框 - 記錄API - 檢查使用者是否可以刪除任務(在前端) - 您的後端應用程式始終負責 - 您可以獲得更好的安全性,因為您不會向瀏覽器發送不相關的資料並竊取敏感資訊 - 你會得到更好的表現 __*最重要的是,您可以讓您的應用程式保持簡單,只有在解決使用者問題時才允許複雜性!*__ 您只需指示 HTMX 從何處獲取對話框以及將其放置在何處,一切就完成了! ``` <!-- the delete button --> @if ($chirp->user->is(auth()->user())) <form> @csrf @method('delete') <x-dropdown-link :component="'button'" type="submit" hx-get="{{ route('chirps.confirm-destroy', $chirp) }}" hx-swap="beforeend" hx-target="closest .chirp" > {{ __('Delete') }} </x-dropdown-link> </form> @endif <!-- the dialog template --> <div class="modal fixed z-10 inset-0 overflow-y-auto flex justify-center items-center bg-black bg-opacity-50" style="backdrop-filter: blur(14px);"> <div class="bg-white rounded p-6"> <h2 class="text-xl border-b pb-2 mb-2">Confirm Action</h2> <p>Are you sure you want to delete this chirp?</p> <div class="flex justify-end mt-4 gap-4"> <x-secondary-button _="on click remove closest .modal" > Cancel </x-secondary-button> <form> @csrf <x-danger-button hx-delete="{{route('chirps.destroy', $chirp)}}" hx-target="closest .chirp" hx-swap="delete"> Delete </x-danger-button> </form> </div> </div> </div> ``` _這個範例來自我的 [HTMX with Laravel] 教學(https://dev.to/turculaurentiu91/laravel-htmx--g0n) ,請看!_ 就像這樣,當我們單擊刪除按鈕時,我們指示 HTMX 對 `chirps/{chirp}/confirm-destroy` 執行 **GET** 請求,並將結果 HTML 放在最接近的父級 `< 之前div class="chirp">` 結束(在底部)。在刪除對話方塊中,當使用者確認時,我們指示 HTMX 對 `chirps/{chirp}` 端點執行 **DELETE** 請求,成功後,我們刪除具有 `chirp` 類別的最接近的父級。 ## 結論 在不斷發展的 Web 開發領域,看到 HTMX 等倡導簡單性和回歸基礎的工具令人耳目一新。透過利用 HTML 和 HTTP 的強大功能,HTMX 允許開發人員建立動態 Web 應用程式,而無需傳統 JavaScript 框架的複雜性和開銷。 因此,下次您開始新專案或考慮重構現有專案時,請嘗試 HTMX。您可能會驚訝於用這麼少的錢就能取得如此大的成就。

Laravel + GraphQL 接案心得&範例分享 Part 1:強大優點、API 線上試玩、工具介紹

客戶最近有把舊 laravel 專案改寫為 SPA 的需求,需要前後端分離 為了方便前後端溝通、改善開發者體驗,我建議&協助他們導入 GraphQL 技術到 laravel 專案中! 實際導入&開發半年之後,成效非常不錯!前端工程師、後端工程師都用得很開心! 今天跟大家分享一些心得&範例程式碼! ## 破除迷思 > 很多公司聽到 GraphQL 會有點卻步,覺得太新、不成熟 其實,這技術面世八年了,在國外已經被許多公司廣泛採用,不算很新了! > 很多公司會以為這是給大公司用的技術,小公司不適合使用 其實,我自己的使用經驗是,就算團隊只有兩個工程師,這技術也很好用,會讓開發速度更快,不會更慢! > laravel 社群會以為這技術在 node 社群、或其他社群比較常見 其實,laravel 社群也有很好用的套件,導入也很方便! 所以這技術非常值得學習、使用,至少了解一下! ## 優點介紹 我認為最大的優點就是,大幅降低了前後端溝通的成本! 傳統開發,後端寫完 API,要另外寫文件告訴前端網址是多少、回傳的資料格式 然後前端需要用 postman 之類的工具,方便測試、開發 使用 graphql 的話,後端寫完程式碼,就同時自動生成文件&測試工具了! 為了方便讀者「親自試玩」以上描述,我準備了一個範例專案給大家! 這個專案模擬電商網站,API 可以撈 products 與 comments 兩種資料! 然後可以訂閱商家的電子報,也就是新增 subscriber 這種資料! ## 實務範例與 API 線上試玩 我先分享範例專案給大家! https://graphql-laravel-example.tw/ 原始碼也已公開 https://github.com/howtomakeaturn/graphql-laravel-example --- 以往 RESTful 的設計,「讀取資料」這種動作,在 graphql 稱之為 query https://github.com/howtomakeaturn/graphql-laravel-example/tree/main/app/GraphQL/Queries 會去「更新資料庫」的動作,在 graphql 稱之為 mutation https://github.com/howtomakeaturn/graphql-laravel-example/tree/main/app/GraphQL/Mutations 以上兩個資料夾可以翻閱一下,每支 api 會是一個檔案,所以很好管理 接著使用 graphql 社群的強大工具:graphiql,就同時得到文件&測試工具了! https://graphql-laravel-example.tw/graphiql 我安裝了一份 graphiql 給大家,點進去玩玩看吧! 把他當成是技術規格文件與 Postman 測試工具,身兼兩種用途! 有了這個工具,大幅減少了前後端需要溝通的事項,對於前後端合作有「巨大幫助」! (請注意,實務上 graphiql 建議在本機執行,不要這樣線上公開,會有資安疑慮) ## 套件介紹 在 graphql 社群,有兩種開發 api 的哲學 分別是 schema-first 與 code-first 兩種方法 laravel 社群最知名的 schema-first 套件是這款 https://github.com/nuwave/lighthouse laravel 社群最知名的 code-first 套件是這款 https://github.com/rebing/graphql-laravel schema-first 與 code-first 的差異與優缺點我先不細談 總之,我個人比較喜歡 code-first,我覺得比較直觀、簡單、好導入 所以我的範例是用 https://github.com/rebing/graphql-laravel 這套件 您的 laravel 版本建議至少要是 8.0 以上版本,太舊的可能會有問題 順帶一提,兩個套件背後都是使用 https://github.com/webonyx/graphql-php 所以底層元件一樣,兩者有很多通用的觀念,不用太擔心 --- graphiql 是 graphql 官方的重要工具 laravel 社群已經有人寫好懶人安裝套件了 https://github.com/mll-lab/laravel-graphiql 按照說明安裝即可得到超好用的自動文件&測試工具面板! ## 結論 有了以上兩個套件,按照說明分別安裝 然後參考我提供的範例程式碼 https://github.com/howtomakeaturn/graphql-laravel-example 您應該就可以在專案之中導入 graphql 基礎架構,並且開始用 graphql 寫出您的第一支 api 我在替客戶導入的時候,發現網路上 graphql 的教學、說明雖然很多 但是剛開始寫還是很困難,很少範例 所以我製作這份 open source 方便大家參考&入門 並且直接把 graphiql 面板公開部署上線,方便大家體驗! (此為系列文章,更多內容會在近期發佈) --- # 系列文章 - [Laravel + GraphQL 接案心得&範例分享 Part 1:強大優點、API 線上試玩、工具介紹](https://codelove.tw/@howtomakeaturn/post/yx08mx) - [Laravel + GraphQL 接案心得&範例分享 Part 2:前端 Query/Mutation 與 React 串接範例](https://codelove.tw/@howtomakeaturn/post/2an0Gx)