前端核心基础汇总

一、JavaScript 核心基础

1. 闭包 (Closure)
  • 定义 :函数和其周围状态(词法环境)的引用捆绑在一起构成闭包。简单说,就是内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。
  • 作用:数据私有化、延长变量生命周期、柯里化。
  • 缺点:滥用会导致内存泄漏(变量无法被回收)。
2. 原型链 (Prototype Chain)
  • 机制 :每个对象都有一个 __proto__ 指向它的原型对象 (prototype)。当访问一个属性时,如果自身没有,就会沿着 __proto__ 向上查找,直到 null。这条链条就是原型链。
  • 终点Object.prototype.__proto__ === null
3. 数据类型
  • 基本类型 (栈)String, Number, Boolean, Null, Undefined, Symbol, BigInt。按值访问,复制是复制值。
  • 引用类型 (堆)Object, Array, Function, Date 等。按引用访问,复制是复制地址(指针)。
4. 冒泡排序 (Bubble Sort)
  • 原理:重复遍历数组,比较相邻元素,如果顺序错误就交换。每一轮将最大的元素"浮"到末尾。
  • 复杂度:时间 O(n2)O(n2) ,空间 O(1)O(1) 。
  • 代码简述:双重循环,外层控制轮数,内层控制比较交换。
5. 递归算法
  • 定义:函数在内部调用自身。
  • 关键 :必须有终止条件(基准情况),否则会栈溢出。
  • 应用:阶乘、斐波那契数列、深拷贝、树形结构遍历。
6. 数组排序
  • 原生方法array.sort((a, b) => a - b)。注意默认是按字符串 Unicode 排序,数字需传比较函数。
  • 常见算法:冒泡、选择、插入、快速排序 (Quick Sort, 最常用,平均 O(nlog⁡n)O(nlogn) )、归并排序。
7. 浅拷贝 vs 深拷贝
  • 浅拷贝 :只复制第一层属性。如果属性是引用类型,复制的是地址(改一处全变)。
    • 方法:Object.assign(), 展开运算符 {...obj}, Array.slice().
  • 深拷贝 :递归复制所有层级,生成全新的对象,互不影响。
    • 方法:JSON.parse(JSON.stringify(obj)) (有缺陷,不能处理函数/undefined/date), structuredClone() (新API), 手写递归,lodash _.cloneDeep
8. this 的指向
  • 默认绑定 :独立函数调用,指向全局 (window/undefined)。
  • 隐式绑定obj.fn(),指向 obj
  • 显式绑定call, apply, bind,指向指定的对象。
  • new 绑定:构造函数调用,指向新创建的实例。
  • 箭头函数没有自己的 this ,继承自上一层作用域的 this
9. 继承
  • 原型链继承:子类原型 = 父类实例。缺点:引用属性共享。
  • 构造函数继承Parent.call(this)。缺点:方法无法复用。
  • 组合继承:原型链 + 构造函数(最常用)。
  • ES6 Class 继承class Child extends Parent,底层仍是原型链,但语法更清晰。
10. 判断是不是原型的方法 / for in 遍历原型
  • 判断原型A.prototype.isPrototypeOf(B)B instanceof A

  • for in 遍历 遍历对象自身可枚举属性 以及 原型链上的可枚举属性。

  • 过滤原型 :通常配合 hasOwnProperty 使用:javascript

    javascript 复制代码
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) { ... } // 只处理自身属性
    }
11. 遍历数组/对象
  • 数组for, forEach, map (返回新数组), filter, reduce, for...of (推荐,可中断)。
  • 对象for...in (含原型), Object.keys(), Object.values(), Object.entries()
12. 事件循环机制 (Event Loop)
  • 流程
    1. 执行同步代码(调用栈)。
    2. 异步任务放入任务队列(宏任务:setTimeout, I/O; 微任务:Promise, nextTick)。
    3. 调用栈清空后,先执行完所有微任务
    4. 再执行一个宏任务。
    5. 循环往复。
  • 关键点:微任务优先级高于宏任务。

二、浏览器、网络与安全

13. 输入 URL 到页面展示的详细过程
  1. DNS 解析:域名 -> IP 地址。
  2. TCP 连接:三次握手。
  3. 发送 HTTP 请求
  4. 服务器处理并返回响应
  5. 浏览器渲染
    • 构建 DOM 树。
    • 构建 CSSOM 树。
    • 生成渲染树 (Render Tree)。
    • 布局 (Layout/Reflow)。
    • 绘制 (Paint)。
  6. TCP 断开:四次挥手。
14. 常见的状态码
  • 200:成功。
  • 301/302:永久/临时重定向。
  • 304:资源未修改(使用缓存)。
  • 400:请求参数错误。
  • 401:未授权。
  • 403:禁止访问。
  • 404:资源不存在。
  • 500:服务器内部错误。
  • 502/503/504:网关错误/服务不可用/超时。
15. 跨域解决
  • 原因:浏览器的同源策略(协议、域名、端口任一不同即跨域)。
  • 解决方案
    • CORS (后端设置 Access-Control-Allow-Origin) - 最主流。
    • Nginx 反向代理 - 生产环境常用。
    • Webpack/Vite 开发代理 (proxy)。
    • postMessage (窗口间通信)。
    • (旧方案:JSONP,仅支持 GET)
16. HTTP 缓存
  • 强缓存 :不发送请求,直接用本地。
    • 头:Cache-Control: max-age=3600, Expires
  • 协商缓存 :发送请求,服务器判断是否过期(返回 304)。
    • 头:Last-Modified / If-Modified-Since (基于时间),Etag / If-None-Match (基于内容哈希,更精准)。
17. XSS 攻击 vs CSRF 攻击
  • XSS (跨站脚本攻击)
    • 原理:注入恶意脚本到网页,用户浏览时执行,窃取 Cookie 等。
    • 防御:转义输入输出,CSP (内容安全策略),HttpOnly Cookie。
  • CSRF (跨站请求伪造)
    • 原理:诱导用户在已登录状态下访问恶意网站,向后端发送请求(如转账)。
    • 防御 :SameSite Cookie,验证 Referer/Origin,CSRF Token
  • 区别:XSS 是借用户的浏览器执行脚本;CSRF 是借用户的身份发送请求。
18. 怎么打断点
  • Sources 面板:点击行号。
  • 代码中debugger; 语句。
  • DOM 断点:Elements 面板 -> 右键节点 -> Break on。
  • XHR/Fetch 断点:Sources 面板右侧 XHR Breakpoints。
19. Git 冲突怎么解决
  1. git pullgit merge 时发现冲突。
  2. 打开冲突文件,找到 <<<<<<<, =======, >>>>>>> 标记。
  3. 手动保留需要的代码,删除标记符号。
  4. git add <file> 标记为已解决。
  5. git commit 完成合并。

三、CSS、HTML5 与工程化

20. H5 (HTML5) & C3 (CSS3)
  • H5 新特性 :语义化标签 (header, footer),多媒体 (video, audio),存储 (localStorage, sessionStorage),绘图 (Canvas, SVG),地理定位,Web Workers。
  • C3 新特性 :选择器增强,盒模型 (box-sizing),Flex/Grid 布局,动画 (transition, animation, transform),媒体查询 (响应式),变量 (--color)。
21. Less/Sass 用法和编译
  • 用法 :嵌套写法、变量 ($color)、混合 (mixin)、函数、继承 (@extend)。
  • 编译:浏览器不直接识别,需通过构建工具 (Webpack Loader, Vite Plugin) 或 CLI 编译成 CSS。
22. 兼容性解决
  • CSS :加厂商前缀 (-webkit-, -moz-),使用 Autoprefixer 插件自动添加;Polyfill。
  • JS :Babel 转译 ES6+ 为 ES5;引入核心 Polyfill (core-js)。
  • 策略:渐进增强,优雅降级。
23. Rem 原理 & 移动端适配
  • Rem :相对于根元素 (html) 的 font-size
  • 原理 :通过 JS 或 CSS 媒体查询,根据屏幕宽度动态设置 htmlfont-size。例如:屏幕宽 375px,设 html font-size 为 37.5px,则 1rem = 37.5px。设计稿 100px -> 写 2.66rem
  • 方案flexible.js 方案,或 vw/vh 单位(更现代,1vw = 1% 屏幕宽)。
24. 性能优化
  • 网络:压缩资源 (Gzip/Brotli),图片优化 (WebP, 懒加载),CDN 加速,减少 HTTP 请求 (合并/雪碧图),HTTP/2。
  • 渲染 :减少重排重绘,使用 will-change,虚拟列表 (长列表),防抖节流。
  • 代码:路由懒加载,组件懒加载,Tree Shaking,移除无用代码。
  • 缓存:合理利用强缓存和协商缓存。

四、Vue 框架专项

25. 生命周期 (Vue 2 vs Vue 3)
  • Vue 2 : beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed
  • Vue 3 (Composition API) : setup() 替代了 beforeCreatecreated。其他钩子前加 on,如 onMounted, onUpdated, onBeforeUnmount
  • 常用created/mounted (发起请求), beforeUnmount (清除定时器/解绑事件)。
26. 传值的方式
  • 父传子props
  • 子传父$emit
  • 兄弟/跨级 :EventBus (Vue2), Provide/Inject, Vuex/Pinia, $attrs/$listeners
  • 透传$attrs (Vue3 默认开启,Vue2 需配置 inheritAttrs)。
27. 计算属性 (Computed) vs 监听属性 (Watch)
  • Computed
    • 缓存,依赖不变不重新计算。
    • 必须return 一个值。
    • 不支持异步。
    • 适用:一个值受多个值影响(多对一)。
  • Watch
    • 无缓存,数据变就执行。
    • 支持异步操作。
    • 可以监听对象深层变化 (deep: true)。
    • 适用:一个值变化影响多个操作(一对多),或需要执行副作用。
28. Vuex (状态管理)
  • 核心概念
    • State:存放数据。
    • Getters:数据的计算属性。
    • Mutations唯一修改 State 的地方(同步)。
    • Actions:处理异步逻辑,提交 Mutations。
    • Modules:模块化。
  • Vue 3 趋势 :推荐使用 Pinia (更轻量,去掉了 Mutation,支持 TS 更好)。
29. 数据双向绑定原理
  • Vue 2Object.defineProperty()
    • 缺点:无法监听对象属性的新增/删除,无法监听数组下标变化(需用 $set 或替换方法)。
  • Vue 3Proxy
    • 优点:直接代理整个对象,完美监听增删改查,性能更好。
30. v-show vs v-if
  • v-if
    • 真正销毁/创建 DOM 节点。
    • 切换开销大。
    • 支持 <template> 分组。
    • 适用:条件很少改变,或初始不显示。
  • v-show
    • 始终渲染,通过 CSS display: none 控制显示。
    • 切换开销小。
    • 不支持 <template>
    • 适用:频繁切换显示状态。
31. keep-alive
  • 作用 :内置组件,用于缓存动态组件router-view,保留组件状态,避免重复渲染。
  • 生命周期 :被缓存的组件会多出 activated (激活) 和 deactivated (停用) 钩子。
  • 属性include (缓存谁), exclude (不缓存谁), max (最大缓存数)。
32. nextTick
  • 原理 :将回调函数延迟到下一次 DOM 更新循环结束之后执行。
  • 场景 :当你修改了数据,想立即获取更新后的 DOM 元素(因为 DOM 更新是异步的),就需要用 this.$nextTick(() => { ... })await nextTick()

一、怎么实现 apply 函数?

Function.prototype.apply 的作用是改变函数运行时的 this 指向 ,并接收一个参数数组来调用函数。

核心思路
  1. 处理上下文 :如果传入的 thisArgnullundefined,在非严格模式下指向全局对象(浏览器是 window),严格模式下为 undefined
  2. 临时绑定 :将当前函数(调用 apply 的函数)作为传入对象的一个临时属性。
  3. 执行函数 :通过对象调用该临时属性(此时 this 指向该对象),并使用展开运算符 ... 传递参数数组。
  4. 清理现场:删除临时属性,防止污染原对象。
  5. 返回结果:返回函数执行的结果。
代码实现
javascript 复制代码
Function.prototype.myApply = function(context, argsArray) {
  // 1. 处理 context:如果是 null/undefined,指向全局对象 (window)
  // 注意:在严格模式下 this 可能是 undefined,这里做简单兼容处理
  if (context === null || context === undefined) {
    context = typeof window !== 'undefined' ? window : globalThis;
  } else {
    // 如果传入的是基本类型,需要转换为对象 (如 'str' -> new String('str'))
    context = Object(context);
  }

  // 2. 获取调用 myApply 的函数本身
  const fn = this;

  // 3. 定义一个唯一的 Symbol 键,防止覆盖对象原有属性
  const fnKey = Symbol('fn');

  // 4. 将函数挂载到 context 上
  context[fnKey] = fn;

  // 5. 执行函数
  let result;
  if (!argsArray) {
    // 如果没有传参数数组,直接调用
    result = context[fnKey]();
  } else {
    // 如果有参数数组,使用展开运算符传递
    // 需确保 argsArray 是类数组对象,否则报错
    if (!Array.isArray(argsArray) && !(argsArray instanceof Object)) {
       throw new TypeError('CreateListFromArrayLike called on non-object');
    }
    result = context[fnKey](...argsArray);
  }

  // 6. 删除临时属性
  delete context[fnKey];

  // 7. 返回结果
  return result;
};
测试用例
javascript 复制代码
function greet(greeting, punctuation) {
  return greeting + ', ' + this.name + punctuation;
}

const person = { name: 'Alice' };

console.log(greet.myApply(person, ['Hello', '!'])); 
// 输出: "Hello, Alice!"

console.log(greet.myApply(null, ['Hi', '.'])); 
// 输出: "Hi, undefined." (非严格模式下指向 window,window.name 通常为空或特定值)

二、怎么优化 Webpack 打包?

Webpack 优化主要分为两个维度:构建速度优化 (开发体验)和 打包体积优化(用户体验)。结合 2026 年的技术背景,以下是核心策略:

1. 构建速度优化(让打包更快)
  • 开启持久化缓存 (Webpack 5+ 必配)
    利用文件系统缓存,二次构建时复用未变动的模块,速度提升巨大。

    javascript 复制代码
    module.exports = {
      cache: {
        type: 'filesystem', // 使用文件系统缓存
        buildDependencies: { config: [__filename] } // 配置变更时缓存失效
      }
    };
  • 缩小构建范围

    • include / exclude :在 loader 中明确指定只处理 src 目录,排除 node_modules
    • resolve.modules:指定模块搜索路径,减少递归查找。
    • resolve.extensions :减少后缀尝试次数,把常用的 .js, .jsx 放前面。
  • 多线程并行处理
    使用 thread-loader 将耗时的 loader(如 babel-loader, ts-loader)放入 worker 池中并行运行。

  • 减少插件使用
    生产环境才需要的插件(如压缩、提取 CSS)不要放在开发环境配置中。

2. 打包体积优化(让文件更小)
  • Tree Shaking (摇树优化)

    • 确保代码使用 ES Module (import/export) 语法。
    • package.json 中设置 "sideEffects": false 或配置具体文件,标记无副作用模块。
    • 生产模式默认开启,但需配合 usedExports: true
  • 代码分割 (Code Splitting)

    • 多入口分离 :配置多个 entry
    • SplitChunksPlugin :提取公共代码(如 vendor 包),避免重复打包。
    • 动态导入 :使用 import() 语法实现路由级或组件级的懒加载。
    • optimization: { splitChunks: { chunks: 'all' } // 自动分割所有类型的 chunk }
  • 压缩与优化

    • JS/CSS 压缩 :Webpack 5 内置 TerserPluginCssMinimizerWebpackPlugin(需安装)。
    • 图片压缩 :使用 image-minimizer-webpack-pluginsquash-images-webpack-plugin
    • Gzip/Brotli :使用 compression-webpack-plugin 生成 .gz.br 文件,由 Nginx 直接serve。
  • 外部化依赖 (Externals)
    将大型库(如 React, Vue, ECharts)通过 CDN 引入,不打包进 bundle.

    javascript 复制代码
    externals: {
      react: 'React',
      'react-dom': 'ReactDOM'
    }
  • 分析工具
    使用 webpack-bundle-analyzer 可视化分析包体积,精准定位大文件。


三、讲解下 Webpack 机制

Webpack 是一个静态模块打包工具 。它的核心机制可以概括为:"一切皆模块",从入口出发,递归解析依赖,最终生成一个或多个 Bundle。

1. 核心工作流程 (四大步骤)
  1. 初始化 (Initialization)

    • 读取配置文件 (webpack.config.js) 和 Shell 命令参数。
    • 实例化 Compiler 对象(负责整个构建过程的核心对象)。
    • 注册所有配置的插件 (plugins),监听生命周期钩子。
  2. 编译 (Compilation)

    • entry 入口文件开始。
    • 调用配置的 Loader 对模块进行翻译(如 TS -> JS, SCSS -> CSS)。
    • 分析模块语法(AST),找出该模块依赖的其他模块(import, require)。
    • 递归地对每个依赖模块执行上述过程,直到所有依赖都被处理。
    • 最终形成一张完整的 依赖图 (Dependency Graph)
  3. 输出 (Emission)

    • 根据依赖图和配置,将模块组合成一个或多个 Chunk
    • 将 Chunk 转换成最终的 Bundle 文件(包含运行时代码和模块代码)。
    • 写入文件系统(磁盘)。
  4. 完成 (Done)

    • 触发完成钩子,通知插件构建结束。
2. 核心概念解析
  • Entry (入口):构建依赖图的起点。Webpack 从这里开始识别哪些模块应该被纳入。
  • Output (输出) :定义 Bundle 文件的输出路径和文件名(通常配合 [contenthash] 实现缓存优化)。
  • Loader (加载器)
    • 作用:Webpack 原生只懂 JS 和 JSON。Loader 让它能处理其他类型的文件(CSS, Image, TS 等),将其转换为有效模块。
    • 机制 :链式执行,从右向左(或从下到上)。例如 style-loader(css-loader('a.scss'))
  • Plugin (插件)
    • 作用:扩展 Webpack 的功能,执行更广泛的任务(如打包优化、资源管理、环境变量注入)。
    • 机制 :基于 Tapable 库发布 - 订阅模式,在构建流程的特定生命周期钩子(Hook)中注入逻辑。
  • Mode (模式)
    • development:优化构建速度,启用 NamedModulesPlugin。
    • production:优化输出体积,启用 Tree Shaking, Scope Hoisting, Uglify/Terser。
  • Chunk & Bundle
    • Chunk:代码块,Webpack 内部编译过程中的中间产物。
    • Bundle:最终输出的文件,由一个或多个 Chunk 组成。
3. 运行机制图解(简化版)
javascript 复制代码
[Entry Files] 
    ↓ (读取)
[Loader 转换] (TS->JS, SCSS->CSS)
    ↓ (AST 分析依赖)
[Dependency Graph] (依赖图)
    ↓ (合并)
[Chunks] (代码块)
    ↓ (Plugin 处理/压缩)
[Bundles] (最终文件 -> dist/)
4. 为什么 Webpack 慢?

因为它是全量编译。每次修改代码,它都需要重新走一遍"读取->解析->转换->合并"的流程(虽然有了缓存和 HMR 优化,但原理上仍比 Vite 的 ESM 按需编译重)。这也是为什么现在流行 Vite(开发环境用 ESM 原生能力,生产环境用 Rollup)的原因。

相关推荐
伊可历普斯2 小时前
前端数据校验太难?一个 Zod 就够了
前端·javascript
ou.cs2 小时前
C# params 关键字详解:从入门到精通(保姆级教程)
开发语言·c#·.net
前端 贾公子2 小时前
unplugin-icons == elementPlus自动引入icon
前端·javascript·vue.js
請你喝杯Java2 小时前
Python 后端开发:从虚拟环境、pip、requirements.txt 到项目启动
开发语言·python·pip
光影少年2 小时前
说说模块化规范?CommonJS和ES Module的区别?
前端·javascript·elasticsearch
也曾看到过繁星2 小时前
初识c++
开发语言·c++
2401_874732532 小时前
泛型编程与STL设计思想
开发语言·c++·算法
飞Link2 小时前
具身智能中 Wrapper 架构的深度解构与 Python 实战
开发语言·python·架构