Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 一区二区三区免费,亚洲a在线视频,精品一区二区日本高清

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          D3.js實戰教程:1 D3.js簡介


          章涵蓋

          • 了解 D3.js 的作用及其背后的理念
          • 認識與 D3 結合使用來創建數據可視化的工具
          • 使用代碼創建可縮放矢量圖形 (SVG) 并為其設計樣式
          • 了解數據可視化最佳實踐如何支持您作為 D3 開發人員的旅程

          D3.js 是網絡上幾乎所有最具創新性和令人興奮的信息可視化的幕后黑手。D3 代表數據驅動文檔,它是一個品牌名稱,也是多年來以某種形式提供的一類應用程序。我們可以使用這個庫來構建各種數據驅動的項目,從簡單的條形圖到動態地圖,再到復雜的空間和時間探索。當您希望在數據可視化方面獲得完全的創意和技術自由時,無論您是構建用于研究的交互式原型、頂級科技公司廣泛且完全響應的數據儀表板,還是揭示數據故事的長篇文章,D3 都是您的首選工具當用戶滾動時。

          1.1 什么是D3.js

          D3 是一個開源 JavaScript 庫,由 Mike Bostock 于 2011 年創建,用于為 Web 生成動態和交互式數據可視化。盡管過去幾年推出了許多新的數據可視化庫,但它們通常在底層使用 D3。這是因為 D3 與 JavaScript 一樣,非常靈活且強大。




          圖 1.1 漢密爾頓中每條線的交互式可視化,這是Shirley Wu創建的 D3 項目


          1.1.1 對可通過網絡訪問的數據可視化的需求

          D3.js 的創建是為了滿足對可通過網絡訪問的復雜數據可視化的迫切需求。假設您的公司正在使用商業智能工具,但它沒有顯示您的團隊所需的數據模式。您必須構建一個自定義儀表板,根據您的特定領域量身定制,準確顯示客戶的行為方式。該儀表板需要快速、交互式且可在整個組織內共享。D3 將是此類項目的自然選擇。

          或者想象一下,您被雇用來實現一個網頁,該網頁以可視化方式展示 LGBTQ+ 群體(女同性戀、男同性戀、雙性戀、跨性別者、酷兒等)的權利在過去幾十年和全世界的演變情況。此頁面包含許多隨著用戶滾動而變化的創意可視化效果。它們通過鼠標事件顯示更多信息并適應屏幕大小。D3 將是構建此類項目的首選工具。

          Mike Bostock 最初創建 D3 是為了利用新興的 Web 標準,正如他所說,“避免了專有表示并提供了非凡的靈活性,暴露了 CSS3、HTML5 和 SVG 等 Web 標準的全部功能”(http: // d3js.org)。D3.js 版本 7 是這個流行庫的最新版本,它通過模塊化 D3 的各個部分來延續這一趨勢,使其與 ECMAScript 模塊(一種基于 JavaScript 的腳本語言)和現代應用程序開發完全兼容。

          D3.js 使開發人員不僅能夠制作豐富的交互式應用程序,而且能夠制作樣式和服務類似于傳統 Web 內容的應用程序。這使得它們更可移植,更適合增長,并且更容易由其他團隊成員可能不知道 D3 的具體語法的大型團體維護。

          圖 1.2 D3 開發人員可以訪問各種數據表示形式,地圖就是一個例子。這是由Christophe Viau創建的數字高程模型 (DEM) 地圖。


          Bostock 決定廣泛處理數據并創建一個能夠像圖表一樣簡單、像網絡一樣簡單、像列表一樣簡單地呈現地圖的庫,這也意味著開發人員不需要了解以下內容的抽象和語法:一個用于地圖的庫,另一個用于動態文本內容的庫,還有另一個用于傳統圖形的庫。相反,用于運行交互式網絡可視化的代碼接近于純 JavaScript,并且也類似于表示 D3 地圖上的動態點的代碼。方法是相同的,但數據也可以是相同的,以一種方式制定用于網絡的節點和鏈路,而以另一種方式制定用于地圖上的地理空間表示。

          D3 不僅可以創建復雜多樣的圖形,還可以嵌入用戶期望的高水平交互性,這對于現代 Web 開發至關重要。使用 D3,每個圖表的每個元素(從旋轉的地球儀到餅圖的切片)都以相同的方式進行交互。由于 D3 是由精通數據可視化實踐的人編寫的,因此它包含數據可視化和 Web 開發中標準的交互式組件和行為。

          圖 1.3 交互性是 D3 的核心。在此網絡可視化中,鼠標交互揭示了不同組織之間的關系以及特定于所選節點的信息(https://amdufour.github.io/organizations-against-polization)。



          1.1.2 什么時候使用D3.js?

          數據可視化領域正在蓬勃發展,可用于生成數據綁定圖形的工具數量在過去十年中呈爆炸式增長。我們擁有 Excel(數據可視化的常用入口)和 Power BI(用于構建儀表板的 Microsoft 解決方案)等商業智能工具。另一方面,更有經驗的數據科學家通常會轉向 R 的 ggplot2 或 Python 的 matplotlib。

          基于瀏覽器的點擊式工具(例如 Tableau、Flourish、DataWrapper、RAWGraphs 和 Google 圖表)也占據了主導地位,允許用最少的技術知識創建令人驚嘆的作品。

          最后,HighCharts、Chart.js 和 D3.js 等 JavaScript 庫專門用于開發基于 Web 的交互式可視化。

          而且這個列表遠非詳盡無遺......

          那么,D3 在數據可視化工具的海洋中處于什么位置呢?我們何時以及如何使用它?我們可以說,雖然 D3 完全可以構建此處列出的數據可視化庫提供的任何圖表,但它通常不是構建簡單的傳統圖表或探索階段(我們調查哪種類型的可視化是)的首選選項。最適合代表我們的數據。構建 D3 項目需要時間,而 D3 在復雜、交互式和定制的項目中真正表現出色。數據可視化不僅僅是折線圖和散點圖!雖然上面提到的工具通常專注于預定義的圖表,但 D3 允許我們將數據綁定到任何圖形元素,并通過以獨特的方式組合這些視覺元素來打破常規。

          圖 1.4 D3 具有 SVG 和畫布繪圖功能,允許開發人員構建自定義可視化效果,例如Elijah Meeks的樂譜表示形式。


          以下是我們如何在數據可視化項目范圍內使用 D3 的示例。首先,我們從預先存在的數據集或手動收集的數據開始。在開始數據分析過程之前,我們通常會花費大量時間清理、格式化和準備數據。Python 和 R 等數據科學工具在這方面功能強大,可以幫助我們識別隱藏在數據中的故事。Excel 還可以完成簡單的數據整理和數據分析工作,并且需要較少的技術背景。我們甚至可以使用 JavaScript 和 D3 進行基本數據探索,因為它們提供了我們將在本書后面討論的統計方法。

          一旦數據分析開始,通常會創建一些原型來幫助完善我們的故事。Tableau 和 RawGraphs 等工具使我們能夠快速生成此類圖表。這是非常重要的一步,在此階段創建的可視化通常并不花哨或精致。我們不想在原型設計階段過于執著于我們的想法,花費大量時間。我們可能會發現自己必須“殺死我們的寶貝”并重新開始幾次,直到我們找到最適合我們想要講述的故事的可視化效果。網絡圖可能是一個例外,直接跳到 D3 對于這些項目通常是有意義的。

          最后,一旦我們知道要創建的可視化類型,就該卷起袖子,對其進行編碼,并使用 D3 對其進行完善。如今,編碼步驟通常發生在單頁應用程序 (SPA) 中,使用 React 或 Svelte 等框架。

          圖 1.5 使用 D3 構建的自定義可視化的另一個示例,其中形狀與每首歌曲的不同屬性(例如持續時間、流派和節奏)成比例(https://amdufour.github.io/spotify-hits)。



          1.1.3 D3.js 的工作原理

          您可能已經嘗試過 D3,并發現它并不容易上手。也許那是因為您希望它是一個簡單的圖表庫。一個恰當的例子是創建條形圖,我們將在第 2 章和第 3 章中進行此操作。D3 沒有一個函數來創建條形圖。相反,它有一個將<svg>容器附加到文檔對象模型 (DOM) 的函數,以及另一組附加容器的函數。<rect>每個數據點的元素。然后,我們使用比例來計算構成直方圖的矩形的長度并設置它們的屬性。最后,我們調用另一組函數,將 x 軸和 y 軸添加到條形圖中。如圖 1.6 所示,這個過程比使用 Highcharts 等專用圖表庫要長得多。但 D3 處理數據和圖形的明確方式也是它的優勢。盡管其他圖表庫允許您方便地制作折線圖和餅圖,但當您想要創建不屬于傳統圖表范圍的可視化效果或實現自定義交互時,它們很快就會崩潰。不是D3。D3 允許您構建您可以想象的任何數據驅動圖形和交互性。

          圖 1.6 使用 Highcharts 與 D3.js 生成的條形圖。Highcharts 的代碼更簡單、更短,但 D3.js 更通用。



          在圖 1.7 中,您可以看到我們通常如何使用 D3 進行數據可視化編碼的地圖。我們從一個數據集(通常是 CSV 或 JSON 文件)開始,然后使用 d3-fetch 模塊將此數據集加載到我們的項目中。我們通常需要執行一些操作來格式化數據。例如,我們確保數字和日期的格式正確。如果我們之前沒有這樣做,我們可能還想詢問我們的數據集以找到其主要特征。例如,提前知道其最大值和最小值通常很有幫助。然后我們準備開始構建可視化,為此我們將結合我們將在本書中學習的不同 D3 函數。最后,我們通過監聽鼠標事件來添加交互性,允許用戶過濾數據或放大可視化。

          圖 1.7 如何使用 D3.js 實現數據可視化



          1.2 D3 生態系統 - 入門所需了解的內容

          D3.js 從來不會單獨使用,而是我們結合起來創建豐富的 Web 界面的技術和工具生態系統的一部分。與任何網頁一樣,D3 項目是在 DOM(文檔對象模型)內構建的,并利用 HTML5 的強大功能。盡管 D3 可以創建和操作傳統的 HTML 元素,例如分區 ( <div>) 和列表 ( <ul>, <ol>),但我們主要使用 SVG 圖形或在畫布(從腳本渲染位圖圖像的 HTML 元素)內生成可視化效果。然后,我們還可以使用舊的 CSS 樣式表,它可以增強 D3 項目并使其設計更易于維護,尤其是在廣泛的團隊中。

          鑒于 D3 是一個 JavaScript 庫,我們自然傾向于將 D3 方法與本機 JavaScript 函數結合起來來訪問和操作數據。D3 現在完全支持 JavaScript 的 ECMAScript 2015 或 ES6 修訂版以及大多數最新更新。D3 還作為模塊提供,可以集成到我們構建 Web 項目所用的最新框架和庫中。使用這些模塊通常是首選方法,因為它不會污染我們應用程序的全局范圍。

          在本節中,我們將簡要討論這些技術及其在 D3 生態系統中的作用。由于 SVG 知識是理解 D3 的基礎,因此我們將花時間更詳細地解釋您開始構建可視化所需理解的基礎知識。如果您已經熟悉 HTML、SVG 元素、CSS、JavaScript 和 JavaScript 模塊,請隨意瀏覽或跳至第 1.3 節。

          1.2.1 HTML 和 DOM

          與 GIF 動畫和框架成為網絡動態內容頂峰的時代相比,我們已經走過了很長一段路。在圖 1.8 中,您可以看到為什么 GIF 從未在強大的基于 Web 的數據可視化中流行起來。GIF 與設計用于使用 VML(矢量標記語言)的 infoviz 庫一樣,對于早期瀏覽器來說是必需的,但 D3 是為不再需要向后兼容性的現代瀏覽器而設計的。

          圖 1.8 20 世紀 90 年代的一些例子,比如dpgraph.com,仍然存在,讓我們想起動畫 GIF 無處不在的時代。



          當您登陸網頁時,要加載的第一個文件是超文本標記語言或 HTML 文件,如下例所示。瀏覽器解析 HTML 文件以構建文檔對象模型或 DOM,這是用于 Web 文檔的編程接口。我們經常將其稱為 DOM 樹,因為它由一組嵌套元素(也稱為節點或標簽)組成。在我們的示例中,<head>和 the<body>元素是<html>父元素的子元素。同樣,標簽是、the和標簽<body>的父標簽。標題也是該元素的同級元素。當您加載網頁時,您在屏幕上看到的是標記中包含的元素。

          <!DOCTYPE#nbsp;html>
          <html>
            <head>
              <meta charset="UTF-8">  
              <title>A simple HTML file | D3.js in Action</title>
            </head>
            <body>
              <h1>I am a title</h1>
              <div>
                <p>I am a paragraph.</p>
                <p>I am another paragraph.</p>
              </div>
            </body>
          </html>

          在 DOM 中,每個元素的三類信息定義了其行為和外觀:樣式、屬性和特性。樣式決定顏色、大小、邊框、不透明度等。屬性包括類、id 和交互行為,盡管某些屬性也可以確定外觀,具體取決于您正在處理的元素類型。對于 SVG 元素,屬性用于設置不同形狀的位置、大小和比例。屬性通常指的是狀態,例如復選框的“checked”屬性,如果該框被選中,則該屬性為 true;如果該框未被選中,則該屬性為 false。盡管術語“屬性”和“屬性”經常互換使用,但它們是兩個不同的東西。呈現 DOM 時,屬性顯示為初始狀態。屬性是元素的當前狀態,并且可以隨著用戶與界面交互而改變。在第2章中,我們將討論用于生成或修改HTML和SVG元素的樣式和屬性的D3方法。

          DOM 還決定元素在屏幕上的繪制順序,子元素在父元素之后和內部繪制。盡管 CSS 屬性z-index使我們能夠部分控制傳統 HTML 元素繪制到屏幕上的順序,但 SVG 元素嚴格遵循它們在 DOM 中出現的順序。根據畫家的模型,之后繪制的內容出現在之前繪制的內容之上。

          1.2.2 SVG——可縮放矢量圖形

          可擴展矢量圖形 (SVG) 的引入確實改變了網絡的面貌。幾年之內,SVG 圖形成為主要的 Web 開發工具。光柵圖形(PNG 和 JPG)由微小的像素組成,當我們放大得太近時,這些像素就會變得可見,而矢量圖形則是通過數學和幾何圖形構建的。它們在任何尺寸和任何屏幕分辨率下都能保持清晰的外觀。SVG 圖形的另一個顯著優勢是它們可以直接注入 DOM,允許開發人員操縱其元素并為其設置動畫,并使屏幕閱讀器可以訪問它們。如果構建正確,SVG 也具有高性能,其文件大小僅為等效光柵圖像的一小部分。

          當使用 D3 創建數據可視化時,我們通常將 SVG 形狀注入 DOM 并修改其屬性以生成組成可視化的視覺元素。了解 SVG 的工作原理、主要 SVG 形狀及其表示屬性對于大多數 D3 項目至關重要。

          如何訪問代碼文件

          本書的每一章都包含旨在支持您的學習體驗的代碼練習。我們強烈建議您“做”這本書,而不僅僅是“讀”這本書,這意味著在閱讀章節時完成練習。通過這種方式,您將保留更多信息,并很快就能構建自己的 D3 項目!

          對于每個練習和項目,您都可以訪問現成的代碼文件。您可以在本書的 Github 存儲庫(https://github.com/d3js-in-action-third-edition/code-files)上找到它們。如果您熟悉 Git,則可以將存儲庫克隆到您的計算機上。您還可以下載壓縮文件。

          從 Github 存儲庫下載代碼文件


          每一章都有自己的文件夾,其中包含一個或多個練習,按照每章中的部分編號。練習包括一個start文件夾,其中包含入門所需的所有文件。您將在文件夾中找到練習的完整解決方案end。當您完成一章的各個部分時,您可以繼續在上一部分使用的文件中進行編碼,或者使用專用于該部分的文件夾重新開始。兩種選擇都會導致相同的結果。

          讓我們開始探索矢量圖形。轉到本書提供的代碼文件。找到end中的文件夾chapter_01/SVG_Shapes_Gallery并右鍵單擊該文件index.html。在菜單中,轉到打開方式并選擇瀏覽器。我們建議使用 Chrome 或 Firefox,因為它們具有出色的檢查器工具。該文件將在新的瀏覽器選項卡中打開,并且將出現您在圖 1.9 中看到的矢量圖形。您還可以在 Github 托管項目 ( https://d3js-in-action-third-edition.github.io/svg-shapes-gallery ) 上查看這些 SVG 形狀。

          圖 1.9 我們將在本節中構建的基本 SVG 形狀圖庫。


          您正在查看的 SVG 圖形包含創建 D3 可視化時最常使用的形狀:線條、矩形、圓形、橢圓形、路徑和文本。

          使用 D3 時,您通常會告訴庫應將哪些形狀附加到 DOM。您還負責了解需要計算哪些表示屬性才能使形狀具有您正在尋找的尺寸、顏色和位置。在下面的練習中,您將編寫創建圖 1.9 中每個 SVG 元素的代碼。我們將此練習稱為SVG 形狀圖庫。之后,您將了解入門所需的所有 SVG 基礎知識。

          在您選擇的代碼編輯器中打開練習文件夾index.html中的文件。我們推薦VS Code,這是一個免費、易于使用的代碼編輯器,并且具有多種功能,對前端開發很有幫助。startSVG_Shapes_Gallery

          正如您所看到的,index.html是一個簡單的 HTML 文件。如果您在瀏覽器中打開此文件(右鍵單擊該文件并在“打開方式”菜單中選擇瀏覽器),您將只會看到一個空白頁面。這是因為該<body>元素為空。在接下來的小節中,我們將向此<body>元素添加 SVG 形狀。

          清單 1.1.a SVG 形狀庫練習的起始 HTML 文件

          <!DOCTYPE html>
          <html>
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">  
            <title>SVG Shapes Gallery | D3.js in Action</title>
          </head>
          <body>
            
          </body>
          </html>

          哪里可以找到更多信息

          以下部分將介紹多個 SVG 元素及其屬性。作為開發人員,我們在構建項目、使用我們不熟悉的 SVG 元素或尋找 JavaScript 函數來執行特定操作時嚴重依賴在線資源。在前端開發中,MDN Web Docs ( https://developer.mozilla.org/ ) 始終是可靠且全面的資源。它包含 HTML 元素及其屬性、CSS 屬性和 JavaScript 函數的易于理解且通常可編輯的示例。

          響應式 svg 容器

          在 SVG 圖形的世界中,<svg></svg>容器是在其上繪制所有內容的白板。每個 SVG 形狀都嵌套在<svg>父級中。要查看其實際效果,請在元素index.html內編輯并添加 SVG 容器<body>。在瀏覽器中重新加載頁面。目前還看不到任何東西。

          <body>
            <svg></svg>
          </body>

          打開瀏覽器的檢查器工具(在瀏覽器窗口中右鍵單擊并選擇“檢查”)。在檢查器窗口中,您將看到組成頁面的 DOM。找到<svg></svg>容器,也稱為 SVG 節點。當您在檢查器中將鼠標移到它上面時,SVG 元素會在頁面上突出顯示。您可以在圖 1.5 中看到此效果。

          圖 1.10 在 DOM 樹中選擇并在視口中突出顯示的 SVG 節點


          默認情況下,瀏覽器為 SVG 容器提供寬度300px和高度。150px但我們也可以使用屬性來分配這些值。屬性用于提供有關 HTML 元素的附加信息。對于內聯 SVG,我們主要使用屬性來設置組成 SVG 圖形的元素和形狀的大小和位置。

          例如,我們可以設置SVG 容器的寬度和高度屬性。返回到文本編輯器,并將 awidth和 aheight屬性添加到 SVG 容器。將它們的值設置為900和300并保存文件。

          <svg width="900" height="300"></svg>

          在瀏覽器中重新加載項目并在檢查工具中找到 SVG 節點。請注意,寬度和高度屬性現在顯示在 SVG 容器的括號內。如果將鼠標移到檢查工具 DOM 樹中的 SVG 節點上,您還會看到視口中的 SVG 容器現在的大小為 900 像素 x 300 像素。

          圖1.11 SVG節點采用其屬性指定的大小


          為了幫助我們查看 SVG 容器,而不必從檢查器中突出顯示它,讓我們給它一個邊框。向 SVG 容器添加樣式屬性并插入 CSS 邊框屬性。在下一個代碼片段中,我們使用 border 速記屬性創建一個寬度為 1px 的黑色實心邊框。

          <svg width="900" height="300" style="border:1px solid black;"></svg>

          保存文件,重新加載頁面并確認 SVG 容器周圍有邊框。現在,調整瀏覽器窗口的大小,直到它小于 SVG 容器。您將觀察到 SVG 容器保持固定的寬度和高度,并且不適應瀏覽器窗口的大小。讓我們嘗試使 SVG 容器具有響應能力。

          之前,我們將 SVG 屬性設置為絕對值 (900和300),瀏覽器將它們解釋為以像素為單位的測量值 (900px和300px)。但我們也可以使用百分比。在文本編輯器中,將寬度屬性更改為相對值“ 100%”,保存文件并重新加載頁面。

          <svg width="100%" height="300" style="border:1px solid black;"></svg>

          再次調整瀏覽器大小,并注意 SVG 如何獲取可用的完整寬度并保持 300 像素的固定高度。這更好,但我們失去了原來的縱橫比。

          為了使內聯 SVG 具有響應能力,我們可以使用viewBox 屬性。在代碼編輯器中,從 SVG 容器中刪除width和屬性,并將它們替換為屬性。給它一個值。heightviewBox"0 0 900 300"

          <svg viewBox="0 0 900 300" style="border:1px solid black;"></svg>

          再次調整瀏覽器窗口的大小。你注意到了什么?SVG 容器現在可以適應任何屏幕尺寸,同時保持其縱橫比為 900:300。我們有一個響應式 SVG!

          正如您所注意到的,viewBox 屬性由四個值的列表組成。前兩個數字指定 viewBox 坐標系的原點(x 和 y)。在本書中,我們將始終使用0 0,但很高興知道這些值可用于更改 SVG 容器的哪一部分在屏幕上可見。viewBox 屬性的最后兩個數字是其寬度和高度。它們定義 SVG 的縱橫比,并確保其完美縮放以適合任何容器而不變形。

          安裝在容器內是這里的關鍵。到目前為止,我們的內聯 SVG 的容器是 HTML<body>元素,它通常會擴展以適應瀏覽器的視口。如果視口變得非常大,SVG 也會變得非常大。通常,我們希望 SVG 具有最大寬度,以便它不會大于頁面上的其余內容。為此,請將 SVG 容器包裝在寬度為 100%、最大寬度為 1200px 的 div 內。為簡單起見,我們將這些屬性設置為內聯樣式,但在實際項目中,這些屬性將來自 CSS 文件。請注意,我們還添加了值邊距“ 0 auto”,以使 SVG 在頁面上水平居中。

          <div style="width:100%; max-width:1200px; margin:0 auto;">
            <svg viewBox="0 0 900 300" style="border:1px solid black;"> ... </svg>
          </div>

          嘗試再次調整瀏覽器的大小,看看我們的 SVG 如何優雅地適應任何屏幕尺寸,同時尊重其容器的最大寬度。該策略有助于將 D3 可視化注入響應式網頁,我們將在本書中使用它。

          svg坐標系

          既然我們知道了如何使內聯 SVG 具有響應性,那么解決 SVG 形狀在 SVG 容器內的定位方式就很重要了。SVG 容器就像一張白紙,我們可以在上面繪制矢量形狀。矢量形狀是根據基本幾何原理定義的,并參考 SVG 容器的坐標系進行定位。

          SVG 坐標系與笛卡爾坐標系類似。其 2D 平面使用兩個垂直軸來確定元素的位置,稱為 x 和 y。這兩個軸源自SVG 容器的左上角,如圖 1.12 所示。意思是y軸的正方向是從上到下。記住這一點可以讓你避免一些頭痛!

          圖1.12 SVG容器的坐標系和元素的位置


          為了在 SVG 容器內定位元素,我們從左上角的原點開始向右移動。這將為我們提供元素的水平 (x) 位置。對于垂直 (y) 位置,我們從頂部開始向下移動。這些位置由每個 SVG 形狀的表示屬性定義。

          現在,我們將了解您在構建 D3 項目時經常遇到的 SVG 形狀。我們還將討論它們的主要表現屬性。這里的目標絕不是編寫 SVG 提供的所有形狀和功能的綜合指南,而是涵蓋支持您的 D3 之旅的基礎知識。

          數據可視化技巧:幾何基元

          出色的藝術家可以用矢量圖形繪制任何東西,但您可能不會因為您是一名藝術家而關注 D3。相反,您正在處理圖形并考慮更務實的目標。從這個角度來看,理解幾何基元(也稱為圖形基元)的概念至關重要。幾何基元是簡單的形狀,例如點、線、圓和矩形。這些形狀可以組合成更復雜的圖形,特別方便直觀地顯示信息。

          基元對于理解您在現實世界中看到的復雜信息可視化也很有用。樹形布局,就像我們將在第 10 章中構建的那樣,當您意識到它們只是圓形和直線時,它們就不那么令人生畏了。當您將交互式時間線視為矩形和點的集合時,它們更容易理解和創建。即使是主要以多邊形、點和線形式出現的地理數據,當您將其分解為最基本的圖形結構時,也不會那么混亂。

          線條元素可能是所有 SVG 形狀中最簡單的。它獲取兩個點的位置,設置為屬性,并在它們之間繪制一條直線。返回到該index.html文件,并在 SVG 容器內添加一個<line />元素。聲明其屬性x1和y1并分別賦予它們值 50 和 45。這意味著我們的線的起點位于(50, 45)SVG 容器的坐標系中。如果從 SVG 容器的左上角開始,向右移動 50 像素,向下移動 45 像素,您將遇到線條的起點。(140, 225)同樣,使用屬性x2和y2將線的端點設置為。

          <svg>
            <line x1="50" y1="45" x2="140" y2="225" />
          </svg>

          圖1.13 在SVG容器的坐標系中定位線元素


          如果您保存并重新加載項目,您的線條將不可見,您可能想知道發生了什么。為了使 SVG 線條在屏幕上可見,我們還需要設置其描邊屬性,該屬性控制線條的顏色。border 屬性的值與 CSS color 屬性類似。它可以是顏色名稱 ( black, blue, ...)、RGB 顏色 ( rgb(255,0,0)) 或十六進制值 ( #808080)。向您的線條添加筆劃屬性,并為其指定您選擇的顏色(我們使用黑色)。現在它應該在屏幕上可見。

          <line x1="50" y1="45" x2="140" y2="225" stroke="black" />

          如果我們想設置線條的寬度,我們可以使用描邊寬度屬性。此屬性接受絕對數字(轉換為像素)或相對值 (%)。例如,以下行的 a 為stroke-width3px。如果stroke-width未聲明該屬性,瀏覽器將應用默認值 1px。

          <line x1="50" y1="45" x2="140" y2="225" stroke="black" stroke-width="3" />

          打開瀏覽器的檢查器工具并找到 SVG 節點及其包含的行。雙擊其中一個屬性,更改其值并觀察新值如何修改線的起點或終點。花時間嘗試不同的值,以確認您了解屬性x1、y1、x2和如何y2影響線條的位置和長度。

          -20現在,為屬性賦予 值x1。你看到線的起點是如何消失的嗎?落在 SVG viewBox 之外的任何形狀或形狀部分在屏幕上都不可見。不過,該元素仍然存在于 DOM 中。我們可以訪問和操縱它。如果 SVG 中的某個元素不可見,并且您不知道為什么首先要檢查它是否在 SVG viewBox 之外!請記住,您始終可以通過使用開發人員工具檢查 DOM 來找到它。正如我們之前所做的那樣,如果將鼠標移到檢查器工具中的元素上,即使它位于 SVG viewBox 之外,它也會在視口中突出顯示。

          圖 1.14 SVG 線在 SVG 容器外部時部分隱藏



          筆記

          為了提高效率,大多數 SVG 元素只需要一個自閉合標簽(我們使用 <line /> 而不是 <line></line>)。與其他一些 HTML 標簽一樣,SVG 元素的固有結構在自閉合標簽中提供了所有必需的信息。這對于 SVG 文本元素有所不同,其中文本放置在開始標簽和結束標簽之間。

          長方形

          顧名思義,矩形元素<rect />在屏幕上繪制一個矩形形狀。該<rect />元素需要四個屬性才能可見。屬性x和y聲明矩形左上角的位置,而屬性width和height分別控制其寬度和高度。<rect />在 SVG 容器中添加以下元素及其屬性。

          <rect x="260" y="25" width="120" height="60" />

          在我們的示例中,矩形的左上角位于SVG 容器原點的260px右側和下方。25px它的寬度為120px,高度為60px。與其他位置屬性一樣,我們可以使用百分比而不是絕對數字來設置它們的值。例如,如果我們將該width屬性設置為50%,則矩形將擴展到 SVG 容器寬度的一半。

          圖 1.15 在 SVG 容器的坐標系中定位矩形并調整其大小


          您可能已經注意到我們的矩形充滿了黑色。默認情況下,瀏覽器對大多數 SVG 形狀應用黑色填充。我們可以通過設置fill屬性并為其指定任何 CSS 顏色來更改該顏色。如果我們想給矩形添加邊框,我們添加一個描邊屬性。圖 1.16 顯示了一些示例。請注意,如果不聲明屬性,則矩形周圍不會繪制邊框stroke。另外,在最后一個矩形中,屬性fill-opacity和border-opacity用于使fill和stroke半透明。與 CSS 中一樣,不透明度可以設置為絕對值 ( 0.3) 或百分比 (30%)。與填充和描邊相關的所有屬性也可以從 CSS 文件設置或修改。

          圖 1.16 應用于矩形 SVG 形狀的不同樣式屬性


          如果您希望矩形具有圓角,則只需添加rxry屬性,分別是水平和垂直角半徑。這些屬性接受絕對值(以像素為單位)和相對值(百分比)。例如,下面矩形的每個角的半徑都是 20px。將此矩形添加到您的形狀庫中。

          <rect x="260" y="100" width="120" height="60" rx="20" ry="20" />

          此時,您可能想知道 SVG 中是否有一個可以繪制正方形的元素。我們不需要一個!在 SVG 中,我們<rect />通過賦予元素相等width和height屬性來繪制帶有元素的正方形。例如,以下<rect />元素將繪制一個 60px x 60px 的正方形。也將它添加到您的形狀庫中。

          <rect x="260" y="175" width="60" height="60" />

          作為參考,我們的形狀庫中現在有三種類型的 SVG 矩形:經典矩形、圓角矩形和正方形。為了好玩,我們給了它們顏色#6ba5d7并玩弄它們stroke和fill屬性。請注意,只有筆劃在正方形上可見,因為其fill屬性值為transparent或none。您的矩形應該類似于圖 1.17 中的矩形,除非您更改了它們的屬性(我們鼓勵您這樣做)!

          <rect x="260" y="25" width="120" height="60" fill="#6ba5d7" />
          <rect x="260" y="100" width="120" height="60" rx="20" ry="20"
          ?  fill="#6ba5d7" />
          <rect x="260" y="175" width="60" height="60" fill="transparent"
          ?  stroke="#6ba5d7" />

          圖1.17 三種SVG矩形


          SVG筆畫的位置

          當您嘗試在可視化中對齊形狀時需要記住的一點是,筆劃是均勻地繪制在 SVG 形狀的內部和外部邊界上的。如下圖所示,如果矩形的width屬性為 40px,則應用 ofstroke-width會1在視覺上向矩形的左側添加 0.5px,向右側添加 0.5px(而不是像我們本能地認為的那樣,向每邊添加 1px) ),實際總寬度為 41px。如果stroke-width是2,它會在每邊添加 1px,依此類推。

          筆劃寬度對 SVG 形狀實際寬度的影響


          圓和橢圓

          圓形形狀經常用于數據可視化。它們自然地吸引眼球,并使可視化感覺更加友好和有趣。我們使用<circle />元素繪制 SVG 圓圈。其所需屬性是圓心的位置 ( cx , cy ) 及其半徑 ( r )。圓的半徑是從圓心到其邊界上任意點所繪制的直線的長度。將以下圓圈添加到您的形狀庫中。將其中心定位于(530, 80)并為其指定 50px 的半徑。

          <circle cx="530" cy="80" r="50" />

          圖 1.18 在 SVG 容器的坐標系中定位圓和橢圓并調整其大小


          您還可以使用圓形的填充和描邊屬性。為了生成圖 1.18 中的效果,我們使用了透明填充和 3px 的描邊,顏色為#81c21c。

          類似地,<ellipse />元素需要形狀中心位置的屬性 ( cx, cy)。圓形具有恒定的半徑,而橢圓形的半徑則不同,從而使其具有扁平形狀。我們通過聲明水平半徑 ( rx ) 和垂直半徑 ( ry ) 來創建這種扁平化效果。將下一個片段添加到您的圖庫中。它將在圓下方繪制一個橢圓,水平半徑為 50px,垂直半徑為 30px。

          <ellipse cx="530" cy="205" rx="50" ry="30" />

          路徑

          SVG路徑是迄今為止所有 SVG 元素中最靈活的。它們在 D3 中廣泛用于繪制幾乎所有無法用迄今為止討論的形狀基元之一(直線、矩形、圓形和橢圓形)表示的復雜形狀和曲線。

          d我們通過聲明其屬性(代表“draw”)來指示瀏覽器如何繪制路徑。該d屬性包含一個命令列表,從開始繪制路徑的位置到要使用的曲線類型,直到指定我們是否希望路徑成為閉合形狀。例如,將以下路徑元素添加到您的庫中。在此示例中,d屬性以M680 150開頭,表示“移動到坐標(680, 150)”。然后我們從當前點 (680, 150) 到字母 C 后面的第三個坐標 (755 150) 指定的端點繪制一條三次貝塞爾曲線。三次貝塞爾曲線需要控制點,即字母 C 后面、起點和終點之間的坐標((710, 80) 和 (725, 80))。這些控制點定義了曲線的陡峭程度。然后我們有字母 S,它代表“停止”。它的工作原理與字母 C 類似,只不過它通向曲線的端點。這里最后一條曲線的起點是(755 150),終點是(840, 150),控制點是(810, 220)。曲線可以由一個或兩個控制點定義。

          <path d="M680 150 C 710 80, 725 80, 755 150 S 810 220, 840 150" fill="none" 
          ?  stroke="#773b9a" stroke-width="3" />

          圖 1.19 一個簡單的 SVG 路徑及其控制點


          要深入了解 SVG 路徑,請參閱 MDN 的教程:https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths。

          手動編寫d屬性對于簡單的形狀是可行的,但隨著形狀變得復雜而變得乏味。幸運的是,D3 具有強大的形狀生成器,我們將在第 4 章中討論。

          關于路徑要記住的另一件重要的事情是瀏覽器將以黑色填充它們,除非我們將它們的fill屬性設置為noneor transparent。即使路徑未閉合(如我們的示例中所示),情況也是如此。

          文本

          <div>內聯 SVG 圖形的最大優點之一是它們可以包含可導航的文本,就像插入一個或一個元素中的任何其他 HTML 文本一樣<p>。這對于可訪問性來說是一個很大的優勢。

          由于數據可視化通常包含多個標簽,因此有必要了解如何使用<text></text>元素操作 SVG 文本。讓我們向形狀庫添加標簽,以了解 SVG 文本的基本原理。

          到目前為止討論的 SVG 形狀使用自閉合標簽 ( <line />, <rect />, <path />, ...)。使用 SVGtext元素時,我們需要使用開始標簽和結束標簽。我們將要顯示的文本放置在這兩個標簽之間。例如,讓我們在 SVG 中添加一個表示“line”的文本元素。

          <text>line</text>

          保存文件并重新加載頁面。您可能希望文本出現在 SVG 容器的左上角,但實際上卻看不到......這是為什么?默認情況下,SVG 文本的位置是參考其基線計算的,由屬性控制dominant-baseline。如果文本基線的坐標是(0, 0),您可以在圖 1.20 中看到實際文本如何最終出現在 SVG 容器之外。由于位于 SVG 容器外部的任何元素都是不可見的,因此我們看不到文本。

          圖 1.20 位于 SVG 容器外部的文本



          使用 SVG 文本時要考慮的另一點是文本的流動方式。常規 HTML 元素按照控制內容流的特定規則放置在頁面上。如果您將一堆<div></div>元素插入頁面中,它們會自然地堆疊在一起,并且它們的內容將重排,以便它永遠不會超出其容器。SVG 文本根本不流動,每個 SVG 元素必須單獨定位。一種方法是設置它們的x和y屬性。如果我們使用這些屬性將文本放置在 處(60, 260),標簽“line”將出現在形狀庫中 SVG 線的下方。

          <text x="60" y="260">line</text>

          為了練習,創建一個新的文本元素,將標簽“矩形”放置在矩形和正方形下方。

          到目前為止,我們已經使用x和y屬性來聲明文本元素的左下角。但是如果我們想設置文本中點的位置怎么辦?我們可以通過使用屬性text-anchor并為其指定值來做到這一點middle。例如,我們可以使用此屬性將圓形的文本標簽居中。

          <text x="530" y="155" text-anchor="middle">circle</text>

          圖1.21 text-anchor屬性影響SVG文本的對齊方式。它的默認值是“開始”。為了根據中間對齊文本元素,我們應用“middle”的 text-andchor 屬性。類似地,為了根據文本的結尾對齊文本,我們應用“end”的 text-andchor 屬性。


          最后為橢圓添加一個標簽,為路徑元素添加另一個標簽。默認情況下,SVG 文本為黑色。您可以使用屬性更改其顏色fill。

          分組元素

          我們將在本節中討論的最后一個 SVG 元素是組元素。group 或<g></g>元素與我們迄今為止討論的 SVG 元素不同,因為它沒有圖形表示,也不作為有界空間存在。相反,它是元素的邏輯分組。在創建由多個形狀和文本元素組成的可視化效果時,您需要廣泛使用組。

          如果我們希望正方形和“rect”標簽一起顯示并在 SVG 容器中作為一個整體移動,我們可以將它們放置在一個<g>元素內,如下例所示。請注意元素的左上角如何<rect>更改為(0, 0)。位于<text>處以(0, 85)保持其低于<rect>。

          <g>
            <rect x="0" y="0" width="60" height="60" />
            <text x="0" y="85">rect</text>
          </g>

          包含正方形及其標簽的組現在顯示在 SVG 容器的左上角。我們可以將這個組及其包含的所有元素移動到 SVG 容器中任何我們想要的位置,同時保持正方形與其標簽之間的對齊。

          在 SVG 容器中移動組是通過轉換屬性完成的。變換屬性比目前討論的屬性有點嚇人,但與 CSS 變換屬性相同。它采用一個變換(平移、旋轉、縮放等)或一堆變換作為值。為了移動一個組,我們使用translate(x, y)變換。如果我們想要將<rect>和<text>元素移回其原始位置,我們需要對元素應用向右 260 像素和向下 175 像素的平移。<g>為此,我們將其 Transform 屬性設置為transform="translate(260,175)"。

          <g transform="translate(260,175)">
            <rect x="0" y="0" width="60" height="60" />
            <text x="0" y="85">rect</text>
          </g>

          <g> 元素的另一個有用的方面是它的子元素繼承它的屬性。為了說明這一點,讓我們將<g>元素中所有剩余的文本元素分組,除了標簽“矩形”,我們已經將其與正方形分組。

          <g>
            <text x="60" y="260">line</text>
            <text x="530" y="155" style="text-anchor:middle">circle</text>
            <text x="530" y="260" style="text-anchor:middle">ellipse</text>
            <text x="730" y="260">path</text>
          </g>

          #636466如果我們對組應用填充屬性,<text>則該組內的每個元素將繼承相同的顏色。同樣,如果我們向組添加樣式屬性,例如使用font-family和font-size屬性,則組內的文本將繼承這些屬性。

          <g fill="#636466" style="font-size:16px; font-family:monospace">
            <text x="60" y="260">line</text>
            <text x="530" y="155" style="text-anchor:middle">circle</text>
            <text x="530" y="260" style="text-anchor:middle">ellipse</text>
            <text x="730" y="260">path</text>
          </g>

          最后重新加載頁面并觀察組內的標簽如何繼承組的顏色和字體,而保留在該組之外的標簽則保持其原始外觀。這種將共享屬性應用于組元素的技術非常方便,可以幫助您將 DRY(不要重復自己)編碼原則應用到您的工作中。當您需要更新這些屬性時,它也會讓您的生活更輕松。

          恭喜您完成了本書的第一個練習!您可以在清單 1.1.b 和編碼文件的末尾文件夾中找到形狀庫的完整代碼。當您構建第一個 D3 項目時,請使用此練習作為參考。

          清單 1.1.b 用于 SVG 形狀圖庫練習的完整 HTML 文件

          <!DOCTYPE html>
          <html>
          <head> [...] </head>
          <body>
            <div style="width:100%; max-width:1200px; margin:0 auto;">
              <svg viewBox="0 0 900 300" style="border:1px solid black;">
           
                <line x1="50" y1="45" x2="140" y2="225" stroke="black" />
           
                <rect x="260" y="25" width="120" height="60" fill="#6ba5d7" />
                <rect x="260" y="100" width="120" height="60" rx="20" ry="20"  
                ?  fill="#6ba5d7" /> 
                <g transform="translate(260, 175)">
                  <rect x="0" y="0" width="60" height="60" fill="transparent"
                  ?  stroke="#6ba5d7" />
                  <text x="0" y="85">rect</text>
                </g>
           
                <circle cx="530" cy="80" r="50" fill="none" stroke="#81c21c" stroke-
                ?  width="3" />
                <ellipse cx="530" cy="205" rx="50" ry="30" fill="#81c21c" />
           
                <path d="M680 150 C 710 80, 725 80, 755 150 S 810 220, 840 150" 
                ?  fill="none" stroke="#773b9a" stroke-width="3" />
           
                <g fill="#636466" style="font-size:16px; font-family:monospace">
                  <text x="60" y="260">line</text>
                  <text x="530" y="155" style="text-anchor:middle">circle</text>
                  <text x="530" y="260" style="text-anchor:middle">ellipse</text>
                  <text x="730" y="260">path</text>
                </g>
           
              </svg>
            </div>
          </body>
          </html>

          練習:創建 SVG 圖形

          現在輪到你了!創建如下圖所示的 SVG 圖形。您可以在本章代碼文件start內的文件夾中工作。02_SVG_exercise以下是一些指導原則:

          · 創建一個寬度和高度均為 400 像素的響應式 SVG 容器(當屏幕上有足夠的空間時)。

          · 繪制一個寬度和高度均為 200 像素的正方形。將其置于 SVG 容器的中心,并為其提供透明填充和 5px 黑色描邊。

          · 在 SVG 容器的中心添加一個半徑為 100px 的圓。將其填充屬性設置為 CSS 顏色名稱“plum”。

          · 繪制兩條對角黑線,筆劃為 5 像素。一個從正方形的左上角到右下角。另一個從正方形的右上角到左下角。

          · 添加文本“SVG 太棒了!” 位于正方形上方并將其置于 SVG 容器的中心。為文本指定以下樣式屬性:字體大小為 18px,字體系列為 sans-serif。

          我們鼓勵您構建此 SVG 圖形來強化本節中討論的概念。


          02_SVG_exercise / end您可以在附錄 D 的 D.1.1 節和本章代碼文件的文件夾中找到解決方案。我們鼓勵您嘗試自己完成它。

          1.2.3 畫布和webGL

          我們已經提到過,我們通常使用 SVG 元素構建 D3 項目。有時,我們可能需要從大型數據集創建復雜的可視化效果,而傳統的 SVG 方法可能會產生性能問題。請務必記住,對于數據可視化中的每個圖形細節,D3 都會將一個或多個 SVG 元素附加到 DOM。一個典型的例子是由數千個節點和鏈接組成的大型網絡可視化。這些可能會讓你的瀏覽器喘不過氣來……盡管瀏覽器可以輕松處理的對象數量隨著性能的提高而不斷增加,但普遍接受的經驗法則是,如果滿足以下條件,我們應該考慮使用畫布而不是 SVG:可視化包含 1000 多個元素。

          Canvas 是一種客戶端繪圖 API,它使用腳本(通常是 JavaScript)來創建視覺效果和動畫。它不會將 XML 元素添加到 DOM,這在從大型數據集構建可視化時可以顯著提高性能。

          Canvas 還允許您使用 WebGL API 來創建 3D 對象。盡管學習 WebGL 超出了本書的范圍,但為 Web 創建 3D 數據可視化是可能的。目前主要用于實驗項目。在第 15 章中,我們將介紹如何使用畫布構建可視化并討論其優點和缺點。

          1.2.4 CSS

          CSS 代表層疊樣式表,是一種描述 DOM 元素如何在屏幕上顯示及其外觀的語言。從頁面的整體網格布局到文本使用的字體系列,再到散點圖中圓圈的顏色,CSS 可以將普通的 HTML 文件變成令人驚嘆的網頁。在 D3 項目中,我們通常使用內聯樣式或通過外部樣式表應用 CSS 樣式。

          內聯樣式應用于具有該style屬性的元素,如以下示例所示。該style屬性可以在傳統的 HTML 或 SVG 元素上使用,D3 有一個方便的方法來設置或修改該屬性,我們將在第 2 章中討論。

          <div style="padding:10px; background:#00ced1;"> ... </div>
          <text style="font-size:16px; font-family:serif;"> ... </text>

          內聯樣式僅影響應用它們的元素。如果我們想要將相同的設計傳播到多個元素,我們需要將相同的style屬性應用于每個元素(或將所有元素包裝在一起的 SVG 組)。它當然有效,但不是最有效的方法。

          另一方面,外部 CSS 樣式表非常適合全局應用樣式。一種策略是要求 D3 將相同的類名添加到多個元素。然后,我們使用此類名稱作為外部樣式表中的選擇器,并將相同的樣式屬性應用于目標元素組,如以下示例所示。這種方法效率更高,尤其是在維護大型項目時。它還遵循關注點分離原則,即我們將由 JavaScript 控制的行為與由 CSS 監管的樣式分開。請注意,CSS 預處理器(例如 SASS 和 LESS)是此處描述的外部樣式表方法的一部分。

          在 CSS 樣式表中:

          .my-class {
            font-size: 16px;
            font-family: serif;
          }
           
          In the DOM:
          <text class="my-class"> ... </text>

          請記住,內聯樣式優先于從外部樣式表應用的樣式。在任何前端開發項目中,規劃 CSS 樣式的架構并考慮級聯順序非常重要。

          1.2.5 JavaScript

          D3 是一個 JavaScript 庫。它在 JavaScript 現有核心功能的基礎上添加了新方法。這意味著在使用 D3 時,具有一點 JavaScript 經驗會很有幫助。這也意味著,在構建 D3 項目時,您可以訪問所有現有的 JavaScript 功能。

          在本節中,我們將解釋 D3 項目中廣泛使用的兩個 JavaScript 主題:方法鏈和對象操作。

          方法鏈接

          如果您在網絡上搜索 D3 項目的示例,您會發現在同一選擇上會依次調用方法。這種技術就是我們所說的方法鏈,有助于保持代碼簡潔和可讀。

          我們可以將方法鏈視為汽車裝配線。假設我們編寫了運行這樣一條裝配線的腳本。正如您在下面的示例中看到的,我們首先聲明一個car創建新Car()對象的變量。然后我們調用函數putOnHood(),將引擎蓋放在汽車頂部,然后我們繼續調用將放置車輪、輪胎和燈的函數。每個連續的調用都會添加一個元素到Car()對象,并且,一旦執行了所有方法,汽車就有了引擎蓋、車輪、輪胎和車燈。每個方法都會將更新后的汽車對象傳遞給下一個方法,從而“鏈接”。請注意,每個調用都用點分隔,并且調用方法的順序很重要。在我們的汽車裝配線示例中,我們需要先安裝車輪,然后才能將輪胎安裝到車輪上。

          let car = new Car().putOnHood().putOnWheels().putOnTires().putOnLights();

          現在讓我們看看如何在 D3 中使用方法鏈接。想象一下,我們想要從 DOM 中獲取所有 div 并在每個 div 中添加一個段落元素。段落元素應具有類屬性my-class并包含文本“Wow”。然后,我們要在每個段落中插入一個 span 元素,并將文本“Even More Wow”以粗體顯示。如果沒有方法鏈接,我們需要將每個操作存儲到一個常量中,然后在執行下一個操作時調用該常量,如下所示。光是看著就已經很累了……

          const mySelection = d3.selectAll("div");
          const myParagraphs = mySelection.append("p");
          const myParagraphsWithAClass = myParagraphs.attr("class", "my-class");
          const myParagraphsWithText = myParagraphsWithAClass.text("Wow");
          const mySpans = myParagraphsWithText.append("span");
          const mySpansWithText = mySpans.text("Even More Wow")
          const myBoldSpans = mySpansWithText.style("font-weight", "900");

          由于方法鏈接,相同的示例變得更加簡潔。

          d3.selectAll("div").append("p").attr("class", "my-class").text("Wow")
             ? .append("span").text("Even More Wow").style("font-weight", "900");

          在 D3 中,斷行(JavaScript 會忽略這一點)以及縮進鏈接方法是很常見的。這使得代碼更容易閱讀,并且縮進可以幫助我們看到我們正在處理哪個元素。

          d3.selectAll("div")
            .append("p")
              .attr("class", "my-class")
              .text("Wow")
            .append("span")
              .text("Even More Wow")
              .style("font-weight", "900");

          不要擔心理解前面的代碼示例的作用,盡管您完全可以從不同方法的名稱中猜出它!目前,我們只希望您熟悉如何在 JavaScript 中鏈接方法。我們將在第 2 章中介紹 D3 特定的術語。

          數組和對象操作

          D3 都是關于數據的,而數據通常被構造為 JavaScript 對象。了解這些對象的構造以及如何訪問和操作它們包含的數據將為您構建可視化提供巨大幫助。

          我們首先討論簡單數組,它是元素列表。在與數據相關的項目中,數組通常是數字或字符串的有序列表。

          const arrayOfNumbers = [17, 82, 9, 500, 40];
          const arrayOfStrings = ["blue", "red", "yellow", "orange"];

          數組中的每個元素都有一個數字位置,稱為索引,數組中第一個元素的索引為 0。

          arrayOfNumbers[0]   // => 17
          arrayOfStrings[2]   // => "yellow"

          數組具有長度屬性,對于非稀疏數組,該屬性指定它們包含的元素數量。由于數組是零索引的,因此數組中最后一個元素的索引對應于數組長度減一。

          arrayOfNumbers.length;                      // => 5
          arrayOfStrings[arrayOfStrings.length - 1]   // => "orange"

          我們還可以使用方法來確定數組是否包含特定值includes()。true如果數組中的元素之一與作為參數傳遞的值完全對應,則此方法返回。否則,它返回false。

          arrayOfNumbers.includes(9)         // => true
          arrayOfStrings.includes("pink")    // => false
          arrayOfStrings.includes("ellow")   // => false

          然而,大多數數據集并不是簡單的數字或字符串列表,它們的每個數據點通常由多個屬性組成。讓我們想象一個虛構機構的員工數據庫,如表 1.1 所示。該表包含四列:每個員工的 ID、姓名和職位,以及該員工是否在 D3 工作。

          表 1.1 包含員工及其職位的小型數據集

          ID

          姓名

          位置

          與_d3一起工作

          1

          佐伊

          數據分析師

          錯誤的

          2

          詹姆士

          前端開發人員

          真的

          3

          愛麗絲

          全棧開發人員

          真的

          4

          休伯特

          設計師

          錯誤的

          數據集中的每一行或數據點都可以由 JavaScript 對象表示,如下所示row1。

          const row1 = {
                         id:"1",
                         name:"Zoe",
                         position:"Data analyst",
                         works_with_d3:false
                       };

          我們可以使用點符號輕松訪問對象中每個屬性的值。

          row1.name            // => "Zoe"
          row1.works_with_d3   // => false

          我們還可以使用括號表示法訪問這些值。如果屬性名稱包含空格等特殊字符,或者如果我們之前將屬性名稱保存在常量或變量中,那么括號表示法會很方便。

          row1["position"]                      // => "Data analyst"
           
          const myProperty = "works_with_d3";
          row1[myProperty]                      // => false

          在現實生活中,數據集通常被格式化為對象數組。例如,如果我們使用 D3 加載表 1.2 中包含的數據集(正如我們將在第 3 章中學習的那樣),我們將獲得以下對象數組,可以將其保存在名為 的常量中data。

          const data = [
           {id:"1", name:"Zoe", position:"Data analyst", works_with_d3:false},
           {id:"2", name:"James", position:"Frontend developer", works_with_d3:true},
           {id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true},
           {id:"4", name:"Hubert", position:"Designer", works_with_d3:false}
          ];

          data我們可以使用循環遍歷數組中的每個元素或數據點。更具體地說,JavaScript forEach循環非常方便且易于編寫和閱讀。迭代數據集的一個常見用例是數據整理。當我們加載外部 CSV 文件時,數字通常被格式化為字符串。讓我們以data數組為例,將屬性的值id從字符串轉換為數字。

          在下面的示例中,數組迭代器使d我們能夠訪問每個對象。使用點符號,我們id使用運算符將?每個值轉換為數字+。

          data.forEach(d => {
            d.id = +d.id;
          });

          JavaScript 提供了許多數組迭代器方法,可以幫助我們與數據交互,甚至在需要時重塑數據。假設我們想要將數據集中的每個員工定位到可視化上。創建一個僅包含員工姓名的簡單數組可能會派上用場,為此我們將使用map()方法。

          data.map(d => d.name);   // => ["Zoe", "James", "Alice", "Hubert"]

          同樣,如果我們只想隔離使用 D3 的員工,我們可以使用這些filter()方法。

          data.filter(d => d.works_with_d3);
           
          // => [
             {id:2, name:"James", position:"Frontend developer", works_with_d3:true},
             {id:4, name:"Hubert", position:"Designer", works_with_d3:true}
            ];

          最后,我們可以通過該方法找到id為3的員工find()。請注意,該find()方法在找到它要查找的值后停止迭代。我們只能在搜索單個數據點時使用此方法。

          data.find(d => d.id === 3);
           
          // => {id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true}

          本節討論的方法遠未涵蓋 JavaScript 提供的所有數組和對象操作技術。但在處理數據時,您可能會不斷回想起它們。每當您需要找到另一種方法來訪問或操作數據時,MDN Web 文檔 ( https://developer.mozilla.org/ ) 始終是包含大量示例的可靠參考。

          1.2.6 Node 和 JavaScript 框架

          JavaScript 在過去十年中發生了重大變化。現代 JavaScript 的兩個最重要的趨勢是 Node.js 的興起和 JavaScript 框架作為大多數項目標準的建立。

          對于 D3 項目,我們想了解的主要 Node 技術是 NPM,即 Node Package Manager。NPM 允許您安裝“模塊”或小型 JavaScript 代碼庫以在應用程序中使用。您不必包含<script>對單個文件的一堆標記引用,并且如果模塊已構建為不是一個整體結構,則可以減少應用程序中包含的代碼量。

          D3.js 版本 7 于 2021 年中期發布,利用了模塊導入的優勢。在本書中,您將看到以兩種方式之一使用 D3 的示例。我們要么加載整個 D3 庫,就像我們在第 2 章中所做的那樣,要么只包含我們需要的 D3 的各個部分,正如您將在后面的示例中看到的那樣。我們可以使用腳本標簽來做到這一點,但從第 2 部分開始,我們將使用 NPM 導入 D3 模塊,因為這被認為是當今的標準做法。如果您交付專業的 D3 項目,您可能需要熟悉它。

          如果您已經參與了專業的 Web 項目,那么您也很有可能正在使用 JavaScript 框架,例如 React、Angular、Vue 或 Svelte。框架為開發人員提供了使用模塊化、可重用且可測試的代碼構建 Web 項目的基礎。這些框架負責構建和更新 DOM,這也是 D3 庫所做的事情。在第 8 章中,我們將討論在 JavaScript 框架內構建 D3 可視化時避免沖突的策略。

          最后,在專業的工作環境中,您可能會將 D3 與 TypeScript 結合使用。TypeScript 是 JavaScript 的語法超集,為代碼添加了類型安全性。盡管我們不會在本書中詳細討論它,但 D3 方法的類型可以使用 NPM 包 @type/d3 ( https://www.npmjs.com/package/@types/d3 ) 進行安裝。在第 8 章中,我們將在 Angular 項目中使用此類類型。

          1.2.7 可觀察的筆記本

          如果您在網絡上搜索 D3 項目的示例,您無疑會遇到 Observable 筆記本 ( observablehq.com )。Observable 是數據科學和可視化的協作平臺,類似于 Python 項目的 Jupyter 環境。Observable 平臺由 Mike Bostock 創建,取代了之前的在線 D3 沙箱bl.ocks.org 。所有官方的 D3 示例現在都位于 Observable 上,并且 D3 社區在那里非常活躍。

          重要的是要知道 Observable 要求您學習一種處理特定于該平臺的 D3 項目的方法。此外,您不能直接將 Observable Notebook 復制粘貼到前端開發環境中(但有多種方法可以導出和重用它們)。由于本書的重點是在類似于我們如何交付 D3 項目進行生產的環境中構建 D3 可視化,因此我們不會討論 Observable 筆記本。如果您有興趣學習 Observable,您可以在observablehq.com/tutorials找到一系列優秀的教程。您將在本書中學到的大部分技術和概念都可以轉化為 Observable 筆記本。

          1.3 D3.js 表達的數據可視化標準

          數據可視化從未像今天這樣流行。豐富的地圖、圖表以及系統和數據集的復雜表示不僅存在于工作場所,而且還存在于我們的娛樂和日常生活中。隨著這種流行,使用視覺手段以及美學規則來表示數據和信息的類和子類庫不斷增長,以促進易讀性和理解性。您的受眾,無論是公眾、學者還是決策者,已經習慣了我們曾經認為極其抽象和復雜的數據趨勢表示。這使得 D3 這樣的庫不僅受到數據科學家的歡迎,而且還受到記者、藝術家、學者、IT 專業人士,甚至數據可視化愛好者的歡迎。

          如此豐富的選項似乎讓人不知所措,而且修改數據集以顯示在流圖、樹狀圖或直方圖中相對容易,這往往會促進這樣一種觀念:信息可視化更多地是關于風格而不是實質內容。幸運的是,完善的規則規定了針對不同系統的不同數據類型使用哪些圖表和方法。本書并不旨在涵蓋數據可視化中的所有最佳實踐,但我們將介紹其中的一些。盡管開發人員使用 D3 徹底改變了顏色和布局的使用,但大多數人希望創建支持實際問題的數據的可視化表示。

          當您構建第一個可視化項目時,如果有疑問,請簡化 - 通常,呈現直方圖比小提琴圖更好,或者分層網絡布局(如樹狀圖)比力導向的網絡布局更好。視覺上更復雜的數據顯示方法往往會激發更多的興奮,但也會導致觀眾關注圖形的美觀而不是數據。創建酷炫且令人瞠目結舌的可視化并沒有什么錯,但我們永遠不應該忘記任何數據可視化的主要目標都是講述一個故事。詢問周圍的人是否理解你的可視化以及他們如何解釋它是至關重要的一步。他們需要解釋嗎?他們可以從與您的項目的互動中得出哪些結論?故事被講述了嗎?

          盡管如此,為了正確部署信息可視化,您應該知道該做什么和不該做什么。您需要對您的數據和受眾有深入的了解。D3 賦予我們巨大的靈活性,但正如俗話所說,“能力越大,責任越大”。雖然知道某些圖表更適合表示特定類型的數據固然很好,但更重要的是要記住,如果不謹慎地從知情的角度構建數據可視化,則可能會攜帶錯誤信息。如果您打算設計自己的可視化,那么了解數據可視化最佳實踐是至關重要的。了解這一點的最佳方法是回顧知名設計師和信息可視化從業者的工作。盡管整個圖書館的作品都在處理這些問題,以下是我們發現的一些有用的內容,可以幫助您了解基礎知識。這些絕不是學習數據可視化的唯一文本,但它們是一個很好的起點。

          • 更好的數據可視化,喬納森施瓦比什
          • 功能藝術真實藝術圖表如何謊言,阿爾貝托·開羅
          • 數據可視化數據驅動設計手冊,安迪·柯克
          • 定量信息的視覺顯示設想信息,愛德華·塔夫特
          • 信息設計,伊莎貝爾·梅雷萊斯
          • 模式識別,克里斯蒂安·斯溫哈特
          • 可視化分析與設計,Tamara Munzner

          在閱讀有關數據可視化的內容時要記住的一件事是,文獻通常關注靜態圖表。使用 D3,您將進行交互式動態可視化。一些交互可以使可視化不僅更具可讀性,而且更有吸引力。感覺自己是在探索而不是閱讀的用戶,即使只是將鼠標懸停在事件上幾次或簡單地單擊進行縮放,也可能會發現可視化的內容比閱讀靜態等效內容更引人注目和更令人難忘。但這種增加的復雜性需要了解用戶體驗。我們將在第 7 章中更詳細地討論這一點。

          我們的第一章到此結束!盡管我們還沒有使用過 D3,但您現在已經掌握了入門所需的所有知識。當您不確定應該在可視化中使用哪個 SVG 元素或者需要提醒如何使用 JavaScript 操作數據時,請繼續返回本章。從下一章開始,我們將卷起袖子,創建 D3 可視化。

          1.4 總結

          • 當您希望在數據可視化方面擁有完全的創意和技術自由時,D3 是您的首選工具。
          • D3 應用程序的樣式和服務與傳統 Web 內容類似。
          • D3 從來不會單獨使用,而是技術和工具生態系統的一部分,我們將這些技術和工具結合起來創建豐富的 Web 界面:HTML、CSS、JavaScript、SVG、Canvas 和 React 或 Svelte 等框架。
          • 我們在構建數據可視化時最常使用的 SVG 形狀是直線、矩形、圓形、橢圓形、路徑和文本。
          • 您需要對這些形狀及其主要屬性有基本的了解才能使用 D3。使用 D3 編寫 JavaScript 時,您應該熟悉兩個主題:方法鏈和對象操作。方法鏈接是一種模式,其中在同一對象上依次調用多個方法。在 D3 中,數據集通常被構造為對象數組。JavaScript 提供了多種方法來訪問和操作這些結構中的數據。
          • 作為 D3 開發人員,深入了解數據可視化最佳實踐非常重要。多種資源可以幫助您開始學習之旅。

          眾號:

          CSS

          1. 請解釋CSS的盒模型是什么,并描述其組成部分。

          答案:CSS的盒模型是用于布局和定位元素的概念。它由內容區域、內邊距、邊框和外邊距組成,這些部分依次包裹在元素周圍。

          2. 解釋CSS中的選擇器及其優先級。

          答案:CSS選擇器用于選擇要應用樣式的HTML元素。選擇器的優先級規則是:內聯樣式 > ID選擇器 > 類選擇器、屬性選擇器、偽類選擇器 > 元素選擇器 > 通用選擇器。同時,使用!important可以提升樣式的優先級。

          3. 解釋CSS中的浮動(float)是如何工作的,并提供一個示例。

          答案:浮動(float)是CSS中用于實現元素的左浮動或右浮動,使其脫離文檔流并環繞在其周圍的元素。例如:

          .float-example {
          float: left;
          width: 200px;
          height: 200px;
          }

          4. 解釋CSS中的定位(position)屬性及其不同的取值。

          答案:定位(position)屬性用于控制元素的定位方式。常見的取值有:static(默認,按照文檔流定位)、relative(相對定位)、absolute(絕對定位)、fixed(固定定位)和sticky(粘性定位)。

          5. 解釋CSS中的層疊順序(z-index)是如何工作的。

          答案:層疊順序(z-index)用于控制元素在垂直方向上的堆疊順序。具有較高層疊順序值的元素將顯示在較低層疊順序值的元素之上。默認情況下,層疊順序值為auto。

          6. 解釋CSS中的偽類和偽元素的區別,并給出一個示例。

          答案:偽類用于向選擇器添加特殊的狀態,如:hover、:active等。偽元素用于向選擇器添加特殊的元素,如::before、::after等。例如:

          /* 偽類示例 */
          a:hover {
          color: red;
          }
          /* 偽元素示例 */
          p::before {
          content: "前綴";
          }

          7. 解釋CSS中的盒子模型的兩種模式:標準模式和怪異模式。

          答案:標準模式是按照W3C標準解析渲染頁面的模式。怪異模式是兼容舊版本瀏覽器的解析渲染頁面的模式。可以通過聲明來指定使用哪種模式。

          8. 解釋CSS中的BFC是什么,它的作用是什么?

          答案:BFC(塊級格式化上下文)是CSS中的一種渲染模式,它創建了一個獨立的渲染環境,其中的元素按照一定的規則進行布局和定位。BFC的作用包括:清除浮動、防止外邊距重疊等。

          9. 解釋CSS中的flexbox布局是什么,它的優勢是什么?

          答案:flexbox布局是一種用于創建靈活的、響應式的布局的CSS模塊。它通過flex容器和flex項目的組合來實現強大的布局能力。其優勢包括簡單易用、自適應性強、對齊和分布控制靈活等。

          10.解釋CSS中的媒體查詢是什么,它的作用是什么?

          答案:媒體查詢是CSS中的一種技術,用于根據設備的特性和屬性來應用不同的樣式。通過媒體查詢,可以根據屏幕尺寸、設備類型、分辨率等條件來優化頁面的布局和樣式。

          JavaScript

          1. 解釋JavaScript的數據類型,并舉例說明每種類型。

          答案:JavaScript有七種數據類型:字符串(String)、數字(Number)、布爾值(Boolean)、對象(Object。Array/數組 和 function/函數 也屬于對象的一種)、空值(Null)、未定義(Undefined)、Symbol(獨一無二的值,ES6 新增)、BigInt (大整數,能夠表示超過 Number 類型大小限制的整數,ES 2020新增)

          例如:

          let str = "Hello";
          let num = 10;
          let bool = true;
          let obj = { name: "John" };
          let arr = [1, 2, 3];
          let n = null;
          let undef;

          2. 解釋JavaScript中的變量提升(Hoisting)是什么。

          答案:變量提升是指在JavaScript中,變量和函數聲明會在代碼執行之前被提升到作用域的頂部。這意味著可以在聲明之前使用變量和函數。例如:

          console.log(x); // 輸出 undefined
          var x = 5;

          3. 解釋JavaScript中的閉包(Closure)是什么,并舉例說明。

          答案:閉包是指函數可以訪問并操作其詞法作用域之外的變量。它通過在函數內部創建一個內部函數,并返回該內部函數來實現。例如:

          function outer() {
          let x = 10;
          function inner() {
          console.log(x);
          }
          return inner;
          }
          let closure = outer();
          closure(); // 輸出 10

          4. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指事件從最具體的元素開始向父元素逐級觸發,直到觸發到根元素。事件捕獲是指事件從根元素開始,逐級向最具體的元素觸發。可以使用addEventListener方法的第三個參數來控制是使用事件冒泡還是事件捕獲。

          5. 解釋JavaScript中的原型繼承(Prototype Inheritance)是什么。

          答案:原型繼承是JavaScript中實現對象之間繼承關系的一種機制。每個對象都有一個原型對象,它包含了共享的屬性和方法。當訪問對象的屬性或方法時,如果對象本身沒有,則會沿著原型鏈向上查找。可以使用Object.create()方法或設置對象的__proto__屬性來實現原型繼承。

          6. 解釋JavaScript中的異步編程,并提供一個異步操作的示例。

          答案:異步編程是指在代碼執行過程中,不會阻塞后續代碼執行的一種編程方式。常見的異步操作包括網絡請求、定時器等。例如:

          console.log("開始");
          setTimeout(function() {
          console.log("異步操作");
          }, 1000);
          console.log("結束");

          7. 解釋JavaScript中的this關鍵字的作用和使用場景。

          答案:this關鍵字在JavaScript中表示當前執行上下文的對象。它的具體取值根據函數的調用方式而定。在全局作用域中,this指向全局對象(瀏覽器環境中為window對象)。在函數中,this的指向取決于函數的調用方式,可以通過call、apply、bind等方法來顯式地指定this的值。

          8. 解釋JavaScript中的事件委托(Event Delegation)是什么,并提供一個使用事件委托的示例。

          答案:事件委托是指將事件處理程序綁定到父元素上,而不是直接綁定到每個子元素上。當事件觸發時,事件會冒泡到父元素,然后通過判斷事件的目標來執行相應的處理邏輯。這樣可以減少事件處理程序的數量,提高性能。例如:

          <ul id="list">
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          </ul>
          <script>
          document.getElementById("list").addEventListener("click", function(event) {
          if (event.target.tagName === "LI") {
          console.log(event.target.textContent);
          }
          });
          </script>

          9. 解釋JavaScript中的模塊化編程,并提供一個使用模塊的示例。

          答案:模塊化編程是指將代碼劃分為獨立的模塊,每個模塊負責特定的功能,并通過導入和導出來實現模塊之間的依賴關系。ES6引入了模塊化的語法,可以使用import和export關鍵字來導入和導出模塊。例如:

          // module.js
          export function sayHello() {
          console.log("Hello!");
          }
          // main.js
          import { sayHello } from "./module.js";
          sayHello(); // 輸出 "Hello!"

          10. 解釋JavaScript中的嚴格模式(Strict Mode)。

          答案:嚴格模式是一種JavaScript的執行模式,它提供了更嚴格的語法和錯誤檢查。在嚴格模式下,一些不安全或不推薦的語法會被禁用,同時會引入一些新的特性,如變量必須先聲明才能使用、禁止使用this指向全局對象等。

          11. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指當一個事件在DOM樹中觸發時,它會從最內層的元素開始向外傳播至最外層的元素。事件捕獲是指當一個事件在DOM樹中觸發時,它會從最外層的元素開始向內傳播至最內層的元素。

          12. 什么是原型鏈(Prototype Chain)?如何利用原型鏈實現繼承?

          答案:原型鏈是JavaScript中對象之間的連接關系,每個對象都有一個指向其原型(prototype)的引用。通過原型鏈,對象可以繼承其原型對象的屬性和方法。可以使用原型鏈實現繼承,通過將一個對象的原型指向另一個對象,從而使得該對象可以訪問另一個對象的屬性和方法。

          13. 解釋JavaScript中的防抖(Debounce)和節流(Throttle)。

          答案:防抖和節流都是用于控制函數執行頻率的技術。防抖指的是在某個時間段內,只執行最后一次觸發的函數調用。節流指的是在某個時間段內,按照固定的時間間隔執行函數調用。

          14. 什么是事件循環(Event Loop)?請解釋JavaScript中的事件循環機制。

          答案:事件循環是JavaScript中處理異步操作的機制。事件循環不斷地從任務隊列中取出任務并執行,直到任務隊列為空。事件循環由主線程和任務隊列組成,主線程負責執行同步任務,異步任務會被放入任務隊列中,等待主線程空閑時被執行。

          15. 解釋JavaScript中的深拷貝和淺拷貝。

          答案:深拷貝是指創建一個新對象,將原始對象的所有屬性和嵌套對象的屬性都復制到新對象中。淺拷貝是指創建一個新對象,將原始對象的屬性復制到新對象中,但嵌套對象的引用仍然是共享的。

          16. 什么是異步編程?請列舉幾種處理異步操作的方法。

          答案:異步編程是一種處理可能耗時的操作而不阻塞主線程的編程方式。常見的處理異步操作的方法有回調函數、Promise、async/await和事件監聽等。

          17. 解釋JavaScript中的Hoisting(變量提升)。

          答案:變量提升是指在JavaScript中,變量和函數的聲明會被提升到當前作用域的頂部。這意味著可以在聲明之前使用變量和函數,但它們的賦值或定義仍然在原來的位置。

          18. 什么是柯里化(Currying)?請給出一個柯里化的示例。

          答案:柯里化是一種將接受多個參數的函數轉換為接受一個參數并返回一個新函數的過程。示例:

          function add(a) {
          return function(b) {
          return a + b;
          }
          }
          var add5 = add(5);
          console.log(add5(3)); // 輸出:8

          TypeScript

          1. 解釋TypeScript和JavaScript之間的關系。

          答案:TypeScript是JavaScript的超集,它添加了靜態類型和其他一些特性。TypeScript代碼可以編譯成JavaScript代碼,因此可以在任何支持JavaScript的環境中運行。

          2. TypeScript中的類型注解是什么?如何使用類型注解?

          答案:類型注解是指在變量、函數參數、函數返回值等地方顯式地聲明類型信息。可以使用冒號(:)后跟類型來添加類型注解。例如:

          let num: number = 10;
          function add(a: number, b: number): number {
          return a + b;
          }

          3. TypeScript中的接口是什么?如何定義和使用接口?

          答案:接口是一種用于定義對象的結構和類型的語法。可以使用interface關鍵字來定義接口。例如:

          interface Person {
          name: string;
          age: number;
          }
          function greet(person: Person) {
          console.log(`Hello, ${person.name}!`);
          }
          let john: Person = { name: "John", age: 25 };
          greet(john); // 輸出 "Hello, John!"

          4. TypeScript中的類是什么?如何定義和使用類?

          答案:類是一種用于創建對象的藍圖,它包含屬性和方法。可以使用class關鍵字來定義類。例如:

          class Person {
          name: string;
          age: number;
          constructor(name: string, age: number) {
          this.name = name;
          this.age = age;
          }
          greet() {
          console.log(`Hello, ${this.name}!`);
          }
          }
          let john = new Person("John", 25);
          john.greet(); // 輸出 "Hello, John!"

          5. TypeScript中的泛型是什么?如何使用泛型?

          答案:泛型是一種用于創建可重用代碼的工具,它允許在定義函數、類或接口時使用占位符類型。可以使用尖括號(<>)來指定泛型類型。例如:

          function identity<T>(value: T): T {
          return value;
          }
          let result = identity<string>("Hello");
          console.log(result); // 輸出 "Hello"

          6. TypeScript中的枚舉是什么?如何定義和使用枚舉?

          答案:枚舉是一種用于定義命名常量集合的語法。可以使用enum關鍵字來定義枚舉。例如:

          enum Color {
          Red,
          Green,
          Blue,
          }
          let color: Color = Color.Green;
          console.log(color); // 輸出 1

          7. TypeScript中的模塊是什么?如何導出和導入模塊?

          答案:模塊是用于組織和封裝代碼的單元。可以使用export關鍵字將模塊中的變量、函數、類等導出,以便其他模塊可以使用。可以使用import關鍵字來導入其他模塊的導出。例如:

          // module.ts
          export function greet(name: string) {
          console.log(`Hello, ${name}!`);
          }
          // main.ts
          import { greet } from "./module";
          greet("John"); // 輸出 "Hello, John!"

          8. TypeScript中的類型推斷是什么?如何使用類型推斷?

          答案:類型推斷是指TypeScript根據上下文自動推斷變量的類型,而無需顯式地添加類型注解。例如:

          let num = 10; // 推斷為 number 類型
          let str = "Hello"; // 推斷為 string 類型

          9. TypeScript中的命名空間是什么?如何定義和使用命名空間?

          答案:命名空間是一種用于組織和封裝代碼的機制,它避免了全局命名沖突。可以使用namespace關鍵字來定義命名空間。例如:

          namespace MyNamespace {
          export function greet(name: string) {
          console.log(`Hello, ${name}!`);
          }
          }
          MyNamespace.greet("John"); // 輸出 "Hello, John!"

          10. TypeScript中的類型別名是什么?如何定義和使用類型別名?

          答案:類型別名是給類型起一個別名,以便在代碼中更方便地引用。可以使用type關鍵字來定義類型別名。例如:

          type Point = { x: number; y: number };
          function printPoint(point: Point) {
          console.log(`(${point.x}, ${point.y})`);
          }
          let p: Point = { x: 1, y: 2 };
          printPoint(p); // 輸出 "(1, 2)"

          VUE2

          1. Vue.js是什么?它有哪些特點?

          答案:Vue.js是一個用于構建用戶界面的JavaScript框架。它具有以下特點:

          響應式數據綁定:通過使用Vue的數據綁定語法,可以實現數據的自動更新。 組件化開發:Vue允許將頁面劃分為獨立的組件,提高了代碼的可維護性和復用性。 虛擬DOM:Vue使用虛擬DOM來跟蹤頁面上的變化,并高效地更新實際的DOM。 指令系統:Vue提供了豐富的內置指令,用于處理常見的DOM操作和邏輯控制。 生態系統:Vue擁有龐大的生態系統,包括插件、工具和第三方庫,可以滿足各種開發需求。

          2. Vue中的雙向數據綁定是如何實現的?

          答案:Vue中的雙向數據綁定是通過v-model指令實現的。v-model可以在表單元素(如、、)上創建雙向數據綁定。當用戶輸入改變表單元素的值時,數據模型會自動更新;反之,當數據模型的值改變時,表單元素也會自動更新。

          3. Vue中的生命周期鉤子有哪些?它們的執行順序是怎樣的?

          答案:Vue中的生命周期鉤子包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy和destroyed。它們的執行順序如下:

          beforeCreate created beforeMount mounted beforeUpdate updated beforeDestroy destroyed

          4. Vue中的計算屬性和監聽器有什么區別?

          答案:計算屬性是基于依賴的屬性,它根據其依賴的數據動態計算得出值。計算屬性具有緩存機制,只有在依賴的數據發生變化時才會重新計算。監聽器是用于監聽數據的變化并執行相應的操作。當數據發生變化時,監聽器會立即執行指定的回調函數。

          5. Vue中的組件通信有哪些方式?

          答案:Vue中的組件通信方式包括:

          父子組件通信:通過props向子組件傳遞數據,子組件通過事件向父組件發送消息。 子父組件通信:子組件通過$emit觸發事件,父組件通過監聽事件并響應。 兄弟組件通信:通過共享的父組件來傳遞數據或通過事件總線(Event Bus)進行通信。 跨級組件通信:通過provide和inject來在祖先組件中提供數據,然后在后代組件中使用。

          6. Vue中的路由是如何實現的?

          答案:Vue中的路由是通過Vue Router實現的。Vue Router是Vue.js官方提供的路由管理器,它允許開發者在Vue應用中實現單頁面應用(SPA)。Vue Router通過配置路由映射關系,將URL路徑與組件進行關聯,并提供導航功能,使用戶可以在不刷新頁面的情況下切換視圖。

          7. Vue中的指令有哪些?舉例說明它們的用法。

          答案:Vue中常用的指令包括:

          v-if:根據表達式的值條件性地渲染元素。 v-for:根據數組或對象的數據進行循環渲染。 v-bind:用于動態綁定屬性或響應式地更新屬性。 v-on:用于監聽DOM事件并執行相應的方法。 v-model:用于在表單元素上實現雙向數據綁定。 例如:

          <div v-if="show">顯示內容</div>
          <ul>
          <li v-for="item in items" :key="item.id">{{ item.name }}</li>
          </ul>
          <img v-bind:src="imageUrl">
          <button v-on:click="handleClick">點擊按鈕</button>
          <input v-model="message">

          8. Vue中的watch和computed有什么區別?

          答案:watch和computed都可以用于監聽數據的變化,但它們的用法和實現方式略有不同。watch用于監聽指定的數據變化,并在數據變化時執行相應的操作。computed用于根據依賴的數據動態計算得出一個新的值,并將該值緩存起來,只有在依賴的數據發生變化時才會重新計算。

          9. Vue中的mixin是什么?它有什么作用?

          答案:Mixin是一種用于在多個組件之間共享代碼的方式。Mixin可以包含組件選項(如數據、方法、生命周期鉤子等),并將其合并到使用Mixin的組件中。這樣可以實現代碼的復用和組件的擴展,減少重復編寫相似代碼的工作。

          10. Vue中的keep-alive是什么?它有什么作用?

          答案:是Vue中的一個內置組件,用于緩存動態組件。當組件包裹在中時,組件的狀態將被保留,包括它的實例、狀態和DOM結構。這樣可以避免在組件切換時重復創建和銷毀組件,提高性能和用戶體驗。

          11. 請解釋Vue.js中的依賴注入(Dependency Injection)是什么?它在Vue中的應用場景是什么?

          答案:依賴注入是一種設計模式,用于將依賴關系從一個組件傳遞到另一個組件。在Vue中,依賴注入通過provide和inject選項實現。父組件通過provide提供數據,然后子組件通過inject注入這些數據。它在跨多個層級的組件通信中非常有用。

          12. Vue.js中的渲染函數(Render Function)是什么?它與模板(Template)有什么區別?

          答案:渲染函數是一種用JavaScript代碼編寫組件的方式,它可以動態地生成虛擬DOM。與模板相比,渲染函數提供了更大的靈活性和控制力,可以處理更復雜的邏輯和動態渲染需求。

          13. Vue.js中的插槽(Slot)是什么?請提供一個具有命名插槽和作用域插槽的示例。

          答案:插槽是一種用于在組件中擴展內容的機制。命名插槽允許父組件向子組件插入具有特定名稱的內容,而作用域插槽允許子組件將數據傳遞給父組件。示例:

          <!-- 父組件 -->
          <template>
          <div>
          <slot name="header"></slot>
          <slot :data="data"></slot>
          </div>
          </template>
          <!-- 子組件 -->
          <template>
          <div>
          <slot name="header">默認標題</slot>
          <slot :data="computedData">{{ computedData }}</slot>
          </div>
          </template>

          14. Vue.js中的動畫系統是如何工作的?請提供一個簡單的動畫示例。

          答案:Vue.js的動畫系統通過CSS過渡和動畫類實現。通過在元素上添加過渡類或動畫類,可以觸發相應的過渡效果或動畫效果。示例:

          <transition name="fade">
          <div v-if="show">顯示內容</div>
          </transition>
          <!-- CSS樣式 -->
          <style>
          .fade-enter-active, .fade-leave-active {
          transition: opacity 0.5s;
          }
          .fade-enter, .fade-leave-to {
          opacity: 0;
          }
          </style>

          15. Vue.js中的錯誤處理機制是什么?如何捕獲和處理Vue組件中的錯誤?

          答案:Vue.js提供了全局的錯誤處理機制和組件級別的錯誤處理機制。全局錯誤處理可以通過errorCaptured鉤子函數捕獲和處理錯誤。組件級別的錯誤處理可以通過errorCaptured鉤子函數或errorHandler選項捕獲和處理錯誤。

          16. Vue.js中的服務端渲染(SSR)是什么?它有哪些優勢和限制?

          答案:服務端渲染是指在服務器上生成HTML內容并將其發送到瀏覽器進行渲染的過程。Vue.js可以進行服務端渲染,提供更好的首次加載性能和SEO優化。然而,服務端渲染也帶來了一些限制,如增加了服務器負載和開發復雜性。

          17. Vue.js中的響應式數組有哪些限制?如何解決這些限制?

          答案:Vue.js的響應式系統對于數組的變異方法(如push、pop、splice等)是無法追蹤的。為了解決這個限制,Vue提供了一些特殊的方法,如Vue.set、vm.$set和Array.prototype.splice。這些方法可以用于更新數組并保持響應式。

          18. Vue.js中的性能優化有哪些常見的技巧?

          答案:常見的Vue.js性能優化技巧包括:

          使用v-if和v-for時注意避免不必要的渲染。 合理使用computed屬性和watch監聽器。 使用keep-alive組件緩存組件狀態。 使用異步組件進行按需加載。 避免在模板中使用復雜的表達式。 使用key屬性管理組件和元素的復用。 合理使用懶加載和分割代碼。

          19. Vue.js中的路由導航守衛有哪些?它們的執行順序是怎樣的?

          答案:Vue.js中的路由導航守衛包括全局前置守衛、全局解析守衛、全局后置守衛、路由獨享守衛和組件內守衛。它們的執行順序如下:

          全局前置守衛(beforeEach) 路由獨享守衛(beforeEnter) 解析守衛(beforeResolve) 組件內守衛(beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave) 全局后置守衛(afterEach)

          20. Vue.js中的單元測試是如何進行的?請提供一個簡單的單元測試示例。

          答案:Vue.js的單元測試可以使用工具如Jest或Mocha進行。示例:

          // 組件代碼
          // MyComponent.vue
          <template>
          <div class="my-component">
          <span>{{ message }}</span>
          <button @click="increment">增加</button>
          </div>
          </template>
          <script>
          export default {
          data() {
          return {
          message: 'Hello',
          count: 0
          }
          },
          methods: {
          increment() {
          this.count++
          }
          }
          }
          </script>
          // 單元測試代碼
          // MyComponent.spec.js
          import { shallowMount } from '@vue/test-utils'
          import MyComponent from './MyComponent.vue'
          describe('MyComponent', () => {
          it('renders message correctly', () => {
          const wrapper = shallowMount(MyComponent)
          expect(wrapper.find('span').text()).toBe('Hello')
          })
          it('increments count when button is clicked', () => {
          const wrapper = shallowMount(MyComponent)
          wrapper.find('button').trigger('click')
          expect(wrapper.vm.count).toBe(1)
          })
          })

          VUE3

          1. Vue.js 3中的Composition API是什么?它與Options API有什么區別?

          答案:Composition API是Vue.js 3中引入的一種新的組織組件邏輯的方式。它允許開發者通過函數的方式組織和重用邏輯,而不是通過選項對象。相比之下,Options API是Vue.js 2中常用的組織組件邏輯的方式,通過選項對象中的屬性來定義組件的數據、方法等。

          2. Vue.js 3中的Teleport是什么?請給出一個Teleport的示例。

          答案:Teleport是Vue.js 3中引入的一種機制,用于將組件的內容渲染到DOM樹中的任意位置。示例:

          <template>
          <div>
          <button @click="showModal = true">打開模態框</button>
          <teleport to="body">
          <modal v-if="showModal" @close="showModal = false">模態框內容</modal>
          </teleport>
          </div>
          </template>

          3. Vue.js 3中的響應式系統是如何工作的?它與Vue.js 2中的響應式系統有什么區別?

          答案:Vue.js 3中的響應式系統使用了Proxy對象來實現。與Vue.js 2中的響應式系統相比,Vue.js 3的響應式系統具有更好的性能和更細粒度的追蹤,能夠更準確地檢測到數據的變化,并且支持嵌套的響應式數據。

          4. Vue.js 3中的Suspense是什么?它的作用是什么?

          答案:Suspense是Vue.js 3中引入的一種機制,用于處理異步組件的加載狀態。它可以在異步組件加載完成之前顯示一個占位符,并在加載完成后渲染異步組件的內容。這樣可以更好地處理異步組件的加載過程,提供更好的用戶體驗。

          5. Vue.js 3中的provide和inject有什么作用?請給出一個provide和inject的示例。

          答案:provide和inject用于實現組件之間的依賴注入。通過在父組件中使用provide提供數據,然后在子組件中使用inject注入這些數據。示例:

          // 父組件
          const Parent = {
          provide: {
          message: 'Hello'
          },
          // ...
          }
          // 子組件
          const Child = {
          inject: ['message'],
          created() {
          console.log(this.message); // 輸出:Hello
          },
          // ...
          }

          6. Vue.js 3中的動畫系統有哪些改進?請列舉幾個改進之處。

          答案:Vue.js 3中的動畫系統相比Vue.js 2有以下改進之處:

          更好的性能:Vue.js 3的動畫系統使用了更高效的動畫引擎,提供了更好的性能。 更簡潔的語法:Vue.js 3的動畫系統使用了更簡潔的語法,使得動畫的定義和使用更加直觀和方便。 支持更多的動畫特性:Vue.js 3的動畫系統支持更多的動畫特性,如交互式動畫和更復雜的動畫效果。 Vue.js 3中的靜態提升(Static Tree Hoisting)是什么?它有什么優勢? 答案:靜態提升是Vue.js 3中的一項優化技術,通過在編譯階段將靜態節點提升為常量,從而減少了運行時的開銷。這項優化技術可以提高組件的渲染性能,并減少生成的代碼體積。

          7. Vue.js 3中的Fragment是什么?它的作用是什么?

          答案:Fragment是Vue.js 3中引入的一種機制,用于在組件中返回多個根節點。在Vue.js 2中,組件的模板只能有一個 Vue.js 3中的Composition API中的ref和reactive有什么區別?什么時候使用哪個? 答案:ref用于創建一個響應式的基本數據類型,而reactive用于創建一個響應式的對象。當需要創建一個簡單的響應式數據時,可以使用ref,當需要創建一個包含多個屬性的響應式對象時,可以使用reactive。

          8. Vue.js 3中的watchEffect和watch有什么區別?什么時候使用哪個?

          答案:watchEffect用于監聽響應式數據的變化,并在回調函數中執行相應的操作。它會自動追蹤依賴,并在依賴變化時重新運行回調函數。watch用于監聽指定的響應式數據,并在其變化時執行相應的操作。它可以精確地指定要監聽的數據,并提供更多的配置選項。一般來說,如果只需要監聽一個響應式數據的變化并執行相應操作,可以使用watchEffect;如果需要更細粒度的控制,可以使用watch。

          9. Vue.js 3中的v-model指令在使用時有哪些注意事項?

          答案:在使用v-model指令時,有以下注意事項:

          v-model指令必須與一個表單元素一起使用,如、、等。 當使用自定義組件時,組件內部必須實現modelValue屬性和update:modelValue事件,以支持v-model的雙向綁定。 可以使用.lazy修飾符實現在輸入框失去焦點時更新數據。 可以使用.trim修飾符自動去除輸入框內容的首尾空格。 可以使用.number修飾符將輸入框的值轉換為數字類型。

          10. Vue.js 3中的provide和inject是否支持響應式數據?

          答案:默認情況下,provide和inject不支持響應式數據。如果需要在provide中提供一個響應式數據,可以使用ref或reactive將數據包裝起來。然后在inject中使用toRefs或toRef將數據解構出來,以獲取響應式的引用。

          11. Vue.js 3中的nextTick方法有什么作用?在什么情況下使用它?

          答案:nextTick方法用于在下次DOM更新循環結束之后執行回調函數。它可以用來確保在更新DOM后執行某些操作,如操作更新后的DOM元素或獲取更新后的計算屬性的值。通常在需要等待DOM更新完成后進行操作的情況下使用nextTick。

          12. Vue.js 3中的和組件有什么區別?

          答案:組件用于將組件的內容渲染到DOM樹中的任意位置,而組件用于在組件進入或離開DOM樹時應用過渡效果。主要用于組件的位置移動,而主要用于組件的顯示和隱藏過渡。

          13. Vue.js 3中的v-for指令中的key屬性有什么作用?為什么要使用它?

          答案:v-for指令中的key屬性用于給每個迭代項設置一個唯一的標識符。它的作用是幫助Vue.js跟蹤每個節點的身份,以便在數據發生變化時高效地更新DOM。使用key屬性可以避免出現錯誤的節點更新或重新排序的問題。

          React

          1. 什么是React?它的核心概念是什么?

          答案:React是一個用于構建用戶界面的JavaScript庫。它的核心概念是組件化和聲明式編程。React將用戶界面拆分為獨立的可重用組件,并使用聲明式語法描述組件的狀態和UI的關系,使得構建復雜的UI變得簡單和可維護。

          2. 什么是JSX?它與HTML有什么區別?

          答案:JSX是一種JavaScript的語法擴展,用于在React中描述UI的結構。它類似于HTML,但有一些區別:

          3. 什么是React組件?它們有哪兩種類型?

          答案:React組件是構建用戶界面的獨立單元。React組件有兩種類型:

          函數組件:使用函數來定義組件,接收props作為參數,并返回一個React元素。 類組件:使用ES6類來定義組件,繼承自React.Component類,通過render方法返回一個React元素。

          4. 什么是狀態(state)和屬性(props)?它們之間有什么區別?

          答案:狀態(state)是組件自身管理的數據,可以通過setState方法來更新。屬性(props)是從父組件傳遞給子組件的數據,子組件無法直接修改props,只能通過父組件的更新來改變props。

          區別:

          狀態(state)是組件內部的數據,可以在組件中自由修改和管理。 屬性(props)是從父組件傳遞給子組件的數據,子組件無法直接修改,只能接收和使用。

          5. 什么是React生命周期方法?列舉一些常用的生命周期方法。

          答案:React生命周期方法是在組件不同階段執行的特定方法。以下是一些常用的React生命周期方法:

          componentDidMount:組件掛載后立即調用。 componentDidUpdate:組件更新后調用。 componentWillUnmount:組件卸載前調用。 shouldComponentUpdate:決定組件是否需要重新渲染。 getDerivedStateFromProps:根據props的變化來更新狀態。

          6. 什么是React Hooks?它們的作用是什么?

          答案:React Hooks是React 16.8版本引入的一種特性,用于在函數組件中使用狀態和其他React特性。Hooks提供了一種無需編寫類組件的方式來管理狀態和處理副作用,使得函數組件具有類組件的能力。

          7. 什么是React Router?它的作用是什么?

          答案:React Router是React中用于處理路由的庫。它提供了一種在單頁面應用中實現導航和路由功能的方式。React Router可以幫助開發者實現頁面之間的切換、URL參數的傳遞、嵌套路由等功能。

          8. 什么是React Context?它的作用是什么?

          答案:React Context是一種用于在組件樹中共享數據的機制。它可以避免通過props一層層傳遞數據,使得跨組件的數據共享變得更加簡單和高效。React Context提供了一個Provider和Consumer組件,用于提供和消費共享的數據。

          9. 什么是React的協調(Reconciliation)過程?它是如何工作的?

          答案:React的協調過程是指React在進行組件更新時,通過比較新舊虛擬DOM樹的差異,僅對需要更新的部分進行實際的DOM操作。協調過程的工作方式如下:

          React會逐層比較新舊虛擬DOM樹的節點,并找出差異。 對于每個差異,React會生成相應的DOM操作指令,如插入、更新或刪除節點。 React會將所有的DOM操作指令批量執行,以減少對真實DOM的操作次數。

          10. 什么是React的事件合成(SyntheticEvent)?它的作用是什么?

          答案:React的事件合成是一種在React中處理事件的機制。它是React為了提高性能和跨瀏覽器兼容性而實現的一種事件系統。事件合成的作用包括:

          提供了一種統一的方式來處理事件,無需考慮瀏覽器兼容性。 可以通過事件委托的方式將事件處理程序綁定到父組件,提高性能。 可以訪問原生事件對象的屬性和方法。

          11. 什么是React的Fiber架構?它解決了什么問題?

          答案:React的Fiber架構是React 16版本引入的一種新的協調算法和架構。它旨在解決長時間渲染阻塞主線程的問題,提高應用的性能和用戶體驗。Fiber架構通過將渲染過程分解為多個小任務,并使用優先級調度算法來動態分配時間片,使得React可以在每個幀中執行一部分任務,從而實現平滑的用戶界面和更好的響應性能。

          12. 什么是React的錯誤邊界(Error Boundary)?它的作用是什么?

          答案:React的錯誤邊界是一種用于處理組件錯誤的機制。它允許組件捕獲并處理其子組件中發生的JavaScript錯誤,以避免整個應用崩潰。錯誤邊界的作用包括:

          捕獲并處理組件樹中的錯誤,防止錯誤導致整個應用崩潰。 提供一種優雅的方式來顯示錯誤信息或備用UI。 可以用于記錄錯誤和發送錯誤報告。

          網絡

          1. 什么是HTTP?它是如何工作的?

          答案:HTTP(Hypertext Transfer Protocol)是一種用于在Web上傳輸數據的協議。它使用客戶端-服務器模型,客戶端發送HTTP請求到服務器,服務器返回HTTP響應。HTTP的工作流程如下:

          客戶端發送HTTP請求到指定的URL。 服務器接收請求并處理,然后返回HTTP響應。 客戶端接收響應并解析,從中獲取所需的數據。

          2. 什么是HTTPS?與HTTP有什么區別?

          答案:HTTPS(Hypertext Transfer Protocol Secure)是HTTP的安全版本,通過使用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)協議對通信進行加密和身份驗證。與HTTP相比,HTTPS具有以下區別:

          數據在傳輸過程中通過加密進行保護,提供更高的安全性。 使用數字證書對服務器進行身份驗證,防止中間人攻擊。 使用默認端口443。

          3. 什么是跨域請求?它是如何解決的?

          答案:跨域請求是指在瀏覽器中向不同域名、端口或協議發送的請求。由于瀏覽器的同源策略(Same-Origin Policy)限制,跨域請求會受到限制。為了解決跨域問題,可以使用以下方法:

          JSONP(JSON with Padding):通過動態創建

          4. 什么是緩存?在前端中如何使用緩存來提高性能?

          答案:緩存是將數據或資源存儲在臨時存儲中,以便在后續請求中重復使用,從而提高性能和減少網絡流量。在前端中,可以使用以下方式來利用緩存:

          HTTP緩存:通過設置適當的緩存頭(如Cache-Control和Expires)來指示瀏覽器緩存響應。 資源緩存:使用文件指紋或版本號來重命名靜態資源文件,以便在文件內容變化時使瀏覽器重新下載。 數據緩存:使用內存緩存、瀏覽器本地存儲(如localStorage)或服務端緩存(如Redis)來存儲數據,避免重復請求。

          5. 什么是CDN?它的作用是什么?

          答案:CDN(Content Delivery Network)是一種分布式網絡架構,用于在全球各地提供高性能、低延遲的內容傳輸服務。CDN的作用包括:

          將靜態資源(如圖片、樣式表、腳本等)緩存到離用戶更近的服務器上,提供更快的加載速度。 分發網絡流量,減輕源服務器的負載壓力。 提供內容壓縮、數據壓縮和緩存等優化技術,提高用戶體驗。

          6. 什么是網頁加載性能優化?可以采取哪些措施來改善網頁加載性能?

          答案:網頁加載性能優化是指通過各種技術手段來減少網頁加載時間并提高用戶體驗。可以采取以下措施來改善網頁加載性能:

          壓縮和合并資源文件(如CSS和JavaScript),減少文件大小和請求數量。 使用圖像壓縮和適當的格式選擇來減小圖像文件大小。 使用瀏覽器緩存和HTTP緩存頭來緩存靜態資源。 使用懶加載延遲加載非關鍵資源,提高初始加載速度。 使用CDN(內容分發網絡)來分發靜態資源,減少網絡延遲。 優化關鍵渲染路徑,盡早呈現頁面內容。

          7. 什么是網頁性能監測和分析?可以使用哪些工具來監測和分析網頁性能?

          答案:網頁性能監測和分析是指通過測量和收集有關網頁加載和交互性能的數據,以便識別性能瓶頸并進行優化。可以使用以下工具來監測和分析網頁性能:

          Web性能API:瀏覽器提供的JavaScript API,可通過performance對象來收集性能數據。 Lighthouse:一種開源工具,可提供關于網頁性能、可訪問性和最佳實踐的綜合報告。 WebPagetest:在線工具,可測量網頁加載時間并提供詳細的性能分析報告。 Chrome開發者工具:瀏覽器內置的開發者工具,提供了性能分析、網絡監控和頁面審查等功能。

          8. 什么是漸進式圖像加載(Progressive Image Loading)?它如何改善網頁加載性能?

          答案:漸進式圖像加載是一種技術,通過逐步加載圖像的模糊或低分辨率版本,然后逐漸提高圖像的清晰度,以改善網頁加載性能和用戶體驗。漸進式圖像加載的好處包括:

          用戶可以更快地看到頁面內容,提高感知速度。 逐步加載圖像可以減少網頁整體的加載時間。 漸進式圖像加載可以提供平滑的過渡效果,避免頁面內容突然閃爍或變化。

          9. 什么是前端資源優先級(Resource Prioritization)?如何設置資源的優先級?

          答案:前端資源優先級是指為不同類型的資源分配加載優先級,以優化網頁加載性能。可以使用以下方法設置資源的優先級:

          使用標簽來指定資源的預加載,以確保關鍵資源盡早加載。 使用標簽來指定可能在未來頁面中使用的資源,以提前加載。 使用標簽來指定要預解析的域名,以減少DNS查找時間。 使用標簽來指定要預連接的域名,以減少建立連接的時間。

          瀏覽器

          1.解釋一下瀏覽器的工作原理。

          答案:瀏覽器的工作原理包括以下幾個關鍵步驟:

          解析:瀏覽器將接收到的HTML、CSS和JavaScript代碼解析成DOM樹、CSSOM樹和JavaScript引擎可執行的代碼。 渲染:瀏覽器使用DOM樹和CSSOM樹構建渲染樹,然后根據渲染樹進行布局(計算元素的位置和大小)和繪制(將元素繪制到屏幕上)。 布局和繪制:瀏覽器根據渲染樹的變化進行布局和繪制,然后將最終的頁面呈現給用戶。 JavaScript引擎執行:瀏覽器的JavaScript引擎解釋和執行JavaScript代碼,并根據需要更新渲染樹和重新渲染頁面。

          2. 什么是重繪(Repaint)和重排(Reflow)?它們之間有什么區別?

          答案:重繪是指當元素的外觀(如顏色、背景等)發生改變,但布局不受影響時的更新過程。重繪不會導致元素的位置或大小發生變化。

          重排是指當元素的布局屬性(如寬度、高度、位置等)發生改變時的更新過程。重排會導致瀏覽器重新計算渲染樹和重新繪制頁面的一部分或全部。

          區別在于重繪只涉及外觀的更改,而重排涉及布局的更改。重排比重繪更消耗性能,因為它需要重新計算布局和繪制整個頁面。

          3. 什么是事件冒泡和事件捕獲?它們之間有什么區別?

          答案:事件冒泡和事件捕獲是指瀏覽器處理事件時的兩種不同的傳播方式。

          事件冒泡是指事件從最內層的元素開始觸發,然后逐級向上傳播到父元素,直到傳播到最外層的元素。

          事件捕獲是指事件從最外層的元素開始觸發,然后逐級向下傳播到最內層的元素。

          區別在于傳播方向的不同。事件冒泡是從內向外傳播,而事件捕獲是從外向內傳播。

          4. 解釋一下同步和異步的JavaScript代碼執行方式。

          答案:同步代碼是按照順序執行的代碼,每個任務必須等待前一個任務完成后才能執行。同步代碼會阻塞后續代碼的執行,直到當前任務完成。

          異步代碼是不按照順序執行的代碼,它會在后臺執行,不會阻塞后續代碼的執行。異步代碼通常使用回調函數、Promise、async/await等方式來處理異步操作的結果。

          通過異步執行,可以避免阻塞主線程,提高頁面的響應性能。

          5. 什么是事件循環(Event Loop)?它在JavaScript中的作用是什么?

          答案:事件循環是JavaScript中處理異步代碼執行的機制。它負責管理調度和執行異步任務,并將它們添加到執行隊列中。

          在JavaScript中,事件循環的作用是確保異步任務按照正確的順序執行,并且不會阻塞主線程。它通過不斷地從執行隊列中取出任務并執行,以實現非阻塞的異步操作。

          6. 解釋一下瀏覽器的垃圾回收機制是如何工作的。

          答案:瀏覽器的垃圾回收機制是一種自動管理內存的機制,用于檢測和回收不再使用的對象,以釋放內存資源。

          垃圾回收機制通過標記-清除算法實現。它的工作原理如下:

          標記階段:垃圾回收器會從根對象(如全局對象)開始,遞歸遍歷所有對象,并標記仍然可訪問的對象。 清除階段:垃圾回收器會掃描堆內存,清除未被標記的對象,并回收它們所占用的內存空間。 垃圾回收機制的目標是識別和回收不再使用的對象,以避免內存泄漏和提高內存利用率。

          7. 解釋一下瀏覽器的同源策略(Same-Origin Policy)及其限制。

          答案:同源策略是瀏覽器的一項安全機制,用于限制來自不同源的網頁之間的交互。同源是指協議、域名和端口號完全相同。

          同源策略的限制包括:

          腳本訪問限制:不同源的腳本無法直接訪問彼此的數據和操作。 DOM訪問限制:不同源的網頁無法通過JavaScript訪問彼此的DOM元素。 Cookie限制:不同源的網頁無法讀取或修改彼此的Cookie。 AJAX請求限制:不同源的網頁無法通過AJAX請求訪問彼此的數據。 同源策略的存在可以防止惡意網站獲取用戶的敏感信息或進行惡意操作。

          8. 什么是Web Workers?它們在瀏覽器中的作用是什么?

          答案:Web Workers是一種瀏覽器提供的JavaScript API,用于在后臺線程中執行耗時的計算任務,以避免阻塞主線程。

          Web Workers的作用是提高瀏覽器的響應性能,使得在執行復雜計算或處理大量數據時,不會影響用戶界面的流暢性。

          Web Workers通過將任務委托給后臺線程來實現并行處理,從而充分利用多核處理器的能力。它們可以與主線程進行通信,但不能直接訪問DOM或執行UI相關的操作。

          9. 解釋一下瀏覽器緩存(Browser Cache)是什么,以及它的作用是什么?

          答案:瀏覽器緩存是瀏覽器在本地存儲Web頁面和資源的副本,以便在后續訪問時可以快速加載。它的作用是減少對服務器的請求次數和網絡傳輸量,提高頁面加載速度和用戶體驗。

          瀏覽器緩存通過在首次請求時將資源保存到本地,并在后續請求時檢查資源是否已經存在并且沒有過期來工作。如果資源已經存在且未過期,瀏覽器會直接從緩存中加載資源,而不是從服務器重新下載。

          10. 什么是重定向(Redirect)?它在瀏覽器中的作用是什么?

          答案:重定向是指當瀏覽器請求一個URL時,服務器返回一個不同的URL,從而將瀏覽器的請求重定向到新的URL上。

          重定向在瀏覽器中的作用是實現頁面的跳轉、URL的修改或資源的重定向。它可以用于多種情況,例如處理舊鏈接的跳轉、實現URL的規范化、處理用戶認證等。

          重定向通過在HTTP響應中設置特定的狀態碼(如301永久重定向、302臨時重定向)和Location頭部字段來實現。

          11. 什么是瀏覽器存儲(Browser Storage)?它有哪些不同的存儲機制?

          答案:瀏覽器存儲是瀏覽器提供的一種在客戶端存儲數據的機制,用于在不同的網頁間共享數據或持久保存數據。

          瀏覽器存儲有以下不同的存儲機制:

          Cookie:小型文本文件,可以存儲少量數據,并在每次HTTP請求中自動發送到服務器。 Web Storage(localStorage和sessionStorage):可以存儲較大量的數據,以鍵值對的形式存儲在瀏覽器中。 IndexedDB:一種高級的客戶端數據庫,可以存儲大量結構化數據,并支持索引和事務操作。 Cache API:用于緩存網絡請求的響應,以便離線訪問或提高頁面加載速度。 不同的存儲機制適用于不同的需求,開發者可以根據具體情況選擇合適的存儲方式。


          原文鏈接:https://juejin.cn/post/7276407803618656295

          2023金九銀十必看前端面試題! 金九銀十黃金期來了 想要跳槽的小伙伴快來看啊

          CSS

          1. 請解釋CSS的盒模型是什么,并描述其組成部分。

          答案:CSS的盒模型是用于布局和定位元素的概念。它由內容區域、內邊距、邊框和外邊距組成,這些部分依次包裹在元素周圍。

          2. 解釋CSS中的選擇器及其優先級。

          答案:CSS選擇器用于選擇要應用樣式的HTML元素。選擇器的優先級規則是:內聯樣式 > ID選擇器 > 類選擇器、屬性選擇器、偽類選擇器 > 元素選擇器 > 通用選擇器。同時,使用!important可以提升樣式的優先級。

          3. 解釋CSS中的浮動(float)是如何工作的,并提供一個示例。

          答案:浮動(float)是CSS中用于實現元素的左浮動或右浮動,使其脫離文檔流并環繞在其周圍的元素。例如:

          .float-example {
            float: left;
            width: 200px;
            height: 200px;
          }

          4. 解釋CSS中的定位(position)屬性及其不同的取值。

          答案:定位(position)屬性用于控制元素的定位方式。常見的取值有:static(默認,按照文檔流定位)、relative(相對定位)、absolute(絕對定位)、fixed(固定定位)和sticky(粘性定位)。

          5. 解釋CSS中的層疊順序(z-index)是如何工作的。

          答案:層疊順序(z-index)用于控制元素在垂直方向上的堆疊順序。具有較高層疊順序值的元素將顯示在較低層疊順序值的元素之上。默認情況下,層疊順序值為auto。

          6. 解釋CSS中的偽類和偽元素的區別,并給出一個示例。

          答案:偽類用于向選擇器添加特殊的狀態,如:hover、:active等。偽元素用于向選擇器添加特殊的元素,如::before、::after等。例如:

          /* 偽類示例 */
          a:hover {
            color: red;
          }
          
          /* 偽元素示例 */
          p::before {
            content: "前綴";
          }

          7. 解釋CSS中的盒子模型的兩種模式:標準模式和怪異模式。

          答案:標準模式是按照W3C標準解析渲染頁面的模式。怪異模式是兼容舊版本瀏覽器的解析渲染頁面的模式。可以通過聲明來指定使用哪種模式。

          8. 解釋CSS中的BFC是什么,它的作用是什么?

          答案:BFC(塊級格式化上下文)是CSS中的一種渲染模式,它創建了一個獨立的渲染環境,其中的元素按照一定的規則進行布局和定位。BFC的作用包括:清除浮動、防止外邊距重疊等。

          9. 解釋CSS中的flexbox布局是什么,它的優勢是什么?

          答案:flexbox布局是一種用于創建靈活的、響應式的布局的CSS模塊。它通過flex容器和flex項目的組合來實現強大的布局能力。其優勢包括簡單易用、自適應性強、對齊和分布控制靈活等。

          10.解釋CSS中的媒體查詢是什么,它的作用是什么?

          答案:媒體查詢是CSS中的一種技術,用于根據設備的特性和屬性來應用不同的樣式。通過媒體查詢,可以根據屏幕尺寸、設備類型、分辨率等條件來優化頁面的布局和樣式。

          JavaScript

          1. 解釋JavaScript的數據類型,并舉例說明每種類型。

          答案:JavaScript有七種數據類型:字符串(String)、數字(Number)、布爾值(Boolean)、對象(Object)、數組(Array)、空值(Null)和未定義(Undefined)。例如:

          let str = "Hello";
          let num = 10;
          let bool = true;
          let obj = { name: "John" };
          let arr = [1, 2, 3];
          let n = null;
          let undef;

          2. 解釋JavaScript中的變量提升(Hoisting)是什么。

          答案:變量提升是指在JavaScript中,變量和函數聲明會在代碼執行之前被提升到作用域的頂部。這意味著可以在聲明之前使用變量和函數。例如:

          console.log(x); // 輸出 undefined
          var x = 5;

          3. 解釋JavaScript中的閉包(Closure)是什么,并舉例說明。

          答案:閉包是指函數可以訪問并操作其詞法作用域之外的變量。它通過在函數內部創建一個內部函數,并返回該內部函數來實現。例如:

          function outer() {
            let x = 10;
            function inner() {
              console.log(x);
            }
            return inner;
          }
          
          let closure = outer();
          closure(); // 輸出 10
          

          4. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指事件從最具體的元素開始向父元素逐級觸發,直到觸發到根元素。事件捕獲是指事件從根元素開始,逐級向最具體的元素觸發。可以使用addEventListener方法的第三個參數來控制是使用事件冒泡還是事件捕獲。

          5. 解釋JavaScript中的原型繼承(Prototype Inheritance)是什么。

          答案:原型繼承是JavaScript中實現對象之間繼承關系的一種機制。每個對象都有一個原型對象,它包含了共享的屬性和方法。當訪問對象的屬性或方法時,如果對象本身沒有,則會沿著原型鏈向上查找。可以使用Object.create()方法或設置對象的__proto__屬性來實現原型繼承。

          6. 解釋JavaScript中的異步編程,并提供一個異步操作的示例。

          答案:異步編程是指在代碼執行過程中,不會阻塞后續代碼執行的一種編程方式。常見的異步操作包括網絡請求、定時器等。例如:

          console.log("開始");
          setTimeout(function() {
            console.log("異步操作");
          }, 1000);
          console.log("結束");

          7. 解釋JavaScript中的閉包(Closure)是什么,并舉例說明。

          答案:閉包是指函數可以訪問并操作其詞法作用域之外的變量。它通過在函數內部創建一個內部函數,并返回該內部函數來實現。例如:

          function outer() {
            let x = 10;
            function inner() {
              console.log(x);
            }
            return inner;
          }
          
          let closure = outer();
          closure(); // 輸出 10

          8. 解釋JavaScript中的this關鍵字的作用和使用場景。

          答案:this關鍵字在JavaScript中表示當前執行上下文的對象。它的具體取值根據函數的調用方式而定。在全局作用域中,this指向全局對象(瀏覽器環境中為window對象)。在函數中,this的指向取決于函數的調用方式,可以通過call、apply、bind等方法來顯式地指定this的值。

          9. 解釋JavaScript中的事件委托(Event Delegation)是什么,并提供一個使用事件委托的示例。

          答案:事件委托是指將事件處理程序綁定到父元素上,而不是直接綁定到每個子元素上。當事件觸發時,事件會冒泡到父元素,然后通過判斷事件的目標來執行相應的處理邏輯。這樣可以減少事件處理程序的數量,提高性能。例如:

          <ul id="list">
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
          </ul>
          
          <script>
          document.getElementById("list").addEventListener("click", function(event) {
            if (event.target.tagName === "LI") {
              console.log(event.target.textContent);
            }
          });
          </script>

          10. 解釋JavaScript中的模塊化編程,并提供一個使用模塊的示例。

          答案:模塊化編程是指將代碼劃分為獨立的模塊,每個模塊負責特定的功能,并通過導入和導出來實現模塊之間的依賴關系。ES6引入了模塊化的語法,可以使用import和export關鍵字來導入和導出模塊。例如:

          // module.js
          export function sayHello() {
            console.log("Hello!");
          }
          
          // main.js
          import { sayHello } from "./module.js";
          sayHello(); // 輸出 "Hello!"

          11. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指當一個事件在DOM樹中觸發時,它會從最內層的元素開始向外傳播至最外層的元素。事件捕獲是指當一個事件在DOM樹中觸發時,它會從最外層的元素開始向內傳播至最內層的元素。

          12. 什么是原型鏈(Prototype Chain)?如何利用原型鏈實現繼承?

          答案:原型鏈是JavaScript中對象之間的連接關系,每個對象都有一個指向其原型(prototype)的引用。通過原型鏈,對象可以繼承其原型對象的屬性和方法。可以使用原型鏈實現繼承,通過將一個對象的原型指向另一個對象,從而使得該對象可以訪問另一個對象的屬性和方法。

          13. 解釋JavaScript中的防抖(Debounce)和節流(Throttle)。

          答案:防抖和節流都是用于控制函數執行頻率的技術。防抖指的是在某個時間段內,只執行最后一次觸發的函數調用。節流指的是在某個時間段內,按照固定的時間間隔執行函數調用。

          14. 什么是事件循環(Event Loop)?請解釋JavaScript中的事件循環機制。

          答案:事件循環是JavaScript中處理異步操作的機制。事件循環不斷地從任務隊列中取出任務并執行,直到任務隊列為空。事件循環由主線程和任務隊列組成,主線程負責執行同步任務,異步任務會被放入任務隊列中,等待主線程空閑時被執行。

          15. 解釋JavaScript中的深拷貝和淺拷貝。

          答案:深拷貝是指創建一個新對象,將原始對象的所有屬性和嵌套對象的屬性都復制到新對象中。淺拷貝是指創建一個新對象,將原始對象的屬性復制到新對象中,但嵌套對象的引用仍然是共享的。

          16. 什么是異步編程?請列舉幾種處理異步操作的方法。

          答案:異步編程是一種處理可能耗時的操作而不阻塞主線程的編程方式。常見的處理異步操作的方法有回調函數、Promise、async/await和事件監聽等。

          17. 解釋JavaScript中的Hoisting(變量提升)。

          答案:變量提升是指在JavaScript中,變量和函數的聲明會被提升到當前作用域的頂部。這意味著可以在聲明之前使用變量和函數,但它們的賦值或定義仍然在原來的位置。

          18. 什么是柯里化(Currying)?請給出一個柯里化的示例。

          答案:柯里化是一種將接受多個參數的函數轉換為接受一個參數并返回一個新函數的過程。示例:

          function add(a) {
            return function(b) {
              return a + b;
            }
          }
          
          var add5 = add(5);
          console.log(add5(3)); // 輸出:8

          19. 解釋JavaScript中的嚴格模式(Strict Mode)。

          答案:嚴格模式是一種JavaScript的執行模式,它提供了更嚴格的語法和錯誤檢查。在嚴格模式下,一些不安全或不推薦的語法會被禁用,同時會引入一些新的特性,如變量必須先聲明才能使用、禁止使用this指向全局對象等。

          TypeScript

          1. 解釋TypeScript和JavaScript之間的關系。

          答案:TypeScript是JavaScript的超集,它添加了靜態類型和其他一些特性。TypeScript代碼可以編譯成JavaScript代碼,因此可以在任何支持JavaScript的環境中運行。

          2. TypeScript中的類型注解是什么?如何使用類型注解?

          答案:類型注解是指在變量、函數參數、函數返回值等地方顯式地聲明類型信息。可以使用冒號(:)后跟類型來添加類型注解。例如:

          let num: number = 10;
          
          function add(a: number, b: number): number {
            return a + b;
          }

          3. TypeScript中的接口是什么?如何定義和使用接口?

          答案:接口是一種用于定義對象的結構和類型的語法。可以使用interface關鍵字來定義接口。例如:

          interface Person {
            name: string;
            age: number;
          }
          
          function greet(person: Person) {
            console.log(`Hello, ${person.name}!`);
          }
          
          let john: Person = { name: "John", age: 25 };
          greet(john); // 輸出 "Hello, John!"

          4. TypeScript中的類是什么?如何定義和使用類?

          答案:類是一種用于創建對象的藍圖,它包含屬性和方法。可以使用class關鍵字來定義類。例如:

          class Person {
            name: string;
            age: number;
          
            constructor(name: string, age: number) {
              this.name = name;
              this.age = age;
            }
          
            greet() {
              console.log(`Hello, ${this.name}!`);
            }
          }
          
          let john = new Person("John", 25);
          john.greet(); // 輸出 "Hello, John!"

          5. TypeScript中的泛型是什么?如何使用泛型?

          答案:泛型是一種用于創建可重用代碼的工具,它允許在定義函數、類或接口時使用占位符類型。可以使用尖括號(<>)來指定泛型類型。例如:

          function identity<T>(value: T): T {
            return value;
          }
          
          let result = identity<string>("Hello");
          console.log(result); // 輸出 "Hello"

          6. TypeScript中的枚舉是什么?如何定義和使用枚舉?

          答案:枚舉是一種用于定義命名常量集合的語法。可以使用enum關鍵字來定義枚舉。例如:

          enum Color {
            Red,
            Green,
            Blue,
          }
          
          let color: Color = Color.Green;
          console.log(color); // 輸出 1

          7. TypeScript中的模塊是什么?如何導出和導入模塊?

          答案:模塊是用于組織和封裝代碼的單元。可以使用export關鍵字將模塊中的變量、函數、類等導出,以便其他模塊可以使用。可以使用import關鍵字來導入其他模塊的導出。例如:

          // module.ts
          export function greet(name: string) {
            console.log(`Hello, ${name}!`);
          }
          
          // main.ts
          import { greet } from "./module";
          greet("John"); // 輸出 "Hello, John!"

          8. TypeScript中的類型推斷是什么?如何使用類型推斷?

          答案:類型推斷是指TypeScript根據上下文自動推斷變量的類型,而無需顯式地添加類型注解。例如:

          let num = 10; // 推斷為 number 類型
          let str = "Hello"; // 推斷為 string 類型

          9. TypeScript中的命名空間是什么?如何定義和使用命名空間?

          答案:命名空間是一種用于組織和封裝代碼的機制,它避免了全局命名沖突。可以使用namespace關鍵字來定義命名空間。例如:

          namespace MyNamespace {
            export function greet(name: string) {
              console.log(`Hello, ${name}!`);
            }
          }
          
          MyNamespace.greet("John"); // 輸出 "Hello, John!"

          10. TypeScript中的類型別名是什么?如何定義和使用類型別名?

          答案:類型別名是給類型起一個別名,以便在代碼中更方便地引用。可以使用type關鍵字來定義類型別名。例如:

          type Point = { x: number; y: number };
          
          function printPoint(point: Point) {
            console.log(`(${point.x}, ${point.y})`);
          }
          
          let p: Point = { x: 1, y: 2 };
          printPoint(p); // 輸出 "(1, 2)"

          VUE2

          1. Vue.js是什么?它有哪些特點?

          答案:Vue.js是一個用于構建用戶界面的JavaScript框架。它具有以下特點:

          響應式數據綁定:通過使用Vue的數據綁定語法,可以實現數據的自動更新。 組件化開發:Vue允許將頁面劃分為獨立的組件,提高了代碼的可維護性和復用性。 虛擬DOM:Vue使用虛擬DOM來跟蹤頁面上的變化,并高效地更新實際的DOM。 指令系統:Vue提供了豐富的內置指令,用于處理常見的DOM操作和邏輯控制。 生態系統:Vue擁有龐大的生態系統,包括插件、工具和第三方庫,可以滿足各種開發需求。

          2. Vue中的雙向數據綁定是如何實現的?

          答案:Vue中的雙向數據綁定是通過v-model指令實現的。v-model可以在表單元素(如、、)上創建雙向數據綁定。當用戶輸入改變表單元素的值時,數據模型會自動更新;反之,當數據模型的值改變時,表單元素也會自動更新。

          3. Vue中的生命周期鉤子有哪些?它們的執行順序是怎樣的?

          答案:Vue中的生命周期鉤子包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy和destroyed。它們的執行順序如下:

          beforeCreate created beforeMount mounted beforeUpdate updated beforeDestroy destroyed

          4. Vue中的計算屬性和監聽器有什么區別?

          答案:計算屬性是基于依賴的屬性,它根據其依賴的數據動態計算得出值。計算屬性具有緩存機制,只有在依賴的數據發生變化時才會重新計算。監聽器是用于監聽數據的變化并執行相應的操作。當數據發生變化時,監聽器會立即執行指定的回調函數。

          5. Vue中的組件通信有哪些方式?

          答案:Vue中的組件通信方式包括:

          父子組件通信:通過props向子組件傳遞數據,子組件通過事件向父組件發送消息。 子父組件通信:子組件通過$emit觸發事件,父組件通過監聽事件并響應。 兄弟組件通信:通過共享的父組件來傳遞數據或通過事件總線(Event Bus)進行通信。 跨級組件通信:通過provide和inject來在祖先組件中提供數據,然后在后代組件中使用。

          6. Vue中的路由是如何實現的?

          答案:Vue中的路由是通過Vue Router實現的。Vue Router是Vue.js官方提供的路由管理器,它允許開發者在Vue應用中實現單頁面應用(SPA)。Vue Router通過配置路由映射關系,將URL路徑與組件進行關聯,并提供導航功能,使用戶可以在不刷新頁面的情況下切換視圖。

          7. Vue中的指令有哪些?舉例說明它們的用法。

          答案:Vue中常用的指令包括:

          v-if:根據表達式的值條件性地渲染元素。 v-for:根據數組或對象的數據進行循環渲染。 v-bind:用于動態綁定屬性或響應式地更新屬性。 v-on:用于監聽DOM事件并執行相應的方法。 v-model:用于在表單元素上實現雙向數據綁定。 例如:

          <div v-if="show">顯示內容</div>
          
          <ul>
            <li v-for="item in items" :key="item.id">{{ item.name }}</li>
          </ul>
          
          <img v-bind:src="imageUrl">
          
          <button v-on:click="handleClick">點擊按鈕</button>
          
          <input v-model="message">

          8. Vue中的watch和computed有什么區別?

          答案:watch和computed都可以用于監聽數據的變化,但它們的用法和實現方式略有不同。watch用于監聽指定的數據變化,并在數據變化時執行相應的操作。computed用于根據依賴的數據動態計算得出一個新的值,并將該值緩存起來,只有在依賴的數據發生變化時才會重新計算。

          9. Vue中的mixin是什么?它有什么作用?

          答案:Mixin是一種用于在多個組件之間共享代碼的方式。Mixin可以包含組件選項(如數據、方法、生命周期鉤子等),并將其合并到使用Mixin的組件中。這樣可以實現代碼的復用和組件的擴展,減少重復編寫相似代碼的工作。

          10. Vue中的keep-alive是什么?它有什么作用?

          答案:是Vue中的一個內置組件,用于緩存動態組件。當組件包裹在中時,組件的狀態將被保留,包括它的實例、狀態和DOM結構。這樣可以避免在組件切換時重復創建和銷毀組件,提高性能和用戶體驗。

          11. 請解釋Vue.js中的依賴注入(Dependency Injection)是什么?它在Vue中的應用場景是什么?

          答案:依賴注入是一種設計模式,用于將依賴關系從一個組件傳遞到另一個組件。在Vue中,依賴注入通過provide和inject選項實現。父組件通過provide提供數據,然后子組件通過inject注入這些數據。它在跨多個層級的組件通信中非常有用。

          12. Vue.js中的渲染函數(Render Function)是什么?它與模板(Template)有什么區別?

          答案:渲染函數是一種用JavaScript代碼編寫組件的方式,它可以動態地生成虛擬DOM。與模板相比,渲染函數提供了更大的靈活性和控制力,可以處理更復雜的邏輯和動態渲染需求。

          13. Vue.js中的插槽(Slot)是什么?請提供一個具有命名插槽和作用域插槽的示例。

          答案:插槽是一種用于在組件中擴展內容的機制。命名插槽允許父組件向子組件插入具有特定名稱的內容,而作用域插槽允許子組件將數據傳遞給父組件。示例:

          <!-- 父組件 -->
          <template>
            <div>
              <slot name="header"></slot>
              <slot :data="data"></slot>
            </div>
          </template>
          
          <!-- 子組件 -->
          <template>
            <div>
              <slot name="header">默認標題</slot>
              <slot :data="computedData">{{ computedData }}</slot>
            </div>
          </template>

          14. Vue.js中的動畫系統是如何工作的?請提供一個簡單的動畫示例。

          答案:Vue.js的動畫系統通過CSS過渡和動畫類實現。通過在元素上添加過渡類或動畫類,可以觸發相應的過渡效果或動畫效果。示例:

          <transition name="fade">
            <div v-if="show">顯示內容</div>
          </transition>
          
          <!-- CSS樣式 -->
          <style>
          .fade-enter-active, .fade-leave-active {
            transition: opacity 0.5s;
          }
          .fade-enter, .fade-leave-to {
            opacity: 0;
          }
          </style>

          15. Vue.js中的錯誤處理機制是什么?如何捕獲和處理Vue組件中的錯誤?

          答案:Vue.js提供了全局的錯誤處理機制和組件級別的錯誤處理機制。全局錯誤處理可以通過errorCaptured鉤子函數捕獲和處理錯誤。組件級別的錯誤處理可以通過errorCaptured鉤子函數或errorHandler選項捕獲和處理錯誤。

          16. Vue.js中的服務端渲染(SSR)是什么?它有哪些優勢和限制?

          答案:服務端渲染是指在服務器上生成HTML內容并將其發送到瀏覽器進行渲染的過程。Vue.js可以進行服務端渲染,提供更好的首次加載性能和SEO優化。然而,服務端渲染也帶來了一些限制,如增加了服務器負載和開發復雜性。

          17. Vue.js中的響應式數組有哪些限制?如何解決這些限制?

          答案:Vue.js的響應式系統對于數組的變異方法(如push、pop、splice等)是無法追蹤的。為了解決這個限制,Vue提供了一些特殊的方法,如Vue.set、vm.$set和Array.prototype.splice。這些方法可以用于更新數組并保持響應式。

          18. Vue.js中的性能優化有哪些常見的技巧?

          答案:常見的Vue.js性能優化技巧包括:

          使用v-if和v-for時注意避免不必要的渲染。 合理使用computed屬性和watch監聽器。 使用keep-alive組件緩存組件狀態。 使用異步組件進行按需加載。 避免在模板中使用復雜的表達式。 使用key屬性管理組件和元素的復用。 合理使用懶加載和分割代碼。

          19. Vue.js中的路由導航守衛有哪些?它們的執行順序是怎樣的?

          答案:Vue.js中的路由導航守衛包括全局前置守衛、全局解析守衛、全局后置守衛、路由獨享守衛和組件內守衛。它們的執行順序如下:

          全局前置守衛(beforeEach) 路由獨享守衛(beforeEnter) 解析守衛(beforeResolve) 組件內守衛(beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave) 全局后置守衛(afterEach)

          20. Vue.js中的單元測試是如何進行的?請提供一個簡單的單元測試示例。

          答案:Vue.js的單元測試可以使用工具如Jest或Mocha進行。示例:

          // 組件代碼
          // MyComponent.vue
          <template>
            <div class="my-component">
              <span>{{ message }}</span>
              <button @click="increment">增加</button>
            </div>
          </template>
          
          <script>
          export default {
            data() {
              return {
                message: 'Hello',
                count: 0
              }
            },
            methods: {
              increment() {
                this.count++
              }
            }
          }
          </script>
          
          // 單元測試代碼
          // MyComponent.spec.js
          import { shallowMount } from '@vue/test-utils'
          import MyComponent from './MyComponent.vue'
          
          describe('MyComponent', () => {
            it('renders message correctly', () => {
              const wrapper = shallowMount(MyComponent)
              expect(wrapper.find('span').text()).toBe('Hello')
            })
          
            it('increments count when button is clicked', () => {
              const wrapper = shallowMount(MyComponent)
              wrapper.find('button').trigger('click')
              expect(wrapper.vm.count).toBe(1)
            })
          })

          VUE3

          1. Vue.js 3中的Composition API是什么?它與Options API有什么區別?

          答案:Composition API是Vue.js 3中引入的一種新的組織組件邏輯的方式。它允許開發者通過函數的方式組織和重用邏輯,而不是通過選項對象。相比之下,Options API是Vue.js 2中常用的組織組件邏輯的方式,通過選項對象中的屬性來定義組件的數據、方法等。

          2. Vue.js 3中的Teleport是什么?請給出一個Teleport的示例。

          答案:Teleport是Vue.js 3中引入的一種機制,用于將組件的內容渲染到DOM樹中的任意位置。示例:

          <template>
            <div>
              <button @click="showModal = true">打開模態框</button>
              <teleport to="body">
                <modal v-if="showModal" @close="showModal = false">模態框內容</modal>
              </teleport>
            </div>
          </template>

          3. Vue.js 3中的響應式系統是如何工作的?它與Vue.js 2中的響應式系統有什么區別?

          答案:Vue.js 3中的響應式系統使用了Proxy對象來實現。與Vue.js 2中的響應式系統相比,Vue.js 3的響應式系統具有更好的性能和更細粒度的追蹤,能夠更準確地檢測到數據的變化,并且支持嵌套的響應式數據。

          4. Vue.js 3中的Suspense是什么?它的作用是什么?

          答案:Suspense是Vue.js 3中引入的一種機制,用于處理異步組件的加載狀態。它可以在異步組件加載完成之前顯示一個占位符,并在加載完成后渲染異步組件的內容。這樣可以更好地處理異步組件的加載過程,提供更好的用戶體驗。

          5. Vue.js 3中的provide和inject有什么作用?請給出一個provide和inject的示例。

          答案:provide和inject用于實現組件之間的依賴注入。通過在父組件中使用provide提供數據,然后在子組件中使用inject注入這些數據。示例:

          // 父組件
          const Parent = {
            provide: {
              message: 'Hello'
            },
            // ...
          }
          
          // 子組件
          const Child = {
            inject: ['message'],
            created() {
              console.log(this.message); // 輸出:Hello
            },
            // ...
          }

          6. Vue.js 3中的動畫系統有哪些改進?請列舉幾個改進之處。

          答案:Vue.js 3中的動畫系統相比Vue.js 2有以下改進之處:

          更好的性能:Vue.js 3的動畫系統使用了更高效的動畫引擎,提供了更好的性能。 更簡潔的語法:Vue.js 3的動畫系統使用了更簡潔的語法,使得動畫的定義和使用更加直觀和方便。 支持更多的動畫特性:Vue.js 3的動畫系統支持更多的動畫特性,如交互式動畫和更復雜的動畫效果。 Vue.js 3中的靜態提升(Static Tree Hoisting)是什么?它有什么優勢? 答案:靜態提升是Vue.js 3中的一項優化技術,通過在編譯階段將靜態節點提升為常量,從而減少了運行時的開銷。這項優化技術可以提高組件的渲染性能,并減少生成的代碼體積。

          7. Vue.js 3中的Fragment是什么?它的作用是什么?

          答案:Fragment是Vue.js 3中引入的一種機制,用于在組件中返回多個根節點。在Vue.js 2中,組件的模板只能有一個 Vue.js 3中的Composition API中的ref和reactive有什么區別?什么時候使用哪個? 答案:ref用于創建一個響應式的基本數據類型,而reactive用于創建一個響應式的對象。當需要創建一個簡單的響應式數據時,可以使用ref,當需要創建一個包含多個屬性的響應式對象時,可以使用reactive。

          8. Vue.js 3中的watchEffect和watch有什么區別?什么時候使用哪個?

          答案:watchEffect用于監聽響應式數據的變化,并在回調函數中執行相應的操作。它會自動追蹤依賴,并在依賴變化時重新運行回調函數。watch用于監聽指定的響應式數據,并在其變化時執行相應的操作。它可以精確地指定要監聽的數據,并提供更多的配置選項。一般來說,如果只需要監聽一個響應式數據的變化并執行相應操作,可以使用watchEffect;如果需要更細粒度的控制,可以使用watch。

          9. Vue.js 3中的v-model指令在使用時有哪些注意事項?

          答案:在使用v-model指令時,有以下注意事項:

          v-model指令必須與一個表單元素一起使用,如、、等。 當使用自定義組件時,組件內部必須實現modelValue屬性和update:modelValue事件,以支持v-model的雙向綁定。 可以使用.lazy修飾符實現在輸入框失去焦點時更新數據。 可以使用.trim修飾符自動去除輸入框內容的首尾空格。 可以使用.number修飾符將輸入框的值轉換為數字類型。

          10. Vue.js 3中的provide和inject是否支持響應式數據?

          答案:默認情況下,provide和inject不支持響應式數據。如果需要在provide中提供一個響應式數據,可以使用ref或reactive將數據包裝起來。然后在inject中使用toRefs或toRef將數據解構出來,以獲取響應式的引用。

          11. Vue.js 3中的nextTick方法有什么作用?在什么情況下使用它?

          答案:nextTick方法用于在下次DOM更新循環結束之后執行回調函數。它可以用來確保在更新DOM后執行某些操作,如操作更新后的DOM元素或獲取更新后的計算屬性的值。通常在需要等待DOM更新完成后進行操作的情況下使用nextTick。

          12. Vue.js 3中的和組件有什么區別?

          答案:組件用于將組件的內容渲染到DOM樹中的任意位置,而組件用于在組件進入或離開DOM樹時應用過渡效果。主要用于組件的位置移動,而主要用于組件的顯示和隱藏過渡。

          13. Vue.js 3中的v-for指令中的key屬性有什么作用?為什么要使用它?

          答案:v-for指令中的key屬性用于給每個迭代項設置一個唯一的標識符。它的作用是幫助Vue.js跟蹤每個節點的身份,以便在數據發生變化時高效地更新DOM。使用key屬性可以避免出現錯誤的節點更新或重新排序的問題。

          React

          1. 什么是React?它的核心概念是什么?

          答案:React是一個用于構建用戶界面的JavaScript庫。它的核心概念是組件化和聲明式編程。React將用戶界面拆分為獨立的可重用組件,并使用聲明式語法描述組件的狀態和UI的關系,使得構建復雜的UI變得簡單和可維護。

          2. 什么是JSX?它與HTML有什么區別?

          答案:JSX是一種JavaScript的語法擴展,用于在React中描述UI的結構。它類似于HTML,但有一些區別:

          3. 什么是React組件?它們有哪兩種類型?

          答案:React組件是構建用戶界面的獨立單元。React組件有兩種類型:

          函數組件:使用函數來定義組件,接收props作為參數,并返回一個React元素。 類組件:使用ES6類來定義組件,繼承自React.Component類,通過render方法返回一個React元素。

          4. 什么是狀態(state)和屬性(props)?它們之間有什么區別?

          答案:狀態(state)是組件自身管理的數據,可以通過setState方法來更新。屬性(props)是從父組件傳遞給子組件的數據,子組件無法直接修改props,只能通過父組件的更新來改變props。

          區別:

          狀態(state)是組件內部的數據,可以在組件中自由修改和管理。 屬性(props)是從父組件傳遞給子組件的數據,子組件無法直接修改,只能接收和使用。

          5. 什么是React生命周期方法?列舉一些常用的生命周期方法。

          答案:React生命周期方法是在組件不同階段執行的特定方法。以下是一些常用的React生命周期方法:

          componentDidMount:組件掛載后立即調用。 componentDidUpdate:組件更新后調用。 componentWillUnmount:組件卸載前調用。 shouldComponentUpdate:決定組件是否需要重新渲染。 getDerivedStateFromProps:根據props的變化來更新狀態。

          6. 什么是React Hooks?它們的作用是什么?

          答案:React Hooks是React 16.8版本引入的一種特性,用于在函數組件中使用狀態和其他React特性。Hooks提供了一種無需編寫類組件的方式來管理狀態和處理副作用,使得函數組件具有類組件的能力。

          7. 什么是React Router?它的作用是什么?

          答案:React Router是React中用于處理路由的庫。它提供了一種在單頁面應用中實現導航和路由功能的方式。React Router可以幫助開發者實現頁面之間的切換、URL參數的傳遞、嵌套路由等功能。

          8. 什么是React Context?它的作用是什么?

          答案:React Context是一種用于在組件樹中共享數據的機制。它可以避免通過props一層層傳遞數據,使得跨組件的數據共享變得更加簡單和高效。React Context提供了一個Provider和Consumer組件,用于提供和消費共享的數據。

          9. 什么是React的協調(Reconciliation)過程?它是如何工作的?

          答案:React的協調過程是指React在進行組件更新時,通過比較新舊虛擬DOM樹的差異,僅對需要更新的部分進行實際的DOM操作。協調過程的工作方式如下:

          React會逐層比較新舊虛擬DOM樹的節點,并找出差異。 對于每個差異,React會生成相應的DOM操作指令,如插入、更新或刪除節點。 React會將所有的DOM操作指令批量執行,以減少對真實DOM的操作次數。

          10. 什么是React的事件合成(SyntheticEvent)?它的作用是什么?

          答案:React的事件合成是一種在React中處理事件的機制。它是React為了提高性能和跨瀏覽器兼容性而實現的一種事件系統。事件合成的作用包括:

          提供了一種統一的方式來處理事件,無需考慮瀏覽器兼容性。 可以通過事件委托的方式將事件處理程序綁定到父組件,提高性能。 可以訪問原生事件對象的屬性和方法。

          11. 什么是React的Fiber架構?它解決了什么問題?

          答案:React的Fiber架構是React 16版本引入的一種新的協調算法和架構。它旨在解決長時間渲染阻塞主線程的問題,提高應用的性能和用戶體驗。Fiber架構通過將渲染過程分解為多個小任務,并使用優先級調度算法來動態分配時間片,使得React可以在每個幀中執行一部分任務,從而實現平滑的用戶界面和更好的響應性能。

          12. 什么是React的錯誤邊界(Error Boundary)?它的作用是什么?

          答案:React的錯誤邊界是一種用于處理組件錯誤的機制。它允許組件捕獲并處理其子組件中發生的JavaScript錯誤,以避免整個應用崩潰。錯誤邊界的作用包括:

          捕獲并處理組件樹中的錯誤,防止錯誤導致整個應用崩潰。 提供一種優雅的方式來顯示錯誤信息或備用UI。 可以用于記錄錯誤和發送錯誤報告。

          網絡

          1. 什么是HTTP?它是如何工作的?

          答案:HTTP(Hypertext Transfer Protocol)是一種用于在Web上傳輸數據的協議。它使用客戶端-服務器模型,客戶端發送HTTP請求到服務器,服務器返回HTTP響應。HTTP的工作流程如下:

          客戶端發送HTTP請求到指定的URL。 服務器接收請求并處理,然后返回HTTP響應。 客戶端接收響應并解析,從中獲取所需的數據。

          2. 什么是HTTPS?與HTTP有什么區別?

          答案:HTTPS(Hypertext Transfer Protocol Secure)是HTTP的安全版本,通過使用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)協議對通信進行加密和身份驗證。與HTTP相比,HTTPS具有以下區別:

          數據在傳輸過程中通過加密進行保護,提供更高的安全性。 使用數字證書對服務器進行身份驗證,防止中間人攻擊。 使用默認端口443。

          3. 什么是跨域請求?它是如何解決的?

          答案:跨域請求是指在瀏覽器中向不同域名、端口或協議發送的請求。由于瀏覽器的同源策略(Same-Origin Policy)限制,跨域請求會受到限制。為了解決跨域問題,可以使用以下方法:

          JSONP(JSON with Padding):通過動態創建

          4. 什么是緩存?在前端中如何使用緩存來提高性能?

          答案:緩存是將數據或資源存儲在臨時存儲中,以便在后續請求中重復使用,從而提高性能和減少網絡流量。在前端中,可以使用以下方式來利用緩存:

          HTTP緩存:通過設置適當的緩存頭(如Cache-Control和Expires)來指示瀏覽器緩存響應。 資源緩存:使用文件指紋或版本號來重命名靜態資源文件,以便在文件內容變化時使瀏覽器重新下載。 數據緩存:使用內存緩存、瀏覽器本地存儲(如localStorage)或服務端緩存(如Redis)來存儲數據,避免重復請求。

          5. 什么是CDN?它的作用是什么?

          答案:CDN(Content Delivery Network)是一種分布式網絡架構,用于在全球各地提供高性能、低延遲的內容傳輸服務。CDN的作用包括:

          將靜態資源(如圖片、樣式表、腳本等)緩存到離用戶更近的服務器上,提供更快的加載速度。 分發網絡流量,減輕源服務器的負載壓力。 提供內容壓縮、數據壓縮和緩存等優化技術,提高用戶體驗。

          6. 什么是網頁加載性能優化?可以采取哪些措施來改善網頁加載性能?

          答案:網頁加載性能優化是指通過各種技術手段來減少網頁加載時間并提高用戶體驗。可以采取以下措施來改善網頁加載性能:

          壓縮和合并資源文件(如CSS和JavaScript),減少文件大小和請求數量。 使用圖像壓縮和適當的格式選擇來減小圖像文件大小。 使用瀏覽器緩存和HTTP緩存頭來緩存靜態資源。 使用懶加載延遲加載非關鍵資源,提高初始加載速度。 使用CDN(內容分發網絡)來分發靜態資源,減少網絡延遲。 優化關鍵渲染路徑,盡早呈現頁面內容。

          7. 什么是網頁性能監測和分析?可以使用哪些工具來監測和分析網頁性能?

          答案:網頁性能監測和分析是指通過測量和收集有關網頁加載和交互性能的數據,以便識別性能瓶頸并進行優化。可以使用以下工具來監測和分析網頁性能:

          Web性能API:瀏覽器提供的JavaScript API,可通過performance對象來收集性能數據。 Lighthouse:一種開源工具,可提供關于網頁性能、可訪問性和最佳實踐的綜合報告。 WebPagetest:在線工具,可測量網頁加載時間并提供詳細的性能分析報告。 Chrome開發者工具:瀏覽器內置的開發者工具,提供了性能分析、網絡監控和頁面審查等功能。

          8. 什么是漸進式圖像加載(Progressive Image Loading)?它如何改善網頁加載性能?

          答案:漸進式圖像加載是一種技術,通過逐步加載圖像的模糊或低分辨率版本,然后逐漸提高圖像的清晰度,以改善網頁加載性能和用戶體驗。漸進式圖像加載的好處包括:

          用戶可以更快地看到頁面內容,提高感知速度。 逐步加載圖像可以減少網頁整體的加載時間。 漸進式圖像加載可以提供平滑的過渡效果,避免頁面內容突然閃爍或變化。

          9. 什么是前端資源優先級(Resource Prioritization)?如何設置資源的優先級?

          答案:前端資源優先級是指為不同類型的資源分配加載優先級,以優化網頁加載性能。可以使用以下方法設置資源的優先級:

          使用標簽來指定資源的預加載,以確保關鍵資源盡早加載。 使用標簽來指定可能在未來頁面中使用的資源,以提前加載。 使用標簽來指定要預解析的域名,以減少DNS查找時間。 使用標簽來指定要預連接的域名,以減少建立連接的時間。

          瀏覽器

          1.解釋一下瀏覽器的工作原理。

          答案:瀏覽器的工作原理包括以下幾個關鍵步驟:

          解析:瀏覽器將接收到的HTML、CSS和JavaScript代碼解析成DOM樹、CSSOM樹和JavaScript引擎可執行的代碼。 渲染:瀏覽器使用DOM樹和CSSOM樹構建渲染樹,然后根據渲染樹進行布局(計算元素的位置和大小)和繪制(將元素繪制到屏幕上)。 布局和繪制:瀏覽器根據渲染樹的變化進行布局和繪制,然后將最終的頁面呈現給用戶。 JavaScript引擎執行:瀏覽器的JavaScript引擎解釋和執行JavaScript代碼,并根據需要更新渲染樹和重新渲染頁面。

          2. 什么是重繪(Repaint)和重排(Reflow)?它們之間有什么區別?

          答案:重繪是指當元素的外觀(如顏色、背景等)發生改變,但布局不受影響時的更新過程。重繪不會導致元素的位置或大小發生變化。

          重排是指當元素的布局屬性(如寬度、高度、位置等)發生改變時的更新過程。重排會導致瀏覽器重新計算渲染樹和重新繪制頁面的一部分或全部。

          區別在于重繪只涉及外觀的更改,而重排涉及布局的更改。重排比重繪更消耗性能,因為它需要重新計算布局和繪制整個頁面。

          3. 什么是事件冒泡和事件捕獲?它們之間有什么區別?

          答案:事件冒泡和事件捕獲是指瀏覽器處理事件時的兩種不同的傳播方式。

          事件冒泡是指事件從最內層的元素開始觸發,然后逐級向上傳播到父元素,直到傳播到最外層的元素。

          事件捕獲是指事件從最外層的元素開始觸發,然后逐級向下傳播到最內層的元素。

          區別在于傳播方向的不同。事件冒泡是從內向外傳播,而事件捕獲是從外向內傳播。

          4. 解釋一下同步和異步的JavaScript代碼執行方式。

          答案:同步代碼是按照順序執行的代碼,每個任務必須等待前一個任務完成后才能執行。同步代碼會阻塞后續代碼的執行,直到當前任務完成。

          異步代碼是不按照順序執行的代碼,它會在后臺執行,不會阻塞后續代碼的執行。異步代碼通常使用回調函數、Promise、async/await等方式來處理異步操作的結果。

          通過異步執行,可以避免阻塞主線程,提高頁面的響應性能。

          5. 什么是事件循環(Event Loop)?它在JavaScript中的作用是什么?

          答案:事件循環是JavaScript中處理異步代碼執行的機制。它負責管理調度和執行異步任務,并將它們添加到執行隊列中。

          在JavaScript中,事件循環的作用是確保異步任務按照正確的順序執行,并且不會阻塞主線程。它通過不斷地從執行隊列中取出任務并執行,以實現非阻塞的異步操作。

          6. 解釋一下瀏覽器的垃圾回收機制是如何工作的。

          答案:瀏覽器的垃圾回收機制是一種自動管理內存的機制,用于檢測和回收不再使用的對象,以釋放內存資源。

          垃圾回收機制通過標記-清除算法實現。它的工作原理如下:

          標記階段:垃圾回收器會從根對象(如全局對象)開始,遞歸遍歷所有對象,并標記仍然可訪問的對象。 清除階段:垃圾回收器會掃描堆內存,清除未被標記的對象,并回收它們所占用的內存空間。 垃圾回收機制的目標是識別和回收不再使用的對象,以避免內存泄漏和提高內存利用率。

          7. 解釋一下瀏覽器的同源策略(Same-Origin Policy)及其限制。

          答案:同源策略是瀏覽器的一項安全機制,用于限制來自不同源的網頁之間的交互。同源是指協議、域名和端口號完全相同。

          同源策略的限制包括:

          腳本訪問限制:不同源的腳本無法直接訪問彼此的數據和操作。 DOM訪問限制:不同源的網頁無法通過JavaScript訪問彼此的DOM元素。 Cookie限制:不同源的網頁無法讀取或修改彼此的Cookie。 AJAX請求限制:不同源的網頁無法通過AJAX請求訪問彼此的數據。 同源策略的存在可以防止惡意網站獲取用戶的敏感信息或進行惡意操作。

          8. 什么是Web Workers?它們在瀏覽器中的作用是什么?

          答案:Web Workers是一種瀏覽器提供的JavaScript API,用于在后臺線程中執行耗時的計算任務,以避免阻塞主線程。

          Web Workers的作用是提高瀏覽器的響應性能,使得在執行復雜計算或處理大量數據時,不會影響用戶界面的流暢性。

          Web Workers通過將任務委托給后臺線程來實現并行處理,從而充分利用多核處理器的能力。它們可以與主線程進行通信,但不能直接訪問DOM或執行UI相關的操作。

          9. 解釋一下瀏覽器緩存(Browser Cache)是什么,以及它的作用是什么?

          答案:瀏覽器緩存是瀏覽器在本地存儲Web頁面和資源的副本,以便在后續訪問時可以快速加載。它的作用是減少對服務器的請求次數和網絡傳輸量,提高頁面加載速度和用戶體驗。

          瀏覽器緩存通過在首次請求時將資源保存到本地,并在后續請求時檢查資源是否已經存在并且沒有過期來工作。如果資源已經存在且未過期,瀏覽器會直接從緩存中加載資源,而不是從服務器重新下載。

          10. 什么是重定向(Redirect)?它在瀏覽器中的作用是什么?

          答案:重定向是指當瀏覽器請求一個URL時,服務器返回一個不同的URL,從而將瀏覽器的請求重定向到新的URL上。

          重定向在瀏覽器中的作用是實現頁面的跳轉、URL的修改或資源的重定向。它可以用于多種情況,例如處理舊鏈接的跳轉、實現URL的規范化、處理用戶認證等。

          重定向通過在HTTP響應中設置特定的狀態碼(如301永久重定向、302臨時重定向)和Location頭部字段來實現。

          11. 什么是瀏覽器存儲(Browser Storage)?它有哪些不同的存儲機制?

          答案:瀏覽器存儲是瀏覽器提供的一種在客戶端存儲數據的機制,用于在不同的網頁間共享數據或持久保存數據。

          瀏覽器存儲有以下不同的存儲機制:

          Cookie:小型文本文件,可以存儲少量數據,并在每次HTTP請求中自動發送到服務器。 Web Storage(localStorage和sessionStorage):可以存儲較大量的數據,以鍵值對的形式存儲在瀏覽器中。 IndexedDB:一種高級的客戶端數據庫,可以存儲大量結構化數據,并支持索引和事務操作。 Cache API:用于緩存網絡請求的響應,以便離線訪問或提高頁面加載速度。 不同的存儲機制適用于不同的需求,開發者可以根據具體情況選擇合適的存儲方式。

          祝想跳槽的小伙伴們都能成功!需要更多完整面試題可以私信我!


          主站蜘蛛池模板: 无码人妻精品一区二区三区久久久| 视频一区精品自拍| 精品一区二区三区无码免费直播 | 一区二区三区波多野结衣| 精品伦精品一区二区三区视频| 麻豆AV一区二区三区| 国产精品无码一区二区在线观一 | 日韩高清一区二区三区不卡| 亚洲中文字幕无码一区| 日本精品少妇一区二区三区| 日韩免费一区二区三区在线| 国模私拍一区二区三区| 丝袜人妻一区二区三区网站| 日韩一区二区在线观看| 精品一区精品二区| 一区二区三区视频免费观看| 精品不卡一区中文字幕| 国产一区二区三区不卡在线看| 欧美日韩综合一区二区三区| 亚洲AV无码一区二区三区牛牛| 亚洲一区免费视频| 国产乱人伦精品一区二区| 国产乱人伦精品一区二区| 日韩毛片基地一区二区三区| 亚洲AV无码一区二区乱孑伦AS| 不卡一区二区在线| 国产精品一区二区av| 久久精品一区二区| 亚洲国产精品无码久久一区二区| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 亚洲综合av永久无码精品一区二区| 美女福利视频一区二区| 人妻无码一区二区三区| 亚洲av区一区二区三| 高清一区二区三区| 中文字幕一区二区三区永久| 国产高清不卡一区二区| 日韩最新视频一区二区三| 国产成人精品视频一区| 国产另类ts人妖一区二区三区 | 亚洲福利一区二区精品秒拍|