Vue
1.1 響應式系統
Vue 3 使用 Proxy
代替 Vue 2 中的 Object.defineProperty
來實現響應式系統。Proxy
可以監聽對象的所有操作,包括屬性的添加和刪除,從而解決了 Vue 2 的一些局限性。
Vue 2:使用 Vue.set
添加響應式屬性
new Vue({el: "#app",data: {obj: {},},created() {// 使用 Vue.set 添加一個新屬性Vue.set(this.obj, "newProp", "initial value");// 監聽新添加的屬性this.$watch("obj.newProp", function (newVal, oldVal) {console.log(`newProp changed from ${oldVal} to ${newVal}`);});},methods: {updateProp() {// 更新新添加的屬性this.obj.newProp = "updated value";},},
});
1.2 Vue 3 對比 Vue 2 的編譯優化
1. 靜態提升
Vue 3 的模板編譯器會將不變的部分(如 <button>
標簽的內容)提升為靜態節點,只在初次渲染時創建一次,后續渲染時直接處理,減少不必要的計算。
Vue 3:
const _hoisted_1 = /*#__PURE__*/ createVNode("button",{ onClick: updateMessage },"Update Message"
);function render(_ctx, _cache) {return (openBlock(),createBlock("div", null, [createVNode("p", null, toDisplayString(_ctx.message), 1 /* TEXT */),_hoisted_1,]));
}
Vue 2:
render: function(createElement) {return createElement('div', [createElement('p', this.message),createElement('button', { on: { click: this.updateMessage } }, 'Update Message')]);
}
2. 緩存事件處理函數
Vue 3 會緩存事件處理函數(如 updateMessage
),避免每次渲染時都重新創建新的函數。
Vue 3:
const _hoisted_1 = /*#__PURE__*/ createVNode("button",{onClick:_cache[1] ||(_cache[1] = (...args) => _ctx.handleClick && _ctx.handleClick(...args)),},"Click Me"
);function render(_ctx, _cache) {return openBlock(), createBlock("div", null, [_hoisted_1]);
}
Vue 2:
render: function(createElement) {return createElement('div', [createElement('button', { on: { click: this.handleClick } }, 'Click Me')]);
}
3. 優化指令
Vue 3 對 v-if
、v-for
等常用指令進行了優化,使得運行時的性能更高:
- 減少不必要的節點創建和銷毀(如
v-if
使用createCommentVNode
)。 - 高效的列表渲染(如
v-for
使用renderList
和openBlock
、createBlock
)。 - 優化屬性綁定(如
v-bind
使用對象展開操作和標志位)。
Vue 3 示例:
function render(_ctx, _cache) {return (openBlock(),createBlock("div", null, [_ctx.isVisible? (openBlock(), createBlock("p", { key: 0 }, "Visible")): createCommentVNode("v-if", true),(openBlock(true),createBlock(Fragment,null,renderList(_ctx.items, (item) => {return (openBlock(),createBlock("li",{key: item.id,title: item.title,},toDisplayString(item.name),9 /* TEXT, PROPS */,["title"]));}),128 /* KEYED_FRAGMENT */)),]));
}
- Fragments:Vue 3.0 支持組件返回多個根節點(Fragments),不再需要使用額外的包裹元素。
- Teleport:Teleport 允許將組件的 DOM 渲染到指定的 DOM 節點之外,提供了更靈活的布局方式。
es6
在 JavaScript 中,箭頭函數與傳統函數(使用 function
關鍵字定義的函數)有一些顯著的區別,其中之一就是箭頭函數沒有自己的 arguments
對象。
示例代碼
傳統函數
傳統函數可以訪問 arguments
對象,該對象包含了傳遞給函數的所有參數。
function traditionalFunction() {console.log(arguments);
}traditionalFunction(1, 2, 3); // 輸出: [Arguments] { '0': 1, '1': 2, '2': 3 }
箭頭函數
箭頭函數沒有自己的 arguments
對象。如果在箭頭函數中訪問 arguments
,它會從包含它的最近的非箭頭函數中獲取 arguments
。
const arrowFunction = () => {console.log(arguments);
};arrowFunction(1, 2, 3); // ReferenceError: arguments is not defined
解決方案
如果需要在箭頭函數中訪問參數,可以使用剩余參數語法(rest parameters)來代替 arguments
對象。
const arrowFunctionWithRest = (...args) => {console.log(args);
};arrowFunctionWithRest(1, 2, 3); // 輸出: [ 1, 2, 3 ]
手寫promise
function myPromise(executer) {let resolve, reject;this.thenCallbacks = [];this.catchCallback = null;this.then = (callback) => {this.thenCallbacks.push(callback);return this;};this.catch = (callback) => {this.catchCallback = callback;return this;};resolve = (value) => {setTimeout(() => {this.thenCallbacks.forEach((callback) => {value = callback(value);});}, 0);};reject = (reason) => {setTimeout(() => {if (this.catchCallback) {this.catchCallback(reason);}}, 0);};try {executer(resolve, reject);} catch (error) {reject(error);}
}
new myPromise((resolve, reject) => {setTimeout(() => {resolve("Hello, promise!");}, 1000);
}).then((value) => {console.log(value);return value + " Then 1";}).then((value) => {console.log(value);}).catch((error) => {console.log(error);});
柯里化
function curry(fn) {return function curried(...args) {if (args.length >= fn.length) {return fn.apply(this, args);} else {return function(...args2) {return curried.apply(this, args.concat(args2));}}};
}
SSR
SSR 的優點
- 更快的首屏加載速度:由于服務器預先生成了 HTML 內容,客戶端可以立即顯示頁面,而不需要等待 JavaScript 加載和執行。
- 更好的 SEO:搜索引擎爬蟲可以直接抓取到完整的 HTML 內容,從而更好地索引頁面。
- 更好的社交媒體分享效果:當頁面被分享時,社交媒體平臺可以抓取到完整的 HTML 內容,從而生成更豐富的預覽信息。
SSR 的缺點
- 服務器負載增加:服務器需要處理更多的渲染工作,可能會增加服務器的負載。
- 開發復雜度增加:SSR 需要處理更多的服務器端邏輯,開發和調試可能會更加復雜。
- 客戶端和服務器端代碼共享:需要確保客戶端和服務器端的代碼能夠正確地共享和執行,可能會增加代碼管理的復雜度。
Webpack
//常用webpack配置
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');module.exports = {entry: './src/main.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'bundle.js',// filename: '[name].[contenthash].js', // 使用 contenthash 生成文件指紋},cache: {type: 'filesystem', // 使用文件系統緩存cacheDirectory: path.resolve(__dirname, '.webpack_cache'), // 緩存目錄buildDependencies: {config: [__filename], // 當配置文件更改時使緩存失效},},module: {rules: [{test: /\.vue$/,loader: 'vue-loader',},{test: /\.js$/,loader: 'babel-loader',exclude: /node_modules/,},{test: /\.css$/,use: ['style-loader', 'css-loader'],},{test: /\.(png|svg|jpg|jpeg|gif)$/i,type: 'asset/resource',generator: {filename: 'images/[name].[contenthash][ext]', // 為靜態資源生成文件指紋},},],},resolve: {alias: {vue$: 'vue/dist/vue.esm.js',},extensions: ['*', '.js', '.vue', '.json'],},devServer: {contentBase: path.join(__dirname, 'public'),compress: true,port: 8080,},plugins: [new VueLoaderPlugin(),new webpack.PrefetchPlugin({context: path.resolve(__dirname, 'src'),request: './components/HeavyComponent.js',}),//PrefetchPlugin是Webpack提供的一個插件。用于預加載資源。預加載資源可以在瀏覽器空閑時提前加載將來可能會用到的資源,從而提高應用的性能和用戶體驗。// 使用 PrefetchPlugin// PrefetchPlugin 插件會在生成的 HTML 文件中插入 <link rel=“prefetch“> 標簽,以便瀏覽器在空閑時預加載資源。],
};## <font color=#ff0000 >Vite</font>//常用vite配置
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';export default defineConfig({root: process.cwd(), // 項目根目錄base: '/', // 公共基礎路徑mode: 'development', // 模式plugins: [vue(), // 使用 Vue 插件webpackLoaderPlugin({include: '**/*.scss',loaderOptions: {loader: 'sass-loader',options: {// sass-loader 選項},},}),],resolve: {alias: {'@': path.resolve(__dirname, 'src'), // 路徑別名},extensions: ['.js', '.vue', '.json'], // 自動解析的擴展名},css: {preprocessorOptions: {scss: {additionalData: `@import "@/styles/variables.scss";`, // 全局引入 SCSS 變量},},},json: {namedExports: true, // 支持命名導出stringify: false, // 禁用 JSON 字符串化},esbuild: {jsxFactory: 'h',jsxFragment: 'Fragment',},server: {port: 3000, // 開發服務器端口open: true, // 自動打開瀏覽器hmr: true, // 確保 HMR 已啟用proxy: {'/api': {target: 'http://localhost:4000',changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, ''),},},},build: {outDir: 'dist', // 輸出目錄sourcemap: true, // 生成 sourcemaprollupOptions: {input: {main: path.resolve(__dirname, 'index.html'),},treeshake: false, // 禁用 Tree Shaking},},optimizeDeps: {include: ['vue', 'vue-router'], // 強制預構建的依賴},define: {'process.env.NODE_ENV': JSON.stringify('development'), // 定義全局常量},
});
代碼分割
// 代碼分割// - `app` 入口點包含應用程序的代碼。
// - `splitChunks` 配置選項用于控制代碼分割的行為。
// - `chunks: 'all'`:對所有類型的代碼進行分割,包括同步和異步代碼。
// - `minSize` 和 `maxSize`:控制模塊的最小和最大大小。
// - `minChunks`:控制模塊的最小引用次數。
// - `maxAsyncRequests` 和 `maxInitialRequests`:控制最大并行請求數。
// - `automaticNameDelimiter`:控制生成文件名的分隔符。
// - `name`:控制是否自動生成名稱。
// - `cacheGroups`:定義緩存組,用于控制哪些模塊應該被提取到單獨的文件中。
// - `vendors` 緩存組:將 node_modules 目錄中的模塊提取到 `vendors` 文件中。
// - `default` 緩存組:將引用次數大于等于 2 的模塊提取到默認文件中,并復用已經存在的塊。const path = require("path");module.exports = {entry: {app: "./src/app.js",},output: {filename: "[name].bundle.js",path: path.resolve(__dirname, "dist"),},optimization: {splitChunks: {chunks: "all", // 對所有類型的代碼進行分割minSize: 30000, // 模塊的最小大小maxSize: 0, // 模塊的最大大小,0 表示不限制minChunks: 1, // 模塊的最小引用次數maxAsyncRequests: 5, // 按需加載時的最大并行請求數maxInitialRequests: 3, // 入口點的最大并行請求數automaticNameDelimiter: "~", // 文件名分隔符name: true, // 自動生成名稱cacheGroups: {vendors: {test: /[\\/]node_modules[\\/]/,priority: -10, // 優先級name: "vendors", // 提取到的文件名},default: {minChunks: 2,priority: -20,reuseExistingChunk: true, // 復用已經存在的塊},},},},
};
React
useRef
是 React 中的一個 Hook,用于創建一個可變的引用對象。這個引用對象在組件的整個生命周期內保持不變。useRef
常用于以下幾種情況:
- 訪問 DOM 元素:可以通過
useRef
獲取和操作 DOM 元素。 - 存儲可變值:可以存儲任何可變值,而不會觸發組件重新渲染。
總結
useState
:狀態變化會觸發組件重新渲染。useRef
:ref
對象的.current
屬性變化不會觸發組件重新渲染。- 使用
useRef
可以存儲和訪問可變值,而不會影響組件的渲染性能。這在需要頻繁更新但不需要重新渲染的情況下非常有用。
網絡協議
HTTP 建立過程包括以下幾個主要步驟:
- DNS 解析:將域名解析為 IP 地址。
- 建立 TCP 連接:通過三次握手建立客戶端和服務器之間的 TCP 連接。
- 發送 HTTP 請求:瀏覽器向服務器發送 HTTP 請求。
- 服務器處理請求并返回響應:服務器處理請求并返回 HTTP 響應。
- 瀏覽器渲染頁面:瀏覽器解析響應并渲染頁面。
- 關閉連接:在 HTTP/1.1 中,使用持久連接,可以在一個連接上發送多個請求/響應對。
CDN 的作用總結
- 加速內容傳輸:通過將內容分發到多個地理位置的服務器上,CDN 可以顯著減少內容傳輸的延遲,提高用戶訪問速度。
- 減輕服務器負載:CDN 邊緣服務器緩存內容,減少了對原始服務器的請求次數,從而減輕了原始服務器的負載。
- 提高可用性和可靠性:CDN 提供了冗余和負載均衡,確保即使某些服務器出現故障,內容仍然可以從其他服務器獲取。
- 優化帶寬使用:通過緩存和壓縮技術,CDN 可以優化帶寬使用,降低傳輸成本。
瀏覽器緩存
瀏覽器緩存是指瀏覽器將請求的資源(如 HTML、CSS、JavaScript、圖片等)存儲在本地,以便在后續請求中直接使用緩存的資源,從而減少網絡請求,提高頁面加載速度。瀏覽器緩存機制是前端性能優化的重要手段之一。下面詳細解釋瀏覽器緩存的工作原理、緩存策略和常見的緩存控制方法。
瀏覽器緩存策略主要分為兩類:強緩存和協商緩存。
1. 強緩存(Strong Caching)
強緩存是指瀏覽器在緩存有效期內直接使用緩存的資源,而不向服務器發送請求。強緩存通過 Cache-Control
和 Expires
頭部字段控制。
- Cache-Control:是 HTTP/1.1 中定義的頭部字段,用于指定緩存策略。常見的指令包括:
max-age=<seconds>
:指定資源的最大緩存時間(以秒為單位)。no-cache
:強制瀏覽器在使用緩存前向服務器驗證資源的有效性。no-store
:禁止緩存,瀏覽器每次請求都必須從服務器獲取資源。- public:資源可以被任何緩存(如瀏覽器、CDN)緩存。
private
:資源只能被瀏覽器緩存,不能被共享緩存(如 CDN)緩存。
- Expires:是 HTTP/1.0 中定義的頭部字段,用于指定資源的過期時間(絕對時間)。如果
Cache-Control
和Expires
同時存在,Cache-Control
優先級更高。
2. 協商緩存(Conditional Caching)
協商緩存是指瀏覽器在緩存過期后向服務器發送請求,驗證資源的有效性。如果資源未修改,服務器返回 304 狀態碼,瀏覽器繼續使用緩存的資源。協商緩存通過 ETag
和 Last-Modified
頭部字段控制。
- ETag:是資源的唯一標識符(通常是哈希值)。瀏覽器在請求資源時會發送
If-None-Match
頭部字段,服務器根據ETag
判斷資源是否修改。 - Last-Modified:是資源的最后修改時間。瀏覽器在請求資源時會發送
If-Modified-Since
頭部字段,服務器根據Last-Modified
判斷資源是否修改。
緩存策略示例
以下是一些常見的緩存策略示例:
1. 靜態資源緩存
對于不經常變化的靜態資源(如圖片、CSS、JavaScript 文件),可以設置較長的緩存時間:
Cache-Control: max-age=31536000, public
2. 動態資源緩存
對于經常變化的動態資源,可以使用協商緩存:
Cache-Control: no-cache
ETag: "5d8c72a5edda8"
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://example.com/api/data", true);
xhr.setRequestHeader("X-Custom-Header", "CustomHeaderValue");
xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {console.log(xhr.responseText);}
};import $ from "jquery";
$.ajax({url: "https://example.com/api/data",method: "GET",headers: {"X-Custom-Header": "CustomHeaderValue",},success: function (data) {console.log(data);},error: function (error) {console.error("Error:", error);},
});fetch("https://example.com/api/data", {method: "GET",headers: {"X-Custom-Header": "CustomHeaderValue",},
});
axios.get("https://example.com/api/data", {headers: {"X-Custom-Header": "CustomHeaderValue",},
});
圖片懶加載
是一種優化技術,通過延遲加載圖片資源,可以減少初始加載時間,提高頁面加載速度和用戶體驗。可以使用 HTML5 的 loading
屬性或 JavaScript 和 Intersection Observer API 來實現圖片懶加載。懶加載的基本原理是延遲加載資源,直到資源進入視口或接近視口時才開始加載。通過合理使用懶加載,可以顯著優化 Web 應用的性能和用戶體驗。
<imgsrc="path/to/image.jpg"alt="Description"loading="lazy"
/>
<script>document.addEventListener("DOMContentLoaded", function () {const lazyImages = document.querySelectorAll(".placeholder");const observer = new IntersectionObserver((entries, observer) => {entries.forEach((entry) => {if (entry.isIntersecting) {const img = document.createElement("img");img.src = entry.target.getAttribute("data-src");img.alt = "Lazy loaded image";entry.target.appendChild(img);observer.unobserve(entry.target);}});});lazyImages.forEach((image) => {observer.observe(image);});});
</script>
前端網絡安全性
1. 跨站腳本攻擊(XSS)
解釋
跨站腳本攻擊(XSS,Cross-Site Scripting)是指攻擊者在網頁中注入惡意腳本,當用戶訪問該網頁時,惡意腳本會在用戶的瀏覽器中執行,從而竊取用戶信息或執行其他惡意操作。
防范措施
- 輸入驗證:對用戶輸入進行嚴格的驗證和過濾,防止惡意腳本注入。
- 輸出編碼:對輸出到網頁的內容進行編碼,防止惡意腳本執行。可以使用庫如 DOMPurify 來清理用戶輸入。
<script>document.getElementById('commentForm').addEventListener('submit', function(event) {event.preventDefault();const comment = document.getElementById('comment').value;const sanitizedComment = DOMPurify.sanitize(comment);const commentDiv = document.createElement('div');commentDiv.innerHTML = sanitizedComment;document.getElementById('comments').appendChild(commentDiv);}); </script>
- 使用 CSP(內容安全策略):通過設置 Content Security Policy 頭部,限制網頁中可以執行的腳本來源。
-
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com
-
CSP 頭部通過 `Content-Security-Policy` 頭部字段來設置,格式如下:```http
Content-Security-Policy: <directive> <source-list>; <directive> <source-list>; ...
-
directive:指令,用于指定要限制的資源類型。
-
source-list:來源列表,用于指定允許加載資源的來源。
-
default-src:默認資源來源,適用于所有未單獨指定來源的資源類型。
-
script-src:腳本來源,限制可以執行的 JavaScript 代碼的來源。
-
style-src:樣式來源,限制可以應用的 CSS 樣式的來源。
-
img-src:圖片來源,限制可以加載的圖片的來源。
-
font-src:字體來源,限制可以加載的字體的來源。
-
connect-src:連接來源,限制可以發起的網絡請求的來源(如 AJAX、WebSocket)。
-
media-src:媒體來源,限制可以加載的音頻和視頻的來源。
-
object-src:對象來源,限制可以加載的插件內容(如 Flash、Java Applet)。
-
frame-src:框架來源,限制可以嵌入的框架和 iframe 的來源。
-
base-uri:限制
<base>
標簽的來源。 -
form-action:限制可以提交表單的 URL。
-
‘self’:表示同源,即與當前頁面相同的來源。
-
‘none’:表示不允許加載任何資源。
-
‘unsafe-inline’:允許內聯資源(如內聯的
<script>
和<style>
),不推薦使用。 -
‘unsafe-eval’:允許使用
eval()
和類似的方法,不推薦使用。 -
URL:指定具體的 URL 或域名。
-
data::允許
data:
協議的資源。 -
https::允許 HTTPS 協議的資源。
2. 跨站請求偽造(CSRF)
解釋
跨站請求偽造(CSRF,Cross-Site Request Forgery)是指攻擊者誘導用戶在已登錄的情況下執行未授權的操作。攻擊者通常會構造惡意請求,并通過用戶的瀏覽器發送到受信任的網站。
例如
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title>Malicious Site</title></head><body><h1>Welcome to the Malicious Site</h1><imgsrc="http://localhost:3000/change-email?email=attacker@example.com"style="display:none;"/></body>
</html>
防范措施
- 使用 CSRF 令牌:在每個表單或請求中包含一個唯一的 CSRF 令牌,服務器驗證令牌的有效性。
- 驗證 Referer 頭部:檢查請求的 Referer 頭部,確保請求來源于受信任的頁面。
- 使用 SameSite Cookie 屬性:設置 Cookie 的 SameSite 屬性,限制跨站請求攜帶 Cookie。
示例:設置 SameSite Cookie 屬性
Set-Cookie: sessionid=abc123; SameSite=Strict
SameSite
屬性有三個可選值:
- Strict:嚴格模式,完全禁止跨站請求攜帶 Cookie。只有在同一站點的請求中,Cookie 才會被發送。
- Lax:寬松模式,允許部分跨站請求攜帶 Cookie,但限制條件較嚴格。通常用于導航請求(如鏈接點擊)和頂級導航(如表單提交)。
- None:不限制跨站請求,允許所有跨站請求攜帶 Cookie。需要同時設置
Secure
屬性,確保 Cookie 僅通過 HTTPS 傳輸。
const express = require("express");
const cookieParser = require("cookie-parser");const app = express();
app.use(cookieParser());app.get("/", (req, res) => {res.cookie("sessionid", "abc123", { sameSite: "Strict" });res.send("<h1>SameSite Cookie Example</h1>");
});app.listen(3000, () => {console.log("Server is running on http://localhost:3000");
});
3. 點擊劫持(Clickjacking)
解釋
點擊劫持(Clickjacking)是指攻擊者通過在透明的 iframe 中嵌入受害者網站,并誘導用戶點擊,從而執行未授權的操作。
防范措施
- 使用 X-Frame-Options 頭部:通過設置 X-Frame-Options 頭部,防止網頁被嵌入到 iframe 中。
- 使用 CSP:通過設置 Content Security Policy 頭部,限制網頁可以嵌入的框架來源。
示例:設置 X-Frame-Options 頭部
X-Frame-Options: DENY
X-Frame-Options
頭部有三個可選值:
- DENY:完全禁止頁面在任何框架中加載。
- SAMEORIGIN:允許頁面在相同來源的框架中加載。
- ALLOW-FROM uri:允許頁面在指定的來源的框架中加載(注意:此選項在現代瀏覽器中已被棄用,建議使用 CSP 代替)。
4. 不安全的依賴
解釋
使用不安全的第三方庫或依賴可能導致安全漏洞,攻擊者可以利用這些漏洞進行攻擊。
防范措施
- 定期更新依賴:保持依賴庫的最新版本,修復已知的安全漏洞。
- 使用安全掃描工具:使用工具如 npm audit、Snyk 等掃描依賴庫的安全性。
5. 數據泄露
解釋
數據泄露是指敏感數據(如用戶信息、密碼等)被未授權訪問或泄露。
防范措施
- 加密敏感數據:在傳輸和存儲敏感數據時使用加密技術,如 HTTPS、AES 等。
- 最小權限原則:限制用戶和應用程序的權限,確保只有必要的權限才能訪問敏感數據。
- 使用安全存儲:在客戶端使用安全的存儲機制,如 Web Storage、IndexedDB 等。
6. 安全的身份驗證和授權
解釋
確保用戶身份驗證和授權機制的安全性,防止未授權訪問和操作。
防范措施
- 使用強密碼策略:要求用戶設置強密碼,并定期更換密碼。
- 多因素認證(MFA):使用多因素認證提高身份驗證的安全性。
- 使用 OAuth 2.0 和 OpenID Connect:使用標準的身份驗證和授權協議,確保安全性。
7. 安全的 API 調用
解釋
確保前端與后端 API 調用的安全性,防止數據泄露和未授權訪問。
防范措施
- 使用 HTTPS:確保所有 API 調用使用 HTTPS 加密傳輸。
- 驗證 API 請求:在服務器端驗證所有 API 請求的合法性。
- 使用 API 密鑰和令牌:使用 API 密鑰和令牌進行身份驗證和授權。