预览
1-http有哪些状态码
2-==和===区别 它是怎么判断数组/对象一样的
3-怎么判断数组/对象是否一样
4-子组件能修改父组件传入的props吗 父组件如果传了个对象,子组件能修改对象中的值吗
5-v-show v-if区别 使用场景
6-对ts的理解
7-uniapp和h5的区别(小程序和浏览器的区别)
8-怎么判断两个单向链表是否相交
9-冒泡 快排
10-写一个方法合并两个有序数组
11-有用过一些ai工具吗、使用经验、例子
12-对ai的评价
13-个人发展方向 有关注移动客户端吗
1-http有哪些状态码
五大类状态码:
2xx:成功
3xx:重定向,告诉浏览器 你请求的这个资源现在不在这里了,请去另一个地址获取
4xx:客户端错了
5xx:服务器错了
常见组合:
200 OK → 请求成功
201 Created → 资源创建成功
301/302 重定向 → 301永久重定向:资源永久在另一个地址;302临时重定向:资源临时在另一个地址。需要你跳转另一个地址去获取资源。
304 Not Modified → 告诉浏览器,资源没变,可以用缓存的版本,不用重新下载。
304 的工作流程(协商缓存)
1-第一次访问:浏览器请求
main.js,服务器返回文件 + 缓存标识(如ETag或Last-Modified)。浏览器保存文件,并记录缓存信息。2-第二次访问:浏览器发送请求时,带上之前保存的缓存标识。
3-服务器检查文件有没有变化。没变化 → 返回 304,有变化 → 返回 200 和新文件
400 Bad Request → 请求语法错误,服务器无法理解
401 Unauthorized →未授权,需要登录或 token 无效
403 Forbidden →服务器理解请求,但拒绝执行(权限不足)
404 Not Found → 资源不存在
500 Internal Server Error → 服务器内部未知错误
502 Bad Gateway → 网关错误,常见于 Nginx 代理错误
504 Gateway Timeout → 网关超时,后端接口未响应
2-==和===区别 它是怎么判断数组/对象一样的
基础区别:类型不同是,==会做类型转换再比较值,===不会做类型转换直接返回false
当 对象 或 数组 使用 == 或 === 比较时,其实比较的是引用地址,只有指向的内存地址一样,结果才是 true。
3-怎么判断数组/对象是否一样
方法一:JSON 序列化
通过JSON.stringify将数组/对象转化成字符串后进行对比
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(JSON.stringify(arr1) === JSON.stringify(arr2)); // true
方法 2:递归深度比较
function deepEqual(a, b) {
if (a === b) return true;
// 类型不同或其中一个不是对象,直接 false
if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
return false;
}
const keysA = Object.keys(a); // 把对象中的key值以字符串的格式存储在一个数组中
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
for (let key of keysA) {
if (!deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}
// 测试
const obj1 = { name: '婷婷', skills: ['Vue', 'JS'] };
const obj2 = { name: '婷婷', skills: ['Vue', 'JS'] };
console.log(deepEqual(obj1, obj2)); // true
方法 3:使用 Lodash
import _ from 'lodash';
const obj1 = { name: '婷婷', skills: ['Vue', 'JS'] };
const obj2 = { name: '婷婷', skills: ['Vue', 'JS'] };
console.log(_.isEqual(obj1, obj2)); // true
4-子组件能修改父组件传入的props吗 父组件如果传了个对象,子组件能修改对象中的值吗
props 是父组件数据的单向绑定,子组件不能直接去改 props 的值,否则 Vue 会在控制台给出警告;但是如果传递的是引用类型(对象/数组),子组件可以修改它里面的属性值,并且不会触发 Vue 警告
这个现象主要和js传值方式有关:
| 类型 | JS 传递方式 | 子组件是否能修改 |
|---|---|---|
| 基础类型(String、Number、Boolean) | 值传递 | 不能修改 |
| 引用类型(Object、Array) | 引用传递 | 可以修改内部属性 |
Vue 的 props 本身是只读的,但如果传的是引用类型,Vue 只限制你替换整个对象,不限制你修改对象内部,但是不推荐这样做
5-v-show v-if区别 使用场景
| 特性 | v-if | v-show |
|---|---|---|
| 本质 | 控制 DOM 元素是否 创建/销毁 | 控制元素的 显示/隐藏(通过 CSS) |
| 渲染方式 | 条件为 false → 元素 完全移除 | 条件为 false → 元素仍在 DOM,但添加 display: none |
| 初始开销 | 高:切换时要创建/销毁 DOM | 低:只切换样式 |
| 切换开销 | 高:频繁切换性能差 | 低:频繁切换性能好 |
| 初始渲染 | 条件不满足,不会渲染节点,性能更好 | 条件不满足,仍然渲染节点,但隐藏,多了一步操作 |
| 适合场景 | 条件不经常改变(登录状态下才显示的菜单、只在用户操作后出现的弹窗、首次进入页面时需要按需加载的内容) | 条件频繁切换(Tab 选项卡切换、展开/收起的侧边栏、表格中展开详情的功能) |
6-对ts的理解
ts和js的区别:
| 维度 | JavaScript | TypeScript |
|---|---|---|
| 类型系统 | 无类型检查,变量随意赋值 | 有静态类型检查 |
| 错误发现时间 | 运行时 | 编译时 |
| 运行环境 | 直接运行 | 需要编译成 JS |
| 代码可维护性 | 低 | 高 |
| 项目规模 | 适合小型项目 | 适合中大型项目 |
为什么要用 TS:
| JavaScript 痛点 | TS 解决方式 |
|---|---|
| 没有类型限制,变量随便赋值,容易出 bug | 通过静态类型定义,提前检查类型错误 |
| 大型项目多人协作,函数参数、返回值不明确 | 接口(Interface)、类型别名(Type Alias)让数据结构清晰 |
| 运行时报错,排查困难 | 在编译阶段提前发现问题,减少线上 bug |
| 缺乏智能提示,开发体验差 | TS 的类型推断 + IDE 智能提示 |
7-uniapp和h5的区别(小程序和浏览器的区别)
Uni-app 是一个跨端框架,用 Vue 语法编写一套代码,可以同时发布到 小程序端、App 端、H5 端。 其中 H5 就是普通网页,运行在浏览器;小程序运行在微信或其他小程序容器里,底层机制和浏览器有明显区别。
| 维度 | H5(浏览器网页) | 小程序(uni-app 小程序端) |
|---|---|---|
| 运行环境 | 浏览器(WebView) | 小程序容器(微信/支付宝等) |
| 渲染机制 | HTML + CSS + JS 直接渲染 | WXML + WXSS + JS,分为逻辑层和渲染层,双线程通信 |
| API 调用 | 直接使用 DOM、window、document 等原生 API | 无法直接操作 DOM,需要通过小程序提供的 API,比如需要通过 setData 传递数据给视图层 |
| 生态限制 | 几乎无限制,可以使用任何前端库 | 受平台限制,不能随便用外部 JS 库,有沙箱环境 |
| 网络请求 | 任意 HTTP 请求 | 只能走平台提供的 wx.request,需要域名备案和白名单 |
| 性能 | JS、UI 在同一个线程,性能好 | 采用逻辑层和渲染层分离的双线程模型,逻辑层负责运行 JS 代码,渲染层负责 UI ,二者通过数据消息通信,展示通信有延迟,频繁交互性能受限 |
| 发布与使用 | 直接部署到服务器,浏览器访问 URL 即可 | 必须上传到小程序平台审核,用户通过微信或其他客户端访问 |
| 更新方式 | 实时更新,刷新页面即可 | 需要走小程序平台更新,有审核流程 |
| 能力范围 | 受浏览器安全限制 | 可以调用平台能力,如扫码、支付、位置、推送等 |
8-怎么判断两个单向链表是否相交
**思路:**如果两个链表相交,它们的最后一个节点一定是相同的
解法1:暴力解---时间复杂度O(m*n)
function isIntersect(headA, headB) {
let pA = headA;
while (pA) {
let pB = headB;
while (pB) {
if (pA === pB) return true; // 判断节点引用是否相同
pB = pB.next;
}
pA = pA.next;
}
return false;
}
解法2:
思路:先计算两个链表的长度 lenA 和 lenB,让长链表先走 |lenA - lenB| 步,保证两个指针剩余长度一样,两个指针同时移动,每次比较是否相等,如果相等则相交
function isIntersect(headA, headB) {
if (!headA || !headB) return false;
// 计算长度
let lenA = 0, lenB = 0;
let pA = headA, pB = headB;
while (pA) {
lenA++;
pA = pA.next;
}
while (pB) {
lenB++;
pB = pB.next;
}
// 重新指向头结点
pA = headA;
pB = headB;
// 让长链表先走多出来的步数
if (lenA > lenB) {
for (let i = 0; i < lenA - lenB; i++) {
pA = pA.next;
}
} else {
for (let i = 0; i < lenB - lenA; i++) {
pB = pB.next;
}
}
// 同步移动,寻找相交节点
while (pA && pB) {
if (pA === pB) return true;
pA = pA.next;
pB = pB.next;
}
return false;
}
9-冒泡 快排
冒泡:
思路:通过相邻元素两两比较,把最大(或最小)的元素逐步“冒泡”到数组末尾。
时间复杂度分析:
| 情况 | 时间复杂度 | 说明 |
|---|---|---|
| 最优情况 | O(n) | 数组本身有序,只需一轮检查 |
| 平均情况 | O(n²) | 需要比较和交换的次数大约为 n*(n-1)/2 |
| 最坏情况 | O(n²) | 数组完全逆序 |
空间复杂度:O(1):冒泡排序是原地排序,不需要额外存储空间。
快排:
思路:选择一个 基准值(pivot),将数组分为两部分:小于基准值的放左边;大于基准值的放右边。然后对左右两部分 递归排序,最后合并。
时间复杂度分析:
| 情况 | 时间复杂度 | 说明 |
|---|---|---|
| 最优情况 | O(n log n) | 每次平分成两半,递归树高度 log n |
| 平均情况 | O(n log n) | 分区较为均匀 |
| 最坏情况 | O(n²) | 每次分区极度不平衡,比如数组本身有序 |
空间复杂度:O(log n):主要来自递归调用栈。
10-写一个方法合并两个有序数组
双指针比较-- 时间复杂度O(m + n)
function mergeSortedArrays(arr1, arr2) {
const result = [];
let i = 0;
let j = 0;
// 双指针比较
while (i < arr1.length && j < arr2.length) {
if (arr1[i] <= arr2[j]) {
result.push(arr1[i]);
i++;
} else {
result.push(arr2[j]);
j++;
}
}
// 如果 arr1 还有剩余元素,直接放到结果里
while (i < arr1.length) {
result.push(arr1[i]);
i++;
}
// 如果 arr2 还有剩余元素,直接放到结果里
while (j < arr2.length) {
result.push(arr2[j]);
j++;
}
return result;
}
// 测试
console.log(mergeSortedArrays([1, 2, 3, 4], [1, 3, 8, 9]));
// 输出: [1, 1, 2, 3, 3, 4, 8, 9]