成都前端面试复习文档

0 阅读12分钟

成都前端面试复习文档 2025

基于 2025 年成都软件行业行情整理,涵盖高频面试考点


📊 成都前端市场分析

当前行情概况

薪资水平(2025年):

  • 应届生/实习生:6-8K
  • 1-2年经验:8-12K
  • 3-5年经验:12-20K
  • 5年以上:20K+

主要分布区域:

  • 高新区(天府软件园、天府N街)
  • 武侯区
  • 双流区

主流技术栈:

  • Vue3 + TypeScript + Vite
  • React18 + TypeScript + Next.js
  • Node.js 基础
  • 工程化工具(Webpack、Vite)

企业类型:

  • 互联网公司(字节跳动、腾讯、阿里等)
  • 金融科技公司
  • 游戏公司
  • 政务/企业级应用公司

📚 目录

  1. JavaScript 核心
  2. TypeScript(必考)
  3. Vue3 全家桶
  4. React 生态
  5. 性能优化
  6. 工程化与构建
  7. 网络与安全
  8. Node.js
  9. 算法与数据结构
  10. 项目实战问题

JavaScript 核心

1. 数据类型与判断

基本数据类型(7种):

  • String、Number、Boolean、Null、Undefined、Symbol、BigInt

引用数据类型:

  • Object(Array、Function、Date、RegExp、Map、Set 等)

类型判断方法:

// typeof - 判断基本类型
typeof undefined // 'undefined'
typeof null      // 'object' (历史遗留问题)
typeof []        // 'object'
typeof {}        // 'object'

// instanceof - 判断引用类型
[] instanceof Array        // true
{} instanceof Object       // true
new Date() instanceof Date // true

// Object.prototype.toString - 最准确
const getType = (val) => Object.prototype.toString.call(val).slice(8, -1);
getType([])        // 'Array'
getType({})        // 'Object'
getType(null)       // 'Null'
getType(undefined)   // 'Undefined'

面试题:

// 判断数组的方法
Array.isArray([]) // true
Array.isArray({}) // false

// 深拷贝实现
function deepClone(obj, map = new WeakMap()) {
    if (obj === null || typeof obj !== 'object') return obj;
    if (map.has(obj)) return map.get(obj); // 处理循环引用
    
    const clone = Array.isArray(obj) ? [] : {};
    map.set(obj, clone);
    
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            clone[key] = deepClone(obj[key], map);
        }
    }
    return clone;
}

2. this 指向问题

this 的 6 种指向:

场景this 指向
全局环境window
普通函数window
对象方法对象本身
事件处理函数事件源
构造函数实例对象
箭头函数继承外层 this

修改 this 指向:

// call - 立即调用,参数逐个传递
fn.call(obj, arg1, arg2);

// apply - 立即调用,参数数组传递
fn.apply(obj, [arg1, arg2]);

// bind - 返回新函数
const boundFn = fn.bind(obj);
boundFn(arg1, arg2);

面试题:

// 经典面试题
var name = 'global';

const obj = {
    name: 'obj',
    getName: function() {
        return this.name;
    }
};

console.log(obj.getName()); // 'obj'

const fn = obj.getName;
console.log(fn()); // 'global'

console.log(obj.getName.call({ name: 'new' })); // 'new'

// 箭头函数
const obj2 = {
    name: 'obj2',
    getName: () => {
        return this.name; // 继承外层 this
    }
};
console.log(obj2.getName()); // 'undefined' (严格模式) 或 'global'

3. 闭包与作用域

闭包定义: 函数内部定义函数,内部函数引用外部函数的变量,形成闭包。

闭包作用:

  • 延长变量生命周期
  • 创建私有变量
  • 模块化

面试题:

// 经典闭包面试题
for (var i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i); // 5 5 5 5 5
    }, 100);
}

// 解决方案一:let
for (let i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i); // 0 1 2 3 4
    }, 100);
}

// 解决方案二:闭包
for (var i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(() => {
            console.log(i); // 0 1 2 3 4
        }, 100);
    })(i);
}

// 解决方案三:bind
for (var i = 0; i < 5; i++) {
    setTimeout(function(i) {
        console.log(i); // 0 1 2 3 4
    }.bind(null, i), 100);
}

4. 原型与原型链

核心概念:

function Person(name) {
    this.name = name;
}

Person.prototype.sayName() {
    console.log(this.name);
}

const person = new Person('Tom');

// 原型链关系
person.__proto__ === Person.prototype              // true
Person.prototype.__proto__ === Object.prototype   // true
Object.prototype.__proto__ === null              // true

// instanceof 原理
person instanceof Person  // true
person instanceof Object   // true

继承方式:

// 1. 原型链继承
function Child() {}
Child.prototype = new Parent();

// 2. 构造函数继承
function Child() {
    Parent.call(this);
}

// 3. 组合继承
function Child() {
    Parent.call(this);
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;

// 4. ES6 class 继承(推荐)
class Child extends Parent {
    constructor() {
        super();
    }
}

5. 事件循环(Event Loop)

宏任务:

  • setTimeout、setInterval
  • I/O 操作
  • UI 渲染
  • setImmediate(Node.js)

微任务:

  • Promise.then/catch/finally
  • process.nextTick(Node.js)
  • MutationObserver
  • queueMicrotask

执行顺序:

  1. 执行同步代码
  2. 执行所有微任务
  3. 执行一个宏任务
  4. 重复步骤 2-3

经典面试题:

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

Promise.resolve().then(() => {
    console.log('4');
    setTimeout(() => console.log('5'), 0);
});

console.log('6');

// 输出:1 6 3 4 2 5

复杂面试题:

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}

async function async2() {
    console.log('async2');
}

console.log('script start');

setTimeout(() => console.log('setTimeout'), 0);

async1();

new Promise(resolve => {
    console.log('promise1');
    resolve();
}).then(() => console.log('promise2'));

console.log('script end');

// 输出:
// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout

6. 异步编程

Promise 核心方法:

// Promise.all - 所有成功才成功
Promise.all([p1, p2, p3])
    .then(results => console.log(results))
    .catch(error => console.log(error));

// Promise.race - 谁快用谁
Promise.race([p1, p2, p3])
    .then(result => console.log(result));

// Promise.allSettled - 返回所有结果
Promise.allSettled([p1, p2, p3])
    .then(results => console.log(results));

// Promise.any - 只要有一个成功就成功
Promise.any([p1, p2, p3])
    .then(result => console.log(result));

async/await 错误处理:

// 方式一:try-catch
async function fetchData() {
    try {
        const data = await fetch('/api/data');
        return await data.json();
    } catch (error) {
        console.error(error);
        throw error;
    }
}

// 方式二:.catch()
async function fetchData() {
    const data = await fetch('/api/data')
        .catch(error => {
            console.error(error);
            throw error;
        });
    return await data.json();
}

TypeScript(必考)

⚠️ 成都市场现状:TypeScript 已成为标配,不会 TS 很难找到好工作

1. 基础类型

// 基本类型
let name: string = 'Tom';
let age: number = 18;
let isStudent: boolean = true;
let nothing: null = null;
let notDefined: undefined = undefined;

// 数组
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ['a', 'b', 'c'];

// 元组
let tuple: [string, number] = ['Tom', 18];

// 枚举
enum Color {
    Red,
    Green,
    Blue
}
let color: Color = Color.Red;

// any 和 unknown
let anything: any = 10;
let unknownValue: unknown = 10;

// void
function log(message: string): void {
    console.log(message);
}

// never
function error(message: string): never {
    throw new Error(message);
}

2. 接口与类型别名

// 接口
interface Person {
    name: string;
    age: number;
    sayHello(): void;
}

// 类型别名
type PersonType = {
    name: string;
    age: number;
};

// 可选属性
interface User {
    id: number;
    name: string;
    age?: number; // 可选
}

// 只读属性
interface Config {
    readonly id: number;
    name: string;
}

// 函数类型
type AddFunction = (a: number, b: number) => number;
const add: AddFunction = (a, b) => a + b;

3. 泛型

// 泛型函数
function identity<T>(arg: T): T {
    return arg;
}

// 泛型接口
interface Box<T> {
    value: T;
}

// 泛型类
class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

// 泛型约束
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

4. 类型推断与类型守卫

// 类型推断
let x = 3; // 推断为 number

// 类型守卫 - typeof
function printId(id: string | number) {
    if (typeof id === 'string') {
        console.log(id.toUpperCase());
    } else {
        console.log(id.toFixed(2));
    }
}

// 类型守卫 - instanceof
class Bird {
    fly() {}
}

class Fish {
    swim() {}
}

function move(animal: Bird | Fish) {
    if (animal instanceof Bird) {
        animal.fly();
    } else {
        animal.swim();
    }
}

// 类型守卫 - in
interface Square {
    kind: 'square';
    size: number;
}

interface Circle {
    kind: 'circle';
    radius: number;
}

function getArea(shape: Square | Circle) {
    if (shape.kind === 'square') {
        return shape.size * shape.size;
    } else {
        return Math.PI * shape.radius * shape.radius;
    }
}

5. 高级类型

// 联合类型
type ID = string | number;

// 交叉类型
type Person = {
    name: string;
};

type Employee = {
    id: number;
};

type PersonEmployee = Person & Employee;

// 条件类型
type NonNullable<T> = T extends null | undefined ? never : T;

// 映射类型
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

type Partial<T> = {
    [P in keyof T]?: T[P];
};

// 索引签名
interface StringDictionary {
    [index: string]: string;
}

6. 装饰器

// 类装饰器
function sealed(constructor: Function) {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

@sealed
class Greeter {}

// 方法装饰器
function log(target: MethodDecoratorContext, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
        console.log(`Calling ${propertyKey} with`, args);
        return originalMethod.apply(this, args);
    };
}

class Calculator {
    @log
    add(a: number, b: number) {
        return a + b;
    }
}

Vue3 全家桶

1. Vue3 核心特性

Composition API vs Options API:

特性Options APIComposition API
代码组织按选项分类按功能组织
逻辑复用MixinsComposables
TypeScript 支持较弱
this依赖 this无 this

响应式原理:

// Vue2 - Object.defineProperty
Object.defineProperty(obj, 'key', {
    get() {
        // 收集依赖
    },
    set(newVal) {
        // 触发更新
    }
});

// Vue3 - Proxy
const proxy = new Proxy(target, {
    get(target, key) {
        // 收集依赖
        return Reflect.get(target, key);
    },
    set(target, key, value) {
        // 触发更新
        return Reflect.set(target, key, value);
    }
});

2. Composition API

ref vs reactive:

import { ref, reactive } from 'vue';

// ref - 用于基本类型
const count = ref(0);
console.log(count.value); // 访问需要 .value

// reactive - 用于对象
const state = reactive({
    name: 'Tom',
    age: 18
});
console.log(state.name); // 直接访问

// toRefs - 解构 reactive
const { name, age } = toRefs(state);

computed 和 watch:

import { ref, computed, watch, watchEffect } from 'vue';

const count = ref(0);

// computed - 计算属性
const doubled = computed(() => count.value * 2);

// watch - 监听
watch(count, (newVal, oldVal) => {
    console.log(`count changed from ${oldVal} to ${newVal}`);
});

// watchEffect - 自动追踪依赖
watchEffect(() => {
    console.log(`count is ${count.value}`);
});

生命周期:

import { onMounted, onUpdated, onUnmounted } from 'vue';

onMounted(() => {
    console.log('组件已挂载');
});

onUpdated(() => {
    console.log('组件已更新');
});

onUnmounted(() => {
    console.log('组件已卸载');
});

3. 组件通信

父传子(props):

<!-- 父组件 -->
<template>
  <Child :message="parentMessage" :count="count" />
</template>

<script setup lang="ts">
import { ref } from 'vue';
import Child from './Child.vue';

const parentMessage = ref('Hello from parent');
const count = ref(0);
</script>

<!-- 子组件 -->
<script setup lang="ts">
interface Props {
  message: string;
  count?: number;
}

const props = withDefaults(defineProps<Props>(), {
  count: 0
});
</script>

子传父(emit):

<!-- 子组件 -->
<script setup lang="ts">
const emit = defineEmits<{
  (e: 'update', value: number): void;
  (e: 'delete', id: number): void;
}>();

const handleClick = () => {
  emit('update', 10);
};
</script>

<!-- 父组件 -->
<template>
  <Child @update="handleUpdate" />
</template>

<script setup lang="ts">
const handleUpdate = (value: number) => {
  console.log('Received:', value);
};
</script>

provide/inject(跨层级):

// 祖先组件
import { provide, ref } from 'vue';

const theme = ref('dark');
provide('theme', theme);

// 后代组件
import { inject } from 'vue';

const theme = inject('theme');

4. Vue Router

路由模式:

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router';

// history 模式(需要服务器配置)
const router = createRouter({
  history: createWebHistory(),
  routes: []
});

// hash 模式
const router = createRouter({
  history: createWebHashHistory(),
  routes: []
});

路由守卫:

// 全局前置守卫
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isAuthenticated()) {
    next('/login');
  } else {
    next();
  }
});

// 路由独享守卫
{
  path: '/admin',
  component: Admin,
  beforeEnter: (to, from, next) => {
    if (isAdmin()) {
      next();
    } else {
      next('/403');
    }
  }
}

5. Pinia(状态管理)

定义 Store:

import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    name: '',
    age: 0
  }),
  
  getters: {
    doubleAge: (state) => state.age * 2
  },
  
  actions: {
    async fetchUser() {
      const data = await api.getUser();
      this.name = data.name;
      this.age = data.age;
    }
  }
});

使用 Store:

import { useUserStore } from '@/stores/user';

const userStore = useUserStore();

// 访问 state
console.log(userStore.name);

// 访问 getters
console.log(userStore.doubleAge);

// 调用 actions
userStore.fetchUser();

6. 性能优化

v-if vs v-show:

特性v-ifv-show
渲染条件为 false 不渲染始终渲染
切换开销高(销毁/重建)低(display 切换)
初始开销

key 的作用:

<!-- 正确:使用唯一 key -->
<li v-for="item in list" :key="item.id">{{ item.name }}</li>

<!-- 错误:使用 index -->
<li v-for="(item, index) in list" :key="index">{{ item.name }}</li>

keep-alive:

<template>
  <keep-alive include="ComponentA,ComponentB">
    <component :is="currentComponent" />
  </keep-alive>
</template>

React 生态

1. React Hooks

useState:

const [count, setCount] = useState(0);

// 函数式更新
setCount(prev => prev + 1);

useEffect:

useEffect(() => {
  // 副作用
  document.title = `Count: ${count}`;
  
  // 清理函数
  return () => {
    console.log('cleanup');
  };
}, [count]); // 依赖项

useContext:

const ThemeContext = createContext('light');

// 提供者
<ThemeContext.Provider value="dark">
  <App />
</ThemeContext.Provider>

// 消费者
const theme = useContext(ThemeContext);

useMemo 和 useCallback:

// useMemo - 缓存值
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

// useCallback - 缓存函数
const memoizedCallback = useCallback(
  () => doSomething(a, b),
  [a, b]
);

useRef:

const inputRef = useRef<HTMLInputElement>(null);

// 访问 DOM
inputRef.current?.focus();

// 保存可变值
const timerRef = useRef<number>();
timerRef.current = window.setTimeout(() => {}, 1000);

2. React 性能优化

React.memo:

const MemoizedComponent = React.memo<Props>(function MyComponent(props) {
  return <div>{props.value}</div>;
}, (prevProps, nextProps) => {
  // 自定义比较函数
  return prevProps.value === nextProps.value;
});

useMemo 和 useCallback 的使用场景:

// useMemo - 计算属性
const expensiveValue = useMemo(() => {
  return bigArray.filter(item => item.active).map(item => item.value * 2);
}, [bigArray]);

// useCallback - 传递给子组件的函数
const handleClick = useCallback((id: number) => {
  setSelectedId(id);
}, []);

虚拟列表:

import { FixedSizeList } from 'react-window';

const Row = ({ index, style }) => (
  <div style={style}>Row {index}</div>
);

const VirtualList = () => (
  <FixedSizeList
    height={600}
    itemCount={10000}
    itemSize={50}
    width={300}
  >
    {Row}
  </FixedSizeList>
);

3. React Router

路由配置:

import { createBrowserRouter, RouterProvider } from 'react-router-dom';

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,
    children: [
      { index: true, element: <Home /> },
      { path: 'about', element: <About /> }
    ]
  }
]);

function App() {
  return <RouterProvider router={router} />;
}

路由守卫:

const ProtectedRoute = ({ children }) => {
  if (!isAuthenticated()) {
    return <Navigate to="/login" replace />;
  }
  return children;
};

4. Redux Toolkit

创建 Slice:

import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    }
  }
});

export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;

配置 Store:

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer
  }
});

性能优化

1. 网络优化

减少 HTTP 请求:

  • 合并 CSS 和 JS 文件
  • 使用雪碧图(CSS Sprites)
  • 使用 Base64 编码小图片

使用 CDN:

  • 静态资源使用 CDN 加速
  • 多节点部署,就近访问

开启 Gzip 压缩:

// Vite 配置
import viteCompression from 'vite-plugin-compression';

export default defineConfig({
  plugins: [
    viteCompression({
      algorithm: 'gzip',
      ext: '.gz'
    })
  ]
});

HTTP/2:

  • 多路复用
  • 头部压缩
  • 服务器推送

2. 资源优化

图片优化:

  • 使用 WebP 格式
  • 图片懒加载
  • 响应式图片
// 图片懒加载
<img loading="lazy" src="image.jpg" alt="description" />

代码分割:

// 动态导入
const LazyComponent = lazy(() => import('./LazyComponent'));

// 路由级别代码分割
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

Tree Shaking:

  • 移除未使用的代码
  • 使用 ES6 模块语法

3. 渲染优化

减少重排和重绘:

// 批量 DOM 操作
const fragment = document.createDocumentFragment();
items.forEach(item => {
  const li = document.createElement('li');
  li.textContent = item;
  fragment.appendChild(li);
});
ul.appendChild(fragment);

使用 requestAnimationFrame:

function animate() {
  // 动画逻辑
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

防抖和节流:

// 防抖
function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timer: NodeJS.Timeout;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

// 节流
function throttle<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
  let lastTime = 0;
  return (...args) => {
    const now = Date.now();
    if (now - lastTime > delay) {
      fn(...args);
      lastTime = now;
    }
  };
}

4. 缓存优化

强缓存:

// Cache-Control: max-age=31536000

协商缓存:

// ETag
// Last-Modified

LocalStorage:

// 设置
localStorage.setItem('key', JSON.stringify(value));

// 获取
const value = JSON.parse(localStorage.getItem('key') || 'null');

// 删除
localStorage.removeItem('key');

SessionStorage:

  • 会话级别存储
  • 关闭标签页后清除

IndexedDB:

  • 大量数据存储
  • 异步操作
  • 支持索引查询

工程化与构建

1. Vite(推荐)

Vite vs Webpack:

特性ViteWebpack
启动速度快(ESM)慢(打包)
HMR极快较慢
配置简单复杂
生态新兴成熟

Vite 配置:

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  },
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vue-vendor': ['vue', 'vue-router', 'pinia']
        }
      }
    }
  }
});

2. Webpack

核心概念:

  • Entry:入口
  • Output:输出
  • Loader:转换器
  • Plugin:插件
  • Mode:模式

常用 Loader:

module: {
  rules: [
    {
      test: /\.vue$/,
      loader: 'vue-loader'
    },
    {
      test: /\.ts$/,
      loader: 'ts-loader'
    },
    {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    },
    {
      test: /\.(png|jpg|gif)$/,
      type: 'asset',
      parser: {
        dataUrlCondition: {
          maxSize: 8 * 1024 // 8kb
        }
      }
    }
  ]
}

常用 Plugin:

plugins: [
  new HtmlWebpackPlugin({
    template: './public/index.html'
  }),
  new MiniCssExtractPlugin({
    filename: 'css/[name].[contenthash:8].css'
  }),
  new CleanWebpackPlugin()
]

3. ESLint 和 Prettier

ESLint 配置:

module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-recommended',
    'plugin:@typescript-eslint/recommended'
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser'
  }
};

Prettier 配置:

module.exports = {
  semi: false,
  singleQuote: true,
  trailingComma: 'none',
  printWidth: 100
};

网络与安全

1. HTTP 状态码

2xx 成功:

  • 200 OK
  • 201 Created
  • 204 No Content

3xx 重定向:

  • 301 Moved Permanently
  • 302 Found
  • 304 Not Modified

4xx 客户端错误:

  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found

5xx 服务器端错误:

  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable

2. 跨域问题

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();
});

JSONP(只支持 GET):

function jsonp(url, callbackName) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = `${url}?callback=${callbackName}`;
    
    window[callbackName] = (data) => {
      resolve(data);
      delete window[callbackName];
      document.body.removeChild(script);
    };
    
    document.body.appendChild(script);
  });
}

3. 前端安全

XSS(跨站脚本攻击):

// 防御:转义特殊字符
function escapeHtml(unsafe: string): string {
  return unsafe
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

CSRF(跨站请求伪造):

// 防御:使用 CSRF Token
// 1. 服务器生成 Token
// 2. 客户端请求时携带 Token
// 3. 服务器验证 Token

内容安全策略(CSP):

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'unsafe-inline'">

Node.js

1. CommonJS vs ES Modules

CommonJS:

// 导出
module.exports = {
  name: 'module'
};

// 或
exports.name = 'module';

// 导入
const module = require('./module');

ES Modules:

// 导出
export const name = 'module';
export default function() {}

// 导入
import module, { name } from './' + 'module';

2. 内置模块

fs 模块:

import fs from 'fs/promises';

// 异步读取
const data = await fs.readFile('./file.txt', 'utf8');

// 异步写入
await fs.writeFile('./file.txt', 'content');

// 检查文件是否存在
const exists = await fs.access('./file.txt').then(() => true).catch(() => false);

http 模块:

import http from 'http';

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ message: 'Hello World' }));
});

server.listen(3000, () => {
  console.log('Server running on port 3000');
});

path 模块:

import path from 'path';

path.join('/foo', 'bar', 'baz'); // '/foo/bar/baz'
path.resolve('/foo/bar', './baz'); // '/foo/bar/baz'
path.basename('/foo/bar/baz.txt'); // 'baz.txt'

3. 事件驱动

import { EventEmitter } from 'events';

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

myEmitter.on('event', (data) => {
  console.log('Event received:', data);
});

myEmitter.emit('event', { message: 'Hello' });

算法与数据结构

1. 数组操作

数组去重:

// 方法一:Set
const unique = [...new Set(array)];

// 方法二:filter + indexOf
const unique = array.filter((item, index) => array.indexOf(item) === index);

// 方法三:reduce
const unique = array.reduce((acc, cur) => {
  return acc.includes(cur) ? acc : [...acc, cur];
}, []);

数组扁平化:

// 方法一:flat
const flattened = arr.flat(Infinity);

// 方法二:reduce
const flatten = (arr) => {
  return arr.reduce((acc, cur) => {
    return acc.concat(Array.isArray(cur) ? flatten(cur) : cur);
  }, []);
};

2. 常用算法

二分查找:

function binarySearch(arr: number[], target: number): number {
  let left = 0;
  let right = arr.length - 1;
  
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    
    if (arr[mid] === target) {
      return mid;
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }
  
  return -1;
}

快速排序:

function quickSort(arr: number[]): number[] {
  if (arr.length <= 1) return arr;
  
  const pivot = arr[0];
  const left = arr.slice(1).filter(x => x <= pivot);
  const right = arr.slice(1).filter(x => x > pivot);
  
  return [...quickSort(left), pivot, ...quickSort(right)];
}

防抖和节流:

// 防抖
function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timer: NodeJS.Timeout;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

// 节流
function throttle<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
  let lastTime = 0;
  return (...args) => {
    const now = Date.now();
    if (now - lastTime > delay) {
      fn(...args);
      lastTime = now;
    }
  };
}

项目实战问题

1. Vue3 项目问题

Q: Vue3 中 ref 和 reactive 的区别?

A:

  • ref 用于基本类型,访问需要 .value
  • reactive 用于对象,直接访问
  • ref 在模板中自动解包,reactive 不会

Q: Vue3 如何实现组件通信?

A:

  • 父子:props + emit
  • 跨层级:provide/inject
  • 兄弟:事件总线或 Pinia
  • 跨组件:Pinia

Q: Vue3 性能优化有哪些方法?

A:

  • 使用 v-show 替代频繁切换的 v-if
  • 合理使用 key
  • 使用 keep-alive 缓存组件
  • 使用 computed 缓存计算结果
  • 按需引入组件
  • 使用虚拟列表处理长列表

2. React 项目问题

Q: React Hooks 的使用规则?

A:

  • 只在函数组件或自定义 Hook 中使用
  • 只在顶层调用,不要在循环、条件或嵌套函数中调用
  • 依赖项要正确填写

Q: React 如何避免不必要的渲染?

A:

  • 使用 React.memo 包裹组件
  • 使用 useMemo 缓存计算结果
  • 使用 useCallback 缓存函数
  • 使用 key 帮助 React 识别元素

Q: React 虚拟 DOM 的原理?

A:

  • 用 JS 对象描述 DOM 结构
  • 通过 Diff 算法比较新旧虚拟 DOM
  • 只更新变化的部分

3. 工程化问题

Q: Vite 为什么比 Webpack 快?

A:

  • Vite 使用原生 ESM,无需打包
  • Webpack 需要先打包再启动
  • Vite 的 HMR 是按需更新

Q: 如何优化构建速度?

A:

  • 使用多线程(thread-loader)
  • 缓存 loader 结果
  • 减少构建文件数量
  • 使用 DLL Plugin

Q: 如何优化打包体积?

A:

  • Tree Shaking
  • 代码分割
  • 压缩代码
  • 使用 CDN 引入大库
  • 开启 Gzip

4. 性能优化问题

Q: 如何检测性能问题?

A:

  • 使用 Chrome DevTools Performance
  • 使用 Lighthouse
  • 使用 WebPageTest

Q: 首屏加载优化有哪些方法?

A:

  • 减少 HTTP 请求
  • 使用 CDN
  • 开启 Gzip
  • 懒加载
  • 预加载关键资源
  • SSR(服务端渲染)

Q: 如何优化长列表渲染?

A:

  • 使用虚拟列表
  • 分页加载
  • 无限滚动

面试技巧

1. 自我介绍

模板:

您好,我是[姓名],有[X]年前端开发经验。

技术栈方面:
- 熟练掌握 Vue3/React + TypeScript
- 熟悉 Node.js 和工程化工具
- 有性能优化和项目架构经验

项目经验:
- 参与过[项目类型]项目开发
- 负责[具体职责]
- 取得了[成果]

期望:
- 希望加入贵公司,共同成长

2. 回答技巧

STAR 原则:

  • Situation(情境)
  • Task(任务)
  • Action(行动)
  • Result(结果)

示例:

S: 在上一个项目中,我们遇到了首屏加载慢的问题
T: 我负责优化了首屏加载速度
A: 我使用了代码分割、懒加载、CDN 等技术
R: 首屏加载时间从 3s 降低到 1.5s

3. 常见问题

Q: 你遇到过什么技术难题?如何解决的?

A: 描述具体问题、解决思路、最终结果

Q: 你如何学习新技术?

A: 官方文档、技术博客、实践项目、技术分享

Q: 你的职业规划是什么?

A: 短期目标、长期目标、学习计划


复习计划

第 1 周:JavaScript 核心

  • 数据类型与判断
  • this 指向
  • 闭包与作用域
  • 原型与原型链
  • 事件循环
  • 异步编程

第 2 周:TypeScript

  • 基础类型
  • 接口与类型别名
  • 泛型
  • 类型推断与守卫
  • 高级类型
  • 装饰器

第 3 周:Vue3 全家桶

  • Composition API
  • 组件通信
  • Vue Router
  • Pinia
  • 性能优化

第 4 周:React 生态

  • React Hooks
  • 性能优化
  • React Router
  • Redux Toolkit

第 5 周:工程化与性能优化

  • Vite/Webpack
  • 网络优化
  • 渲染优化
  • 缓存优化

第 6 周:项目实战与算法

  • 项目问题总结
  • 常用算法
  • 面试技巧
  • 模拟面试

总结

成都前端市场特点

  1. 技术栈要求高:Vue3/React + TypeScript 是标配
  2. 薪资水平:3-5年经验 12-20K
  3. 主要区域:高新区、武侯区
  4. 企业类型:互联网、金融科技、游戏、政务

高频考点

  1. JavaScript 核心:闭包、原型链、事件循环
  2. TypeScript:泛型、类型守卫、高级类型
  3. Vue3:Composition API、组件通信、性能优化
  4. React:Hooks、性能优化、虚拟 DOM
  5. 性能优化:网络、渲染、缓存优化
  6. 工程化:Vite、Webpack、代码分割

复习建议

  1. 理解原理:不要死记硬背
  2. 动手实践:多写代码
  3. 项目总结:梳理项目经验
  4. 模拟面试:练习表达
  5. 关注趋势:了解最新技术

祝你面试顺利,拿到心仪的 offer! 💪

成都市场机会很多,加油!技术过硬才是硬道理! 🚀