面试一
1、怎么让一个div水平垂直居中
<div class="a">
<div class="b"></div>
</div>
//第一种flex 方法
.a{
width:100%;
height:100vh;
display:flex;
justify-content:center; //水平居中
align-items:centerl;//垂直居中
}
.b{
width:100px;
height:100px;
}
• 方法二:Grid (同样推荐)
.a {
width:100%;
height:100vh;
display:grid;
place-items:center; /* 同时实现水平和垂直居中 */
}
.a {
position: relative;
height: 100vh;
}
.b {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* 使用自身宽高的一半进行反向偏移 */
}
2、HTTP的几种请求方法用途
GET: 请求资源,获取资源
POST:提交数据,用于创建新资源或处理数据
PUT: 替换、更新指定资源所有的内容
DELETE:删除指定资源
PATCH:部分更新指定资源
HEAD:类似GET,但只获取响应头
3、Javascript 怎样添加、移除、移动、复制、创建和查找节点
创建:document.createElement('div')
添加 parent.appendChild(child), parent.insertBefore(newNode, referenceNode)
移除: parent.removeChild(child) 或 child.remove()
• 移动:本质上就是先移除旧位置的节点,再添加到新位置。
• 复制:node.cloneNode(true) // true 为深拷贝,包括子节点
• 查找:
◦ document.getElementById(‘id‘)
◦ document.querySelector(‘.class‘) / document.querySelectorAll(‘p‘)
◦ parent.getElementsByClassName(‘class‘)
4.Js中使用typeof能得到哪些类型,===和==分别在何时使用
• typeof 返回的字符串:"number", "string", "boolean", "undefined", "object" (注意:null 和数组也会返回 "object",这是历史遗留问题), "function", "symbol" (ES6)。
• == (宽松相等) 和 === (严格相等):
◦ ===:推荐使用。首先比较类型,如果类型不同,直接返回 false。类型相同再比较值。
◦ ==:如果类型不同,会先进行类型转换,然后再比较值。规则复杂,容易产生意料之外的结果(如 0 == false 为 true)。
5. 闭包的写法、作用、缺点
for(var i=0;i<5;i++){
((j)=>{
setTimeout(()=>{
console.log(j)
},10) })(i)
}
作用:使函数外部可以操作函数内部的变量。
缺点:
1. 内存泄漏:因为闭包会长期驻留内存,如果使用不当(例如在不需要的DOM元素上绑定事件处理程序),可能导致内存无法被回收。
6. 描述 Vue 组件生命周期 (以 Vue 2 为主
• 创建阶段:
◦ beforeCreate:实例刚创建,data 和 methods 未初始化。
◦ created:实例创建完成,data 和 methods 已可用,但DOM未生成。
• 挂载阶段:
◦ beforeMount:模板编译完成,但尚未挂载到页面。
◦ mounted:实例已挂载到DOM,可以操作DOM。
• 更新阶段:
◦ beforeUpdate:数据更新时,虚拟DOM重新渲染和打补丁之前。
◦ updated:数据更新后,虚拟DOM重新渲染和打补丁完成。
• 销毁阶段:
◦ beforeDestroy:实例销毁之前,此时实例仍完全可用。适合清除定时器、解绑事件。
◦ destroyed:实例销毁后,所有绑定和监听器被移除
7. computed 有啥特点?computed和watch, methods的区别
• computed (计算属性) 特点:
-
缓存性:最大的特点。只有当其依赖的响应式数据发生改变时,才会重新计算,否则直接返回缓存的结果。
-
声明式:像普通属性一样在模板中声明使用,逻辑清晰。
-
同步操作:必须是同步操作,无法处理异步逻辑。
• 三者的区别:
特性 computed watch methods
缓存 有缓存 无缓存 无缓存
使用场景 当一个值依赖于其他一个或多个响应式数据时 当需要在数据变化时执行副作用(如异步请求、复杂逻辑)时 用于绑定事件或需要每次渲染都重新执行的逻辑
异步支持 不支持 支持 支持(但在模板中直接调用异步方法可能不按预期工作)
返回值 必须返回一个值 不返回值,通常用于执行操作 可以返回任何值,也可以不返回
调用方式 在模板中作为属性调用:{{ computedValue }} 在选项中声明,自动监听 在模板中作为方法调用:@click="methodName"
8. Vuex 中 action 和 mutation 有何区别?
• Mutation (变更):
◦ 职责:是修改 Vuex state 的唯一途径。
◦ 特性:必须是同步函数。这样 Devtools 可以准确地跟踪状态变化,方便调试。
◦ 调用:通过 commit('mutationName', payload) 调用。
• Action (动作):
◦ 职责:处理业务逻辑,可以包含任意异步操作(如 API 请求)。
◦ 特性:不直接修改 state,而是通过提交 mutation 来修改。
◦ 调用:通过 dispatch('actionName', payload) 调用。
简单比喻: Mutation 像是会计,只负责记账(修改state);Action 像是业务员,可以出去跑业务(异步请求),然后拿回单据让会计记账。
9. ES6 操作数组方法区别: map, filter, reduce, find
• map:遍历数组的每个元素,对其执行提供的函数,并返回一个由函数结果组成的新数组。原数组不变。用于“映射”或“转换”数组。
◦ const doubled = [1, 2, 3].map(x => x * 2); // [2, 4, 6]
• filter:遍历数组,返回一个由满足条件(函数返回true)的元素组成的新数组。用于“过滤”。
◦ const evens = [1, 2, 3, 4].filter(x => x % 2 === 0); // [2, 4]
• reduce:遍历数组,将每个元素执行一个“缩减器”函数,结果汇总为单个返回值。用于“累加”、“扁平化”或任何需要将数组转换为单一值的操作。
◦ const sum = [1, 2, 3].reduce((acc, cur) => acc + cur, 0); // 6
• find:返回数组中第一个满足所提供测试函数的元素的值。如果没找到,则返回 undefined。
◦ const found = [5, 12, 8, 130].find(num => num > 10); // 12
10. cookies、sessionStorage、localStorage 的区别
特性 cookies sessionStorage localStorage
生命周期 可设置过期时间,否则随浏览器关闭失效 仅限当前会话,关闭标签页或浏览器即失效 永久存储,除非手动清除
存储大小 ~4KB ~5MB ~5MB
与服务器通信 会在每次HTTP请求中自动携带在请求头中,增加流量 不参与服务器通信 不参与服务器通信
API 易用性 原生API较复杂,常用库操作 简单的键值对API(setItem, getItem, removeItem) 同sessionStorage
作用域 在所有同源窗口和标签页中共享 仅在当前浏览器标签页内共享 在所有同源窗口和标签页中共享
面试二
一、选择题(每题10分,共60分,多选题)
1. 关于JavaScript中闭包(Closure)的说法,正确的是
正确答案:A、B、D
- A:闭包可以访问其所在作用域的局部变量 ✅(闭包本质是函数+其词法环境,能访问定义时的外部作用域变量)
- B:闭包会增加内存消耗,因为会持有外部作用域的引用 ✅(被闭包引用的变量不会被垃圾回收,长期存在会占用内存)
- C:闭包只能在函数内部创建,外部无法使用 ❌(闭包可以通过返回函数等方式暴露给外部使用)
- D:闭包常用于实现数据的封装与私有化 ✅(比如模块模式,通过闭包隐藏内部变量,只暴露接口)
2. 下面代码执行后,正确的执行顺序是
console.log(1);
setTimeout(() => { console.log(2); }, 0);
const p = new Promise((resolve) => {
console.log(3);
setTimeout(() => { console.log(4); resolve(); }, 100);
});
p.then(() => { console.log(5); setTimeout(() => { console.log(6); }, 0); });
console.log(7);
正确答案:C(1 3 7 5 2 4 6) 执行逻辑:
- 同步任务:
console.log(1)→ 输出1 - 宏任务:
setTimeout(...,0)放入宏任务队列 - 同步任务:
new Promise中console.log(3)→ 输出3 - 宏任务:
setTimeout(...,100)放入宏任务队列 - 同步任务:
console.log(7)→ 输出7 - 微任务:
Promise.then回调执行 → 输出5,并将setTimeout(...,0)放入宏任务队列 - 宏任务队列按顺序执行:先执行
setTimeout(...,0)→ 输出2;再执行setTimeout(...,100)→ 输出4;最后执行p.then里的setTimeout(...,0)→ 输出6
3. 关于JavaScript基础类型,以下说法正确的是
正确答案:A、B、C
- A:基本类型一共有6种:String、Number、Boolean、Null、Undefined、Symbol ✅(ES6 标准下的6种原始类型)
- B:BigInt 是 ES2020 新增的第7种基本类型 ✅(用于表示任意精度整数)
- C:
typeof null === 'object'是一个历史遗留问题 ✅(JS 最初实现的 bug,一直保留至今) - D:数组(Array)是 JavaScript 的基本类型之一 ❌(数组是引用类型,属于 Object 子类)
4. 以下关于 Vue 计算属性(computed)和侦听器(watch)的说法正确的是
正确答案:A、B、D
- A:computed 有缓存,只有依赖变化才重新计算 ✅(依赖不变时,多次访问会直接返回缓存结果)
- B:watch 适合监听数据变化并执行异步或开销较大的操作 ✅(computed 不适合异步操作,watch 更灵活)
- C:computed 可以实现与 watch 完全相同的功能,性能更高 ❌(computed 是计算值,watch 是监听变化,场景不同,无法完全替代)
- D:watch 可以监听对象的深层属性变化 ✅(配置
deep: true即可深度监听对象内部属性)
5. 关于 this 关键字,下列说法正确的是
正确答案:A、B、D
- A:箭头函数中的 this 在定义时绑定,取决于外层作用域 ✅(箭头函数没有自己的 this,继承自外层作用域)
- B:普通函数的 this 取决于调用方式 ✅(谁调用指向谁,如对象方法、全局调用、bind/call/apply 改变指向)
- C:在严格模式下,未绑定的函数调用中 this 指向 window ❌(严格模式下,未绑定的函数调用中 this 为
undefined) - D:在构造函数中,this 指向新创建的对象 ✅(new 操作符会创建新对象,并将 this 绑定到该对象)
6. 下面代码执行后,result 的值正确的是
const arr = [1, 2, 3, 4];
const result = arr
.filter(x => x % 2 === 0)
.map(x => x * 2)
.reduce((sum, x) => sum + x, 0);
正确答案:B、C、D
- A:result 的值是 12 ❌(实际计算:
filter得[2,4]→map得[4,8]→reduce得12?不,4+8=12,这里需要注意:filter后是[2,4],map后是[4,8],reduce求和是12,所以 A 正确?哦,原选项:- A. result 的值是 12 ✅
- B. filter 之后的数组是 [2,4] ✅
- C. map 之后的数组是 [4,8] ✅
- D. reduce 之后的结果是 14 ❌(实际是 12) 修正:正确答案:A、B、C
二、问答题(每题10分,共40分)
1. 请简述 Vue2 和 Vue3 在响应式系统上的主要区别
| 维度 | Vue2 | Vue3 |
|---|---|---|
| 实现原理 | 基于 Object.defineProperty 对对象属性进行劫持 | 基于 Proxy 对整个对象进行代理 |
| 数组监听 | 重写数组原型方法(push/pop 等)实现监听,无法监听数组 length 变化 | 原生支持数组监听,包括索引修改、length 变化 |
| 新增/删除属性 | 无法自动监听,需使用 Vue.set()/Vue.delete() | 自动监听对象新增/删除属性 |
| 性能 | 递归遍历所有属性,初始化性能开销大 | 惰性代理,只有访问时才劫持,性能更优 |
| 支持类型 | 仅支持对象/数组 | 支持 Map/Set/WeakMap/WeakSet 等更多类型 |
2. 请比较 Vue2 和 Vue3 的生命周期函数的区别
| Vue2 选项式 API | Vue3 组合式 API | 说明 |
|---|---|---|
beforeCreate | setup() | 合并到 setup,setup 是组合式 API 的入口 |
created | setup() | 合并到 setup |
beforeMount | onBeforeMount | 挂载前 |
mounted | onMounted | 挂载完成 |
beforeUpdate | onBeforeUpdate | 更新前 |
updated | onUpdated | 更新完成 |
beforeDestroy | onBeforeUnmount | 卸载前 |
destroyed | onUnmounted | 卸载完成 |
| - | onErrorCaptured | 新增,捕获子孙组件错误 |
| - | onRenderTracked/onRenderTriggered | 新增,调试用,追踪响应式依赖 |
3. 请说明 webpack 和 Vite 在构建上的核心区别
| 维度 | webpack | Vite |
|---|---|---|
| 开发模式 | 打包所有模块后启动开发服务器,冷启动慢 | 基于 ES Module,按需编译,冷启动极快 |
| 热更新 | 重新打包变更模块及依赖,更新速度随项目增大而变慢 | 仅重载变更模块,热更新速度几乎不受项目大小影响 |
| 生产构建 | 全量打包,支持复杂代码分割、tree-shaking | 基于 Rollup 打包,打包速度更快,产物更轻量 |
| 依赖处理 | 打包时处理所有依赖 | 预构建依赖(esbuild),将 CommonJS/UMD 转为 ESM |
| 配置复杂度 | 配置繁琐,需处理 loader、plugin 等 | 开箱即用,内置常见功能,配置更简洁 |
4. 在 Vue 项目中,如何优化首屏加载速度?
- 路由懒加载:使用
() => import('@/views/xxx')拆分路由,按需加载页面代码 - 组件懒加载:异步加载非首屏组件(如
defineAsyncComponent) - 第三方库 CDN 引入:将 Vue、Element UI 等库改为 CDN 引入,减少打包体积
- 代码分割:配置 webpack/Vite 分割 chunk,避免单文件过大
- 图片优化:压缩图片、使用 WebP 格式、图片懒加载
- 开启 Gzip 压缩:服务器配置 Gzip/Brotli 压缩,减小传输体积
- 预加载/预获取:对关键资源使用
<link rel="preload">,对非关键资源使用<link rel="prefetch"> - 减少首屏渲染内容:骨架屏替代空白加载,优先渲染核心内容
- Tree Shaking:移除未使用代码,减小打包体积
- SSR/SSG:服务端渲染或静态站点生成,直接返回首屏 HTML
5. 怎么让一个 div 水平垂直居中
- Flex 布局(推荐):
.parent { display: flex; justify-content: center; align-items: center; } - 绝对定位 + transform:
.parent { position: relative; } .child { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } - Grid 布局:
.parent { display: grid; place-items: center; }
6. HTTP 的几种请求方法用途
- GET:获取资源(查询),参数在 URL,幂等、可缓存
- POST:提交数据(新增),参数在请求体,非幂等
- PUT:更新资源(完整替换),幂等
- DELETE:删除资源,幂等
- PATCH:部分更新资源,非幂等
- HEAD:获取响应头,与 GET 一致但无响应体
- OPTIONS:预检请求,用于跨域时询问服务器支持的方法
7. JavaScript 怎样添加、移除、移动、复制、创建和查找节点
- 创建:
document.createElement('div') - 查找:
getElementById()/querySelector()/querySelectorAll() - 添加:
parent.appendChild(child)/parent.insertBefore(newNode, refNode) - 移除:
parent.removeChild(child) - 复制:
node.cloneNode(true)(true 为深拷贝) - 移动:
parent.appendChild(node)(将已存在节点从原位置移动到新位置)
8. JS 中使用 typeof 能得到哪些类型,=== 和 == 分别在何时使用
- typeof 返回值:
"number"/"string"/"boolean"/"undefined"/"object"/"function"/"symbol"/"bigint" - ===:严格相等,比较值和类型,推荐在所有场景使用(避免类型转换问题)
- ==:宽松相等,会自动类型转换,仅在明确需要类型转换时使用(如判断
null == undefined)
9. 闭包的写法,闭包的作用,闭包的缺点
- 写法:
function createCounter() { let count = 0; return function() { return ++count; }; } const counter = createCounter(); - 作用:
- 封装私有变量,实现模块化
- 延长变量生命周期
- 实现函数柯里化/偏函数
- 缺点:
- 内存泄漏:被闭包引用的变量无法被垃圾回收
- 性能损耗:额外的作用域链查找开销
10. 描述 Vue 组件生命周期(以 Vue2 为例)
beforeCreate:实例初始化后,数据观测/事件配置前created:实例创建完成,数据观测/事件配置完成,$el 未生成beforeMount:挂载开始前,模板编译完成,未渲染到 DOMmounted:挂载完成,DOM 已渲染,可访问 DOM 元素beforeUpdate:数据更新前,DOM 未更新updated:数据更新完成,DOM 已更新beforeDestroy:实例销毁前,仍可访问实例destroyed:实例销毁完成,所有事件监听器被移除
11. computed 有啥特点?computed 和 watch、methods 的区别
| 特性 | computed | watch | methods |
|---|---|---|---|
| 缓存 | 有缓存,依赖不变时直接返回缓存 | 无缓存,数据变化时触发 | 无缓存,每次调用都执行 |
| 使用场景 | 计算衍生值(如过滤列表、求和) | 监听数据变化并执行异步/复杂操作 | 通用业务逻辑,事件处理 |
| 调用方式 | 作为属性访问(this.total) | 配置监听,自动触发 | 作为方法调用(this.handleClick()) |
12. Vuex 中 action 和 mutation 有何区别?
- mutation:
- 同步操作,直接修改 state
- 必须是纯函数,不能有异步逻辑
- 通过
commit()触发
- action:
- 异步操作,不能直接修改 state,需提交 mutation
- 可包含任意异步逻辑(如 API 请求)
- 通过
dispatch()触发
13. ES6 操作数组方法区别(map/filter/reduce/find)
- map:遍历数组,返回新数组,每个元素按规则转换
- filter:遍历数组,返回新数组,包含满足条件的元素
- reduce:遍历数组,将元素累积为一个值(求和、求平均等)
- find:遍历数组,返回第一个满足条件的元素,未找到返回
undefined
14. 描述 cookies、sessionStorage、localStorage 的区别
| 特性 | cookies | sessionStorage | localStorage |
|---|---|---|---|
| 生命周期 | 可设置过期时间,默认会话结束 | 会话结束(标签页关闭) | 永久存储,需手动删除 |
| 存储容量 | 约 4KB | 约 5MB | 约 5MB |
| 与服务器通信 | 随请求自动发送到服务器 | 不发送 | 不发送 |
| 作用域 | 同源(可设置 path/domain) | 同源+标签页 | 同源 |
| API | 原生 API 繁琐 | setItem()/getItem()/removeItem()/clear() | 同 sessionStorage |
总结
这些题目覆盖了JS 基础、异步编程、Vue 核心、工程化等前端高频考点,建议你:
- 重点掌握闭包、this、Promise/Event Loop 等 JS 核心概念
- 熟练 Vue2/Vue3 响应式、生命周期、状态管理
- 熟悉构建工具(webpack/Vite)和性能优化思路
- 多手写代码验证知识点,避免纸上谈兵
面试三
一、不定项选择题
1. 关于 HTTP 响应码
正确答案:A、C
- A. 400:请求出现错误 ✅(客户端请求参数/格式错误)
- B. 403:请求的内容不存在 ❌(403 是禁止访问,404 才是资源不存在)
- C. 304:请求的资源并没有被修改过 ✅(协商缓存,服务器告知客户端使用本地缓存)
- D. 301:请求成功,但结果有多种选择 ❌(301 是永久重定向,300 才是多种选择)
2. 正则与类型判断
var a = /678/, b = /678/;
a == b; // false
a === b; // false
正确答案:B(false false)
解析:正则表达式是对象,==/=== 比较的是引用地址,两个独立正则对象地址不同,故均为 false。
3. 取模运算类型转换
var a = "40", var b = 7;
a % b; // 5
正确答案:C(5)
解析:JS 会自动将字符串 "40" 转为数字 40,执行 40 % 7 = 5,结果为数字 5。
4. CSS position 定位
正确答案:无完全正确选项,最接近为 B(需修正)
- 绝对定位:
absolute→ 相对于最近的有定位的父元素 - 相对定位:
relative→ 相对于自身原位置 - 固定定位:
fixed→ 相对于浏览器窗口 题目表述存在歧义,若按选项理解:- A 选项描述
absolute正确,但未说明relative - B 选项
fixed描述正确,但未对应相对定位 - D 选项
relative描述正确,但未对应绝对定位
- A 选项描述
5. map + parseInt 陷阱
["1", "2", "3"].map(parseInt);
// 结果:[1, NaN, NaN]
正确答案:A
解析:parseInt 接收两个参数(值、进制),map 会传入 (item, index, array),实际执行:
parseInt("1", 0)→ 1parseInt("2", 1)→ NaN(进制 1 无效)parseInt("3", 2)→ NaN(二进制中 3 无效)
6. substring 与 slice 适用范围
正确答案:D
substring:仅可用于字符串slice:可用于字符串和数组
二、判断题
- Cookie 未设置有效期,浏览器关闭后 cookie 还是存在的 → 错(会话级 Cookie 会在浏览器关闭后删除)
- typeof(Null) === 'undefined' → 错(
typeof null === 'object',且Null不是合法标识符,应为null) - HTTP2 多路复用:在一个 TCP 连接中并行传输多个 HTTP 请求/响应,避免了 HTTP1.x 的队头阻塞问题,提升传输效率。
三、解答题
1. Vue2/Vue3 响应式原理区别
| 维度 | Vue2 | Vue3 |
|---|---|---|
| 实现 | Object.defineProperty 劫持对象属性 | Proxy 代理整个对象 |
| 数组监听 | 重写数组原型方法,无法监听 length/索引变化 | 原生支持数组所有操作监听 |
| 新增属性 | 需 Vue.set() 手动监听 | 自动监听对象新增/删除属性 |
| 性能 | 递归遍历所有属性,初始化开销大 | 惰性代理,访问时才劫持,性能更优 |
| 支持类型 | 仅对象/数组 | 支持 Map/Set/WeakMap 等更多类型 |
2. 代码执行顺序 + 多请求方案
console.log('1')
let promise1 = new Promise(function (resolve) {
console.log('2')
resolve()
console.log('3')
}).then(function () {
console.log('4')
})
setTimeout(function(){
console.log('5')
}, 0)
console.log('6')
执行顺序:1 → 2 → 3 → 6 → 4 → 5
- 同步任务:
1→2→3→6 - 微任务:
Promise.then→4 - 宏任务:
setTimeout→5
发起多个请求的方案:
Promise.all():所有请求完成后统一处理Promise.race():第一个完成的请求先处理Promise.allSettled():所有请求完成(无论成功/失败)后处理
3. JS 实现 10-100 随机数数组并排序
// 生成 10 个 10~100 之间的随机整数
const arr = Array.from({ length: 10 }, () =>
Math.floor(Math.random() * 91) + 10
);
// 升序排序
arr.sort((a, b) => a - b);
console.log(arr);
四、选择题
1. 动态改变层内容的方法
正确答案:A、B、C、D(全选)
- A.
innerHTML:直接修改 HTML 内容 - B.
innerText:修改纯文本内容 - C. 隐藏/显示层:视觉上改变内容展示
- D.
display属性:控制元素显示/隐藏
2. 图片模拟提交按钮
正确答案:A
解析:图片没有 onSubmit 事件,需在 onClick 中手动调用 form.submit() 提交表单。
3. CSS 选择器权重排序
选择器权重规则:内联样式 > ID 选择器 > 类/属性/伪类选择器 > 元素/伪元素选择器
- a)
.list .box p→ 类+类+元素 → (0,2,1) - b)
#list .box div span→ ID+类+元素+元素 → (1,1,2) - c)
.list span→ 类+元素 → (0,1,1) - d)
#list #box→ ID+ID → (2,0,0) - e)
p:last-child→ 元素+伪类 → (0,1,1) - f)
style(内联样式)→ (1,0,0,0)
排序结果:f > d > b > a > c = e → 正确答案:C
4. 数组声明错误选项
正确答案:C
var arr[]=new Array(3)(4)→ 语法错误,数组声明不能写[]赋值- 其他选项:A/B/D 均为合法数组声明方式
5. map + parseInt 陷阱(同轻喜到家第5题)
正确答案:A([1, NaN, NaN])
6. 不属于 document 对象的方法
正确答案:D
bgColor()不是 document 方法,document.bgColor是旧版属性,已废弃- A/B/C 均为 document 标准方法
7. 不是 canvas 的方法
正确答案:D
controller不是 canvas 方法,getContext()/fill()/stroke()是 canvas 核心绘图方法
8. 变量提升与作用域
var name = 'World';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
// 输出:Goodbye Jack
正确答案:A
解析:函数内 var name 存在变量提升,if 判断时 name 为 undefined,进入 if 分支赋值为 Jack。
9. setTimeout 用法
setTimeout("check", 10)
正确答案:D
解析:setTimeout 第二个参数是延迟毫秒数,10 毫秒后执行 check 函数一次,不是循环执行。
10. typeof null
var temp = null;
alert(typeof temp); // "object"
正确答案:B
解析:typeof null 返回 "object" 是 JS 历史遗留 bug。
五、问答题
1. 同步和异步的区别
- 同步:代码按顺序执行,需等待前一个任务完成才执行下一个,会阻塞主线程
- 异步:不等待前一个任务完成,直接执行后续代码,异步任务完成后通过回调/Promise 处理结果,不阻塞主线程
2. CSS 动画和 JS 动画的区别
| 维度 | CSS 动画 | JS 动画 |
|---|---|---|
| 实现 | 基于 @keyframes/transition,由浏览器 GPU 加速 | 基于 JS 定时器/requestAnimationFrame 操作 DOM |
| 性能 | 性能更优,浏览器优化渲染,避免 JS 主线程阻塞 | 性能相对较低,频繁操作 DOM 可能导致重绘/重排 |
| 控制粒度 | 控制粒度较粗,仅能定义关键帧 | 控制粒度精细,可动态调整动画参数 |
| 适用场景 | 简单过渡、循环动画 | 复杂交互、动态逻辑动画 |
3. 优雅降级和渐进增强
- 优雅降级:先构建完整功能的现代版网站,再针对低版本浏览器做兼容处理,保证核心功能可用
- 渐进增强:先构建基础功能的核心版网站,再针对现代浏览器逐步增强交互和视觉效果
4. 网页字体使用奇数还是偶数
推荐使用偶数字号
- 原因:浏览器渲染时,偶数字号在不同设备上更清晰,避免因像素对齐问题导致字体模糊;奇数字号在部分设备(如 Retina 屏)可能出现边缘锯齿。
5. 虚拟 DOM 实现原理
- 用 JS 对象模拟真实 DOM 树(虚拟 DOM 树)
- 状态变化时,生成新的虚拟 DOM 树
- 通过 Diff 算法对比新旧虚拟 DOM 树,找出差异
- 将差异批量更新到真实 DOM 树,减少重绘/重排次数,提升性能
6. Vue 路由跳转方式
<router-link to="path">标签式跳转this.$router.push(path)编程式跳转(保留历史记录)this.$router.replace(path)编程式跳转(替换当前历史记录)this.$router.go(n)前进/后退 n 步this.$router.back()后退一步this.$router.forward()前进一步
7. Vue 中实现跨域
- 开发环境:配置
vue.config.js中devServer.proxy代理请求 - 生产环境:
- Nginx 反向代理
- JSONP(仅支持 GET 请求)
- CORS(服务器端配置
Access-Control-Allow-Origin) - postMessage(跨窗口通信)
8. Vue 中引入 jQuery
- 安装:
npm install jquery --save - 全局引入:在
main.js中import $ from 'jquery',并挂载到 Vue 原型Vue.prototype.$ = $ - 组件内引入:
import $ from 'jquery'直接使用
9. Vue-Router 动态路由
- 定义动态路由:
{ path: '/user/:id', component: User } - 获取动态参数:
- 组件内:
this.$route.params.id - 模板中:
$route.params.id - 组合式 API:
import { useRoute } from 'vue-router'; const route = useRoute(); route.params.id
- 组件内:
10. Vue3 特性了解
- 响应式系统:基于
Proxy实现,性能更优,支持更多数据类型 - 组合式 API:
setup()替代 Options API,逻辑复用更灵活 - Tree-Shaking 优化:按需引入,打包体积更小
- Fragment/Teleport/Suspense 新组件
- 更好的 TypeScript 支持
- 性能提升:编译优化、diff 算法优化等
总结
这两套题覆盖了**前端基础(JS/CSS/HTTP)、框架核心(Vue2/Vue3)、工程化(跨域/构建/性能)**等高频考点,建议你重点巩固:
- JS 类型转换、异步编程、变量提升等核心概念
- Vue 响应式原理、路由、状态管理
- CSS 选择器权重、布局、动画
- 浏览器缓存、跨域、性能优化
面试四
一、JavaScript 部分(10题)
1. 选择题
[1,2,3].map(parseInt)
结果为: A. [1,2,3] B. [1, NaN, NaN] C. [NaN, NaN, NaN] D. [1, 2, NaN] 答案:B
2. 选择题
var a = {n:1};
var b = a;
a.x = a = {n:2};
console.log(a.x);
console.log(b.x);
输出: A. undefined, {n:2} B. {n:2}, {n:2} C. undefined, undefined D. {n:2}, undefined 答案:A
3. 选择关于 Promise 执行顺序,正确顺序是:
setTimeout(()=>console.log(1),0)
Promise.resolve().then(()=>console.log(2))
console.log(3)
A. 1 2 3 B. 3 2 1 C. 2 3 1 D. 3 1 2 答案:B
4. 判断typeof null === 'object' 是 JS 设计错误,null 是基本类型。()
答案:对
5. 选择以下能深拷贝对象的是:
A. Object.assign B. 扩展运算符... C. JSON.parse(JSON.stringify) D. 直接赋值
答案:C
6. 选择题
function test(){
let a = 1;
return ()=>{console.log(a)}
}
test()();
涉及的特性是: A. 原型链 B. 闭包 C. 继承 D. 变量提升 答案:B
7. 选择以下哪个方法不会改变原数组:
A. push B. splice C. slice D. sort 答案:C
8. 判断箭头函数没有自己的 this,没有 arguments,不能用作构造函数。()
答案:对
9. 选择题
let arr = [1,,3]; arr.length 结果是:
A. 2 B. 3 C. 报错 D. 0
答案:B
10. 手写实现函数:生成 10 个 10~100 随机整数,升序排序并去重。
答案
function getArr() {
let arr = Array.from({length:10},()=>Math.floor(Math.random()*91)+10)
arr = [...new Set(arr)].sort((a,b)=>a-b)
return arr
}
二、Vue2 部分(8题)
1. 选择Vue2 响应式核心 API 是:
A. Proxy B. Object.defineProperty C. Reflect D. Observer 答案:B
2. 选择Vue2 中无法监听数组哪个操作:
A. push B. pop C. 通过下标修改 arr[0]=1 D. shift 答案:C
3. 判断Vue2 computed 有缓存,依赖不变不会重新计算。()
答案:对
4. 选择Vue2 父子组件通信,子传父用:
A. props B. $emit C. provide/inject D. vuex 答案:B
5. 选择Vue2 生命周期中,DOM 渲染完成在:
A. created B. beforeMount C. mounted D. beforeUpdate 答案:C
6. 判断Vue2 给对象新增属性,必须用 Vue.set 才能响应式。()
答案:对
7. 选择Vue2 路由跳转不留下历史记录:
A. push B. replace C. go D. link 答案:B
8. 手写Vue2 中实现一个防抖指令,限制按钮 500ms 内重复点击。
答案
Vue.directive('debounce', {
inserted(el,binding){
let timer
el.addEventListener('click',()=>{
clearTimeout(timer)
timer = setTimeout(()=>{
binding.value()
},500)
})
}
})
三、Vue3 部分(8题)
1. 选择Vue3 响应式核心是:
A. Object.defineProperty B. Proxy C. setter D. getter 答案:B
2. 选择Vue3 组合式 API 入口是:
A. created B. setup C. beforeCreate D. render 答案:B
3. 选择获取路由参数 useRoute 所在包是:
A. vue B. vue-router C. @vue/runtime D. vuex 答案:B
4. 判断Vue3 支持 Fragment,组件可多个根节点。()
答案:对
5. 选择Vue3 中定义基本类型响应式用:
A. reactive B. ref C. computed D. watch 答案:B
6. 选择Vue3 中清除响应式监听用:
A. stop B. clear C. destroy D. off 答案:A
7. 判断 Vue3 中 reactive 不能直接赋值,否则丢失响应式。()
答案:对
8. 手写题 Vue3 setup 中监听对象深层变化,并在变化后执行请求。
答案
import { watch } from 'vue'
setup(){
const obj = reactive({info:{name:'test'}})
watch(()=>obj.info,()=>{
// 发起请求
},{deep:true})
return { obj }
}
四、其他综合部分(10题,CSS / 浏览器 / 工程化 / 网络)
1. CSS 选择以下居中方案不需要知道子元素宽高的是:
A. margin:auto B. flex 居中 C. 定位+负margin D. table-cell 答案:B
2. CSS 选择选择器权重最高的是:
A. #app .box B. .list #item C. div p D. style内联 答案:D
3. 304 状态码含义:
A. 永久重定向 B. 资源未修改,使用缓存 C. 客户端错误 D. 服务器错误 答案:B
4. 关闭页面即清除,存储约5M,不随请求发送:
A. cookie B. localStorage C. sessionStorage D. indexedDB 答案:C
5. 跨域题 Vue 开发环境跨域常用方案:
A. CORS B. devServer proxy C. JSONP D. postMessage 答案:B
6. 构建工具题 Vite 开发模式基于:
A. CommonJS B. ES Module C. UMD D. AMD 答案:B
7. 浏览器题 宏任务不包括:
A. setTimeout B. Promise.then C. ajax D. script 答案:B
8. 性能题 不属于首屏优化的是:
A. 路由懒加载 B. 图片懒加载 C. 代码压缩 D. 增加全局变量 答案:D
9. 浏览器题 addEventListener 第三个参数为 true 表示:
A. 冒泡 B. 捕获 C. 只执行一次 D. 阻止默认 答案:B
10. 手写题 实现函数防抖(debounce)。
答案
function debounce(fn,delay){
let timer = null
return function(){
clearTimeout(timer)
timer = setTimeout(()=>fn.apply(this,arguments),delay)
}
}
总结
- 先闭卷自测,再对答案,错题重点标注
- JS 重点:EventLoop、parseInt 坑、引用类型、深拷贝、闭包
- Vue2 重点:响应式缺陷、生命周期、通信、数组监听
- Vue3 重点:Proxy、setup、ref/reactive、组合API
- 综合重点:居中、跨域、缓存、构建工具、性能优化