
答案: 闭包是指有权访问另一个函数作用域中变量的函数。简单来说,闭包就是函数和其周围状态的引用捆绑在一起形成的组合。
特点:
作用:
示例:
function outer(x) {
return function inner(y) {
return x + y;
};
}
const add5 = outer(5);
console.log(add5(3)); // 8答案: 原型链是JavaScript实现继承的机制。每个对象都有一个指向其原型对象的内部链接,原型对象也有自己的原型,直到某个对象的原型为null为止。
核心概念:
__proto__:对象的原型链接prototype:函数的原型属性constructor:指向构造函数示例:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
};
const john = new Person('John');
john.sayHello(); // Hello, I'm John
// 原型链查找过程
console.log(john.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true答案:
特性 | var | let | const |
|---|---|---|---|
作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
变量提升 | 是 | 是(但有暂时性死区) | 是(但有暂时性死区) |
重复声明 | 允许 | 不允许 | 不允许 |
重新赋值 | 允许 | 允许 | 不允许 |
初始化 | 可选 | 可选 | 必须 |
示例:
// var - 函数作用域
function example() {
if (true) {
var x = 1;
}
console.log(x); // 1
}
// let - 块级作用域
function example2() {
if (true) {
let y = 1;
}
console.log(y); // ReferenceError
}
// const - 常量
const obj = { name: 'John' };
obj.name = 'Jane'; // 可以修改对象属性
// obj = {}; // TypeError: Assignment to constant variable答案: 事件循环是JavaScript运行时的核心机制,用于处理异步操作。它负责协调调用栈、任务队列和微任务队列的执行。
执行顺序:
示例:
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 输出顺序:1, 4, 3, 2答案:
浅拷贝实现:
// Object.assign
const shallow1 = Object.assign({}, original);
// 扩展运算符
const shallow2 = { ...original };
// Array.slice
const shallowArray = original.slice();深拷贝实现:
// JSON方法(有限制)
const deep1 = JSON.parse(JSON.stringify(original));
// 递归实现
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof Array) return obj.map(item => deepClone(item));
if (typeof obj === 'object') {
const clonedObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
}答案: CSS盒模型描述了元素在页面中所占空间的计算方式。
标准盒模型(content-box):
IE盒模型(border-box):
示例:
/* 标准盒模型 */
.standard-box {
box-sizing: content-box;
width: 200px;
padding: 20px;
border: 5px solid #000;
/* 实际宽度:200 + 40 + 10 = 250px */
}
/* IE盒模型 */
.border-box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 5px solid #000;
/* 实际宽度:200px,内容宽度:150px */
}答案: Flex布局是一种一维布局方法,用于在容器中分配空间和对齐项目。
容器属性:
.container {
display: flex;
flex-direction: row | row-reverse | column | column-reverse;
flex-wrap: nowrap | wrap | wrap-reverse;
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
align-items: stretch | flex-start | flex-end | center | baseline;
align-content: stretch | flex-start | flex-end | center | space-between | space-around;
}项目属性:
.item {
flex-grow: 0; /* 放大比例 */
flex-shrink: 1; /* 缩小比例 */
flex-basis: auto; /* 分配多余空间之前的主轴空间 */
flex: none | auto | initial | <'flex-grow'> <'flex-shrink'> <'flex-basis'>;
align-self: auto | flex-start | flex-end | center | baseline | stretch;
order: 0; /* 排列顺序 */
}答案: Grid布局是二维布局系统,可以同时处理行和列。
基本用法:
.grid-container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: 100px auto 100px;
gap: 10px;
}
.grid-item {
grid-column: 1 / 3; /* 从第1列到第3列 */
grid-row: 2; /* 第2行 */
}命名网格线:
.grid-container {
display: grid;
grid-template-columns: [start] 1fr [middle] 2fr [end];
grid-template-rows: [header-start] 100px [header-end main-start] auto [main-end footer-start] 100px [footer-end];
}答案: CSS选择器优先级按以下规则计算:
优先级权重:
示例:
/* 优先级:1 */
p { color: red; }
/* 优先级:10 */
.text { color: blue; }
/* 优先级:100 */
#title { color: green; }
/* 优先级:111 */
#title p.text { color: yellow; }
/* 最高优先级 */
p { color: purple !important; }答案:
1. 媒体查询:
/* 移动端优先 */
.container {
width: 100%;
padding: 10px;
}
/* 平板 */
@media (min-width: 768px) {
.container {
max-width: 750px;
margin: 0 auto;
}
}
/* 桌面端 */
@media (min-width: 1200px) {
.container {
max-width: 1170px;
}
}2. 弹性单位:
.responsive-text {
font-size: clamp(1rem, 2.5vw, 2rem);
padding: 1em;
margin: 1rem 0;
}3. 弹性图片:
.responsive-img {
max-width: 100%;
height: auto;
}答案:
类组件生命周期:
挂载阶段:
constructor() - 构造函数componentDidMount() - 组件挂载后更新阶段:
componentDidUpdate() - 组件更新后getSnapshotBeforeUpdate() - 更新前获取快照卸载阶段:
componentWillUnmount() - 组件卸载前函数组件Hooks:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate
useEffect(() => {
document.title = `Count: ${count}`;
});
// 相当于 componentDidMount
useEffect(() => {
console.log('Component mounted');
}, []);
// 相当于 componentWillUnmount
useEffect(() => {
return () => {
console.log('Component will unmount');
};
}, []);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}答案:
Vue 2.x - Object.defineProperty:
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.depend();
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify();
}
});
}Vue 3.x - Proxy:
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
trigger(target, key);
return result;
}
});
}答案:
Redux:
// Action
const increment = () => ({ type: 'INCREMENT' });
// Reducer
const counterReducer = (state = { count: 0 }, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
default:
return state;
}
};
// Store
const store = createStore(counterReducer);Vuex:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
increment({ commit }) {
commit('increment');
}
}
});Zustand:
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));答案:
1. 资源优化:
2. 加载优化:
<!-- 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero-image.jpg" as="image">
<!-- DNS预解析 -->
<link rel="dns-prefetch" href="//example.com">
<!-- 预连接 -->
<link rel="preconnect" href="https://fonts.googleapis.com">3. 渲染优化:
/* 启用硬件加速 */
.accelerated {
transform: translateZ(0);
will-change: transform;
}
/* 避免重排重绘 */
.optimized {
transform: translateX(100px); /* 而不是 left: 100px */
}4. JavaScript优化:
// 防抖
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 节流
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}答案:
1. 使用React.memo:
const MyComponent = React.memo(function MyComponent({ name }) {
return <div>Hello {name}</div>;
});
// 自定义比较函数
const MyComponent = React.memo(function MyComponent(props) {
return <div>{props.name}</div>;
}, (prevProps, nextProps) => {
return prevProps.name === nextProps.name;
});2. 使用useMemo和useCallback:
function ExpensiveComponent({ items, filter }) {
// 缓存计算结果
const filteredItems = useMemo(() => {
return items.filter(item => item.category === filter);
}, [items, filter]);
// 缓存函数引用
const handleClick = useCallback((id) => {
// 处理点击
}, []);
return (
<div>
{filteredItems.map(item => (
<Item key={item.id} item={item} onClick={handleClick} />
))}
</div>
);
}3. 代码分割:
import { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}答案:
强缓存:
# Expires(HTTP/1.0)
Expires: Wed, 21 Oct 2025 07:28:00 GMT
# Cache-Control(HTTP/1.1)
Cache-Control: max-age=3600, public
Cache-Control: no-cache, no-store, must-revalidate协商缓存:
# Last-Modified / If-Modified-Since
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
# ETag / If-None-Match
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"缓存策略:
// Service Worker缓存
self.addEventListener('fetch', event => {
if (event.request.destination === 'image') {
event.respondWith(
caches.open('images').then(cache => {
return cache.match(event.request).then(response => {
return response || fetch(event.request).then(fetchResponse => {
cache.put(event.request, fetchResponse.clone());
return fetchResponse;
});
});
})
);
}
});答案:
1. CORS(跨域资源共享):
// 服务端设置
app.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();
});2. JSONP:
function jsonp(url, callback) {
const script = document.createElement('script');
const callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
window[callbackName] = function(data) {
callback(data);
document.head.removeChild(script);
delete window[callbackName];
};
script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + callbackName;
document.head.appendChild(script);
}3. 代理服务器:
// webpack dev server
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};答案:
1. XSS防护:
// 输入过滤
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
// CSP设置
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'">2. CSRF防护:
// CSRF Token
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify(data)
});3. 点击劫持防护:
# X-Frame-Options
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
# CSP frame-ancestors
Content-Security-Policy: frame-ancestors 'none';答案:
快速排序:
function quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[Math.floor(arr.length / 2)];
const left = arr.filter(x => x < pivot);
const middle = arr.filter(x => x === pivot);
const right = arr.filter(x => x > pivot);
return [...quickSort(left), ...middle, ...quickSort(right)];
}归并排序:
function mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}
function merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return result.concat(left.slice(i)).concat(right.slice(j));
}答案:
class TreeNode {
constructor(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
// 前序遍历(递归)
function preorderTraversal(root) {
if (!root) return [];
return [root.val, ...preorderTraversal(root.left), ...preorderTraversal(root.right)];
}
// 中序遍历(迭代)
function inorderTraversal(root) {
const result = [];
const stack = [];
let current = root;
while (current || stack.length) {
while (current) {
stack.push(current);
current = current.left;
}
current = stack.pop();
result.push(current.val);
current = current.right;
}
return result;
}
// 层序遍历
function levelOrder(root) {
if (!root) return [];
const result = [];
const queue = [root];
while (queue.length) {
const levelSize = queue.length;
const currentLevel = [];
for (let i = 0; i < levelSize; i++) {
const node = queue.shift();
currentLevel.push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
result.push(currentLevel);
}
return result;
}答案:
斐波那契数列:
// 递归(效率低)
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
// 动态规划
function fibDP(n) {
if (n <= 1) return n;
const dp = [0, 1];
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
// 空间优化
function fibOptimized(n) {
if (n <= 1) return n;
let prev = 0, curr = 1;
for (let i = 2; i <= n; i++) {
[prev, curr] = [curr, prev + curr];
}
return curr;
}最长公共子序列:
function longestCommonSubsequence(text1, text2) {
const m = text1.length, n = text2.length;
const dp = Array(m + 1).fill().map(() => Array(n + 1).fill(0));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (text1[i - 1] === text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}答案:
class ListNode {
constructor(val, next = null) {
this.val = val;
this.next = next;
}
}
// 反转链表
function reverseList(head) {
let prev = null;
let current = head;
while (current) {
const next = current.next;
current.next = prev;
prev = current;
current = next;
}
return prev;
}
// 检测环
function hasCycle(head) {
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
return false;
}
// 合并两个有序链表
function mergeTwoLists(l1, l2) {
const dummy = new ListNode(0);
let current = dummy;
while (l1 && l2) {
if (l1.val <= l2.val) {
current.next = l1;
l1 = l1.next;
} else {
current.next = l2;
l2 = l2.next;
}
current = current.next;
}
current.next = l1 || l2;
return dummy.next;
}这份前端面试高频题解析涵盖了前端开发的核心知识点,包括:
掌握这些知识点将帮助你在前端面试中脱颖而出。建议结合实际项目经验,深入理解每个概念的应用场景和最佳实践。