引言
这篇文章整合了28个前端高频考题,篇幅较长,可以根据目录自行跳转。🚀
一、图片懒加载
1. 概念
图片懒加载是一种优化网页性能的技术,它可以让图片在即将出现在视口(viewport)时才加载,而不是在页面加载时一次性加载所有图片。这样可以减少页面初始加载时间,提高性能。
2. 实现方式
方法 1:使用 loading="lazy"
(原生方式)
HTML5 提供了 loading="lazy"
属性,浏览器会自动处理懒加载:
ini
<img src="image.jpg" loading="lazy" alt="Lazy Loaded Image">
方法 2:使用 Intersection Observer API
适用于需要兼容更多浏览器的情况:
ini
const images = document.querySelectorAll("img[data-src]");
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute("data-src");
observer.unobserve(img);
}
});
});
images.forEach(img => observer.observe(img));
在 HTML 中:
ini
<img data-src="image.jpg" alt="Lazy Loaded Image">
二、大文件上传
1. 问题
直接上传大文件可能导致:
- 超时问题:网络不好时可能导致上传失败。
- 服务器压力大:大文件占用带宽,影响并发请求。
- 断点续传:如果中途断网,重新上传会很耗费时间。
2. 解决方案
- 分片上传:把大文件拆分成小块(chunk),逐个上传到服务器。
- 断点续传:记录已上传的部分,断线后继续上传。
3. 实现
前端代码(分片上传 + 断点续传) :
ini
async function uploadFile(file) {
const chunkSize = 5 * 1024 * 1024; // 5MB
const chunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const end = start + chunkSize;
const chunk = file.slice(start, end);
const formData = new FormData();
formData.append("file", chunk);
formData.append("index", i);
formData.append("total", chunks);
await fetch("/upload", { method: "POST", body: formData });
}
}
后端(Node.js 示例) :
ini
const fs = require('fs');
const express = require('express');
const app = express();
app.use(express.json());
app.post('/upload', (req, res) => {
const { file, index, total } = req.body;
fs.appendFileSync(`./uploads/file_${index}`, file);
res.send({ status: "ok" });
});
app.listen(3000);
三、异步操作
1. 同步 vs. 异步
- 同步:代码按顺序执行,阻塞后续操作。
- 异步 :不会阻塞主线程,比如
setTimeout
、fetch
、Promise
。
2. Promise & async/await
Promise 示例
javascript
function fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve("数据加载完成"), 2000);
});
}
fetchData().then(console.log); // 2秒后打印 "数据加载完成"
async/await
ini
async function fetchData() {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
}
fetchData();
四、axios(HTTP 请求库)
1. axios vs fetch
特性 | axios | fetch |
---|---|---|
自动 JSON 解析 | ✅ | ❌ 需 response.json() |
拦截器 | ✅ | ❌ |
超时控制 | ✅ | ❌ |
取消请求 | ✅ | ❌ |
2. 基本使用
javascript
import axios from "axios";
axios.get("https://api.example.com/data")
.then(response => console.log(response.data))
.catch(error => console.error(error));
3. 拦截器
ini
axios.interceptors.request.use(config => {
config.headers.Authorization = "Bearer token";
return config;
});
五、闭包
1. 定义
闭包是指函数可以访问其外部作用域的变量,即使函数在外部作用域执行。
2. 示例
scss
function outer() {
let count = 0; // 外部变量
return function inner() {
count++;
console.log(count);
};
}
const counter = outer();
counter(); // 1
counter(); // 2
3. 应用场景
- 数据缓存:避免全局变量污染。
- 实现私有变量:防止变量被外部修改。
- 事件监听:封装逻辑,使代码更清晰。
六、防抖与节流
1. 防抖
定义 :防抖是指短时间内多次触发同一事件时,只有最后一次生效 。常用于搜索框输入、窗口大小调整 等场景。
实现:
javascript
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 示例:搜索输入框
const searchInput = document.getElementById("search");
searchInput.addEventListener("input", debounce((e) => {
console.log("搜索内容:", e.target.value);
}, 500));
2. 节流
定义 :节流是指在一定时间间隔内,只执行一次事件 ,即使它被多次触发。常用于滚动事件、按钮点击 等场景。
实现:
javascript
function throttle(fn, delay) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
}
};
}
// 示例:监听页面滚动
window.addEventListener("scroll", throttle(() => {
console.log("滚动事件触发");
}, 1000));
七、跨域、同源策略和CORS
1. 什么是同源策略?
同源策略(Same-Origin Policy,SOP)是浏览器的一种安全机制,限制不同源的网页互相访问数据 ,避免恶意网站窃取信息。同源 指协议、域名、端口三者必须一致。
2. 解决跨域的方法
-
CORS(跨域资源共享) (推荐)
服务端 返回Access-Control-Allow-Origin
头部:javascriptapp.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE"); res.header("Access-Control-Allow-Headers", "Content-Type, Authorization"); next(); });
-
JSONP(仅支持 GET)
xml<script src="https://api.example.com/data?callback=handleData"></script>
javascriptfunction handleData(data) { console.log(data); }
-
代理服务器(Nginx/Node.js 代理)
php// Node.js 代理 const { createProxyMiddleware } = require("http-proxy-middleware"); app.use("/api", createProxyMiddleware({ target: "https://example.com", changeOrigin: true }));
八、事件循环(Event Loop)
1. JavaScript 是单线程的
JavaScript 采用事件循环机制来处理异步任务,避免主线程被阻塞。
2. 事件循环执行顺序
- 同步代码 先执行。
- 微任务队列(Microtask Queue) (优先):
Promise.then
、process.nextTick
- 宏任务队列(Macrotask Queue) :
setTimeout
、setInterval
、setImmediate
、I/O
3. 示例
javascript
console.log("1"); // 同步任务
setTimeout(() => console.log("2"), 0); // 宏任务
Promise.resolve().then(() => console.log("3")); // 微任务
console.log("4");
执行顺序:1 → 4 → 3 → 2
九、拦截器
拦截器一般用于请求和响应的统一处理 ,例如添加 Token、全局错误处理等。
在 axios 中使用拦截器
ini
import axios from "axios";
// 请求拦截器
axios.interceptors.request.use(config => {
config.headers.Authorization = "Bearer token"; // 添加 Token
return config;
}, error => Promise.reject(error));
// 响应拦截器
axios.interceptors.response.use(response => {
return response.data; // 统一处理响应数据
}, error => {
console.error("请求失败", error);
return Promise.reject(error);
});
应用场景:
- 自动添加 Token
- 处理请求失败
- 统一解析数据格式
十、项目部署上线流程
1. 前端项目部署步骤
-
打包构建
arduinonpm run build
-
上传到服务器
-
方式 1:FTP(FileZilla)
-
方式 2:SSH(SCP 命令)
rubyscp -r dist/ user@server:/var/www/html
-
-
服务器配置
-
Nginx 配置:
iniserver { listen 80; server_name example.com; root /var/www/html; index index.html; }
-
启动 Nginx:
sudo systemctl restart nginx
-
2. Node.js 项目部署
-
上传代码
rubyscp -r myapp/ user@server:/home/user/
-
安装依赖
cssnpm install --production
-
使用 PM2 进程管理
sqlnpm install -g pm2 pm2 start app.js pm2 save pm2 startup
3. Docker 部署
-
创建
Dockerfile
sqlFROM node:18 WORKDIR /app COPY . . RUN npm install CMD ["node", "app.js"]
-
构建并运行
arduinodocker build -t myapp . docker run -d -p 3000:3000 myapp
十一、Promise
1. 什么是 Promise?
Promise 是 JavaScript 中用于处理异步操作的对象,它有三种状态:
- pending(进行中) :初始状态,异步操作未完成。
- fulfilled(已完成) :异步操作成功,调用
.then()
。 - rejected(已失败) :异步操作失败,调用
.catch()
。
2. Promise 的基本用法
javascript
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => resolve("成功"), 2000);
});
myPromise.then(data => console.log(data)).catch(err => console.log(err));
3. Promise 链式调用
ini
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("请求失败", error));
4. async/await 语法(更简洁的 Promise 处理方式)
javascript
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
} catch (error) {
console.error("请求失败", error);
}
}
fetchData();
十二、虚拟 DOM
1. 什么是虚拟 DOM?
虚拟 DOM 是 React、Vue 等前端框架 中的轻量级 JavaScript 对象,它是对真实 DOM 的模拟,避免直接操作 DOM,提高性能。
2. 传统 DOM vs. 虚拟 DOM
特性 | 传统 DOM | 虚拟 DOM |
---|---|---|
直接操作 | 直接修改真实 DOM | 先修改 Virtual DOM,再 diff 对比 |
速度 | 变更多时性能较差 | 变更多时性能较优 |
适用于 | 低频更新 | 高频更新的页面(如 React、Vue) |
3. 虚拟 DOM 的核心机制
- 创建 Virtual DOM:用 JavaScript 对象模拟 DOM 结构。
- Diff 算法:对比新旧 Virtual DOM,找出变化部分。
- 批量更新:只更新变更的部分,提高效率。
ini
const App = () => {
const [count, setCount] = React.useState(0);
return <button onClick={() => setCount(count + 1)}>点击 {count} 次</button>;
};
当 count
变化时:
- 生成新的 Virtual DOM。
- 旧 Virtual DOM 对比新 Virtual DOM(Diff)。
- 只更新变化的部分,减少 DOM 操作。
十三、JSONP
1. 什么是 JSONP?
JSONP(JSON with Padding)是一种利用 <script>
标签 绕过同源策略的方式,只支持 GET
请求。
2. JSONP 实现原理
前端代码:
xml
<script>
function handleData(data) {
console.log("后端返回的数据:", data);
}
</script>
<script src="https://api.example.com/data?callback=handleData"></script>
后端返回数据(JSONP 格式) :
php
handleData({ name: "张三", age: 18 });
缺点:
- 仅支持
GET
请求,不支持POST
、PUT
等。 - 不如
CORS
灵活,现代项目推荐使用CORS
。
十四、注册登录的逻辑
1. 注册逻辑
-
前端 :用户输入用户名、密码 → 校验格式 → 发送
POST
请求。 -
后端:
- 检查用户名是否已存在。
- 对密码进行加密存储 (如
bcrypt
)。 - 生成用户 ID,并存入数据库。
-
返回注册成功信息。
前端代码(React 示例) :
javascript
async function register(username, password) {
const response = await fetch("/api/register", {
method: "POST",
body: JSON.stringify({ username, password }),
headers: { "Content-Type": "application/json" }
});
const data = await response.json();
console.log(data);
}
2. 登录逻辑
-
前端 :用户输入用户名、密码 → 发送
POST
请求。 -
后端:
- 查询数据库,检查用户名是否存在。
- 对比用户输入的密码与数据库中的加密密码。
- 生成
JWT
(JSON Web Token)并返回。
-
前端存储 Token(localStorage/sessionStorage) 。
后端(Node.js + Express 示例) :
ini
const jwt = require("jsonwebtoken");
app.post("/login", async (req, res) => {
const { username, password } = req.body;
const user = await db.findUser(username);
if (!user || !bcrypt.compareSync(password, user.password)) {
return res.status(401).json({ message: "用户名或密码错误" });
}
const token = jwt.sign({ userId: user.id }, "secret_key", { expiresIn: "1h" });
res.json({ token });
});
十五、SSR、CSR、SSG
渲染模式 | 定义 | 适用场景 |
---|---|---|
CSR(客户端渲染) | 浏览器下载 JS 后渲染页面 | 交互性强的 SPA(单页应用) |
SSR(服务器端渲染) | HTML 由服务器渲染并返回 | SEO 友好、首屏加载快 |
SSG(静态生成) | 构建时生成 HTML,直接部署 | 文章、博客、营销页 |
1. CSR(Client-Side Rendering)
- 流程:HTML 仅包含基本结构 → 加载 JavaScript → 通过 React/Vue 渲染页面。
- 优点:前端交互流畅,适用于 SPA 应用。
- 缺点:首屏加载较慢,SEO 不友好。
示例(React 前端渲染):
ini
const App = () => {
const [data, setData] = React.useState(null);
React.useEffect(() => {
fetch("/api/data").then(res => res.json()).then(setData);
}, []);
return <div>{data ? data.title : "加载中..."}</div>;
};
2. SSR(Server-Side Rendering)
- 流程:服务器渲染 HTML 并返回,前端仅增强交互。
- 优点 :SEO 友好,首屏加载快。
- 缺点:服务器压力大,不适合高频交互。
示例(Next.js SSR):
javascript
export async function getServerSideProps() {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
return { props: { data } };
}
const Page = ({ data }) => <div>{data.title}</div>;
export default Page;
3. SSG(Static Site Generation)
- 流程:构建时生成静态 HTML,访问时直接返回。
- 优点 :性能好,适用于博客、文档等页面。
- 缺点:不适用于频繁更新的数据。
示例(Next.js SSG):
javascript
export async function getStaticProps() {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
return { props: { data } };
}
const Page = ({ data }) => <div>{data.title}</div>;
export default Page;
十六、RAG(Retrieval-Augmented Generation)
1. 什么是 RAG?
RAG(检索增强生成)是一种结合信息检索(Retrieval)和 生成式 AI(Generation)的技术。它的核心思想是先检索相关数据,再生成文本,以提高模型的回答准确性。
2. RAG 的工作流程
- 用户输入问题(Query)。
- 检索系统(Retriever)查找相关信息,通常从数据库、知识库或向量索引中检索数据。
- 生成模型(Generator)结合检索到的信息,生成最终回答。
3. RAG 的应用
- 智能问答系统(如 AI 客服、法律咨询)。
- 代码自动补全(基于已有代码片段生成新代码)。
- 文档摘要(提取关键信息并生成总结)。
十七、私域
1. 什么是私域?
私域流量 是指企业可以自由掌控 的用户流量,如微信公众号、企业微信群、小程序、CRM 用户库等,相比于公域流量(如搜索引擎、广告流量),私域流量更稳定且转化率更高。
2. 私域流量的优势
- 降低营销成本:不依赖广告投放,复购率高。
- 用户忠诚度高:企业可以直接与用户互动,提高品牌粘性。
- 精准营销:通过用户数据分析,实现个性化推荐。
3. 私域流量的运营方式
- 建立私域平台(微信群、公众号、小程序)。
- 提供专属服务(社群互动、福利、会员折扣)。
- 数据驱动营销(通过用户行为分析,提供个性化内容)。
十八、双 Token
1. 为什么需要双 Token?
- Access Token:短时间有效,用于快速验证用户身份,减少数据库查询压力。
- Refresh Token :用于获取新的
Access Token
,避免频繁登录。
2. 双 Token 认证流程
- 用户登录后,服务器返回
Access Token
和Refresh Token
。 - 前端请求 API 时 ,携带
Access Token
。 - 如果
Access Token
过期 ,前端使用Refresh Token
请求新的Access Token
。 - 如果
Refresh Token
也过期,要求用户重新登录。
3. 代码示例
后端(Node.js + Express)
ini
const jwt = require("jsonwebtoken");
app.post("/refresh-token", (req, res) => {
const { refreshToken } = req.body;
try {
const payload = jwt.verify(refreshToken, "refresh_secret");
const newAccessToken = jwt.sign({ userId: payload.userId }, "access_secret", { expiresIn: "15m" });
res.json({ accessToken: newAccessToken });
} catch (error) {
res.status(401).json({ message: "Token 失效" });
}
});
十九、打包工具:Vite 和 Webpack
1. Webpack
-
特点:
- 支持 模块打包(JS、CSS、图片等)。
- Tree Shaking(去除无用代码)。
- 需要复杂的 配置文件(webpack.config.js) 。
-
适用场景:适用于大型项目,插件生态丰富。
2. Vite
-
特点:
- 基于 ESModules,启动快(不需要预打包)。
- HMR(热更新)更快。
- 默认使用 Rollup 进行生产环境打包。
-
适用场景:适用于现代前端框架(Vue、React)。
3. Webpack vs. Vite
特性 | Webpack | Vite |
---|---|---|
启动速度 | 慢(构建整个项目) | 快(ESModules + 按需加载) |
HMR(热更新) | 依赖打包 | 更快 |
适用场景 | 传统项目、大型应用 | 现代前端(Vue、React) |
示例:Vite 快速启动 Vue 项目
perl
npm create vite@latest my-vue-app --template vue
cd my-vue-app
npm install
npm run dev
二十、TypeScript(TS)
1. 什么是 TypeScript?
TypeScript(TS)是 JavaScript 的超集,添加了静态类型检查,让代码更安全、更可维护。
2. TypeScript 的主要特性
- 静态类型 (
number
,string
,boolean
) - 接口(Interface)
- 泛型(Generics)
- 类型推导
- 强大的 IDE 提示
3. 基本用法
typescript
// 定义变量
let username: string = "张三";
let age: number = 25;
// 接口
interface User {
name: string;
age: number;
}
const user: User = { name: "李四", age: 30 };
// 函数类型
function greet(user: User): string {
return `你好, ${user.name}`;
}
4. TypeScript 与 JavaScript 的区别
特性 | JavaScript | TypeScript |
---|---|---|
类型检查 | 动态类型(运行时报错) | 静态类型(编译时报错) |
可维护性 | 适合小型项目 | 适合大型项目 |
开发体验 | 依赖文档 | 强类型支持 |
5. TypeScript 适用于哪些场景?
- 大型项目(多人协作时,减少错误)。
- React/Vue 组件开发。
- Node.js 后端开发(如 NestJS)。
二十一、路由守卫
1. 什么是路由守卫?
路由守卫是前端框架(如 Vue Router、React Router)提供的拦截路由跳转 的机制,通常用于权限校验 、登录验证等场景。
2. Vue Router 路由守卫
- 全局前置守卫(beforeEach) :进入某个路由前触发。
- 全局后置守卫(afterEach) :进入路由后触发。
- 组件内守卫(beforeRouteEnter) :在组件加载前执行。
javascript
// Vue Router 全局前置守卫
router.beforeEach((to, from, next) => {
const isAuthenticated = !!localStorage.getItem("token");
if (to.meta.requiresAuth && !isAuthenticated) {
next("/login"); // 未登录跳转到登录页
} else {
next(); // 允许访问
}
});
3. React Router 路由守卫
javascript
import { Navigate } from "react-router-dom";
const PrivateRoute = ({ children }) => {
const isAuthenticated = !!localStorage.getItem("token");
return isAuthenticated ? children : <Navigate to="/login" />;
};
// 使用 PrivateRoute 保护页面
<Route path="/dashboard" element={<PrivateRoute><Dashboard /></PrivateRoute>} />
二十二、输入 URL 到页面渲染的整个流程
-
DNS 解析 :将
www.example.com
解析为 IP 地址。 -
TCP 连接 :使用
TCP 三次握手
连接服务器。 -
发送 HTTP 请求 :浏览器向服务器发送
GET
请求。 -
服务器处理请求:后端查询数据库,返回 HTML/CSS/JS。
-
浏览器解析 HTML:
- 解析 HTML,构建 DOM 树。
- 解析 CSS,构建 CSSOM 树。
- 解析 JS,执行脚本(可能会阻塞)。
-
构建 Render Tree:结合 DOM 树和 CSSOM 生成渲染树。
-
布局(Layout) :计算元素的大小和位置。
-
绘制(Painting) :像素渲染并显示到屏幕。
二十三、History 和 HashHistory
1. Hash 路由(HashHistory)
- 使用 URL 中的
#
(如http://example.com/#/home
)。 - 变化不会触发 HTTP 请求,适用于单页应用(SPA) 。
javascript
window.addEventListener("hashchange", () => {
console.log("Hash 改变了", location.hash);
});
2. History 路由(History API)
- 通过
pushState()
和replaceState()
修改 URL,不依赖#
。 - 需要服务器支持,否则刷新会返回 404。
javascript
history.pushState({}, "", "/newpage");
window.onpopstate = () => console.log("浏览器后退/前进");
方式 | 适用场景 | 特点 |
---|---|---|
HashHistory | 旧浏览器兼容 | URL 有 # ,不会请求服务器 |
History API | 现代应用 | 需要后端配置,URL 更简洁 |
二十四、DNS(Domain Name System)
1. DNS 解析流程
-
浏览器缓存:检查是否已有域名的 IP 解析记录。
-
系统缓存:查询操作系统的 DNS 解析缓存。
-
本地 DNS 服务器(ISP 提供)查询记录。
-
递归查询:
- 根 DNS 服务器 (返回
.com
顶级域名服务器)。 - 顶级域名(TLD)服务器 (返回
example.com
的权威 DNS 服务器)。 - 权威 DNS 服务器 (返回
www.example.com
的真实 IP)。
- 根 DNS 服务器 (返回
-
返回 IP 地址,浏览器使用该 IP 访问网站。
2. DNS 解析的优化
-
DNS 预解析(DNS Prefetch)
ini<link rel="dns-prefetch" href="//cdn.example.com">
-
CDN 加速(分布式 DNS 提供就近解析)。
-
减少 DNS 查询次数(合并域名,避免多次查询)。
二十五、原型和原型链
1. 原型链的工作原理
当访问对象的某个属性或方法时:
- 先在对象自身查找该属性。
- 如果找不到,则沿着
prototype
继续向上查找其原型对象。 - 依次查找,直到找到该属性,或者查找到
null
终止(说明属性不存在)。
示例代码:
javascript
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function () {
console.log(`Hello, my name is ${this.name}`);
};
const p1 = new Person("Alice");
p1.sayHello(); // "Hello, my name is Alice"
console.log(Object.getPrototypeOf(p1) === Person.prototype); // true
console.log(Object.getPrototypeOf(Person.prototype) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype) === null); // true
其原型链结构如下:
javascript
p1 --> Person.prototype --> Object.prototype --> null
2. __proto__
的废弃及替代方案
过去,__proto__
被用于访问对象的原型,例如:
ini
console.log(p1.__proto__ === Person.prototype); // true
但 __proto__
不是标准的一部分,已被 废弃(deprecated) 。ES6 提供了更好的替代方案:
- 获取原型 :
Object.getPrototypeOf(obj)
- 设置原型 :
Object.setPrototypeOf(obj, prototype)
推荐的做法:
javascript
console.log(Object.getPrototypeOf(p1) === Person.prototype); // 推荐方式
尽管 __proto__
仍然在现代浏览器中保留以实现兼容性,但在新的代码中建议使用 Object.getPrototypeOf
代替,以符合现代 JavaScript 的最佳实践。
3. 原型链的作用
- 实现继承 :子类可以通过
prototype
继承父类的方法。 - 共享方法:减少重复定义,提高内存使用效率。
二十六、深拷贝和浅拷贝
1. 什么是浅拷贝?
浅拷贝仅复制对象的第一层,如果对象属性是引用类型(如数组、对象),则拷贝的只是引用,修改拷贝对象的引用属性会影响原对象。
示例(浅拷贝):
ini
const obj1 = { name: "张三", info: { age: 25 } };
const obj2 = { ...obj1 };
obj2.name = "李四"; // 不影响 obj1
obj2.info.age = 30; // 影响 obj1,因为 info 是引用类型
console.log(obj1.info.age); // 输出 30
浅拷贝方法:
Object.assign({}, obj)
- 展开运算符
{ ...obj }
Array.prototype.slice()
(适用于数组)
2. 什么是深拷贝?
深拷贝会递归复制所有层级,即使对象中包含嵌套对象或数组,拷贝后两个对象完全独立,互不影响。
示例(深拷贝):
ini
const obj1 = { name: "张三", info: { age: 25 } };
// JSON 方式
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.info.age = 30; // 不影响 obj1
console.log(obj1.info.age); // 输出 25
深拷贝方法:
- JSON 方法 (
JSON.parse(JSON.stringify(obj))
,但不能处理undefined
、function
、Symbol
等特殊值) - Lodash
_.cloneDeep(obj)
- 递归手写深拷贝:
javascript
function deepClone(obj) {
if (typeof obj !== "object" || obj === null) return obj;
const newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
newObj[key] = deepClone(obj[key]); // 递归拷贝
}
return newObj;
}
二十七、HTTP 和 HTTPS
1. HTTP 与 HTTPS 区别
特性 | HTTP | HTTPS |
---|---|---|
安全性 | 明文传输,容易被攻击 | 加密传输,数据更安全 |
端口号 | 80 |
443 |
证书 | 不需要 | 需要 SSL 证书 |
速度 | 快 | 相对较慢(因加密解密) |
2. HTTPS 如何保障安全?
- 对称加密(AES) :双方使用相同密钥加密和解密,速度快但密钥易被盗。
- 非对称加密(RSA) :服务器生成公钥,客户端加密数据,服务器用私钥解密,安全性高但速度慢。
- SSL/TLS:结合对称加密和非对称加密,使用证书机构(CA)验证网站身份,防止中间人攻击。
3. HTTPS 握手过程
- 客户端请求 HTTPS 站点,服务器返回 SSL 证书(包含公钥)。
- 客户端验证证书(确保证书有效)。
- 客户端生成会话密钥,用公钥加密并传输给服务器。
- 服务器使用私钥解密,并使用会话密钥进行后续通信(对称加密)。
- 通信建立,数据加密传输。
二十八、SEO(搜索引擎优化)
SEO(Search Engine Optimization)是指优化网站,使其在搜索引擎中排名更高,提高流量。
1. SEO 主要策略
-
站内优化
- HTML 语义化 (使用
<h1>
、<p>
、<article>
等标签)。 - URL 规范化 (使用清晰的 URL,如
/products/shoes
)。 - 关键词优化 (在
<title>
、meta description
、内容中合理布局关键词)。 - 网站地图(Sitemap) 提交给搜索引擎。
- robots.txt 控制爬虫抓取范围。
- HTML 语义化 (使用
-
站外优化
- 外链建设(高质量网站的反向链接提升权重)。
- 社交媒体推广(增加品牌曝光度)。
- 提高网站访问速度(使用 CDN、压缩资源)。
2. 前端如何优化 SEO?
-
SSR(服务器端渲染) :提升搜索引擎可见性,如 Next.js、Nuxt.js。
-
静态生成(SSG) :生成静态页面,提高加载速度,如 VitePress、Gatsby。
-
图片优化 :使用
alt
属性,让搜索引擎识别图片内容:ini<img src="shoes.jpg" alt="红色运动鞋">
-
Schema 结构化数据:让搜索引擎理解内容:
less<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "headline": "SEO 最佳实践", "author": { "@type": "Person", "name": "张三" } } </script>
结语
这是目前碰到的面试题,后续还会继续更新。🧑🏻💻主播还在学习中......