某小厂前端实习面试全记录

117 阅读9分钟

预览

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,服务器返回文件 + 缓存标识(如 ETagLast-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-ifv-show
本质控制 DOM 元素是否 创建/销毁控制元素的 显示/隐藏(通过 CSS)
渲染方式条件为 false → 元素 完全移除条件为 false → 元素仍在 DOM,但添加 display: none
初始开销:切换时要创建/销毁 DOM:只切换样式
切换开销:频繁切换性能差:频繁切换性能好
初始渲染条件不满足,不会渲染节点,性能更好条件不满足,仍然渲染节点,但隐藏,多了一步操作
适合场景条件不经常改变(登录状态下才显示的菜单、只在用户操作后出现的弹窗、首次进入页面时需要按需加载的内容)条件频繁切换(Tab 选项卡切换、展开/收起的侧边栏、表格中展开详情的功能)

6-对ts的理解

ts和js的区别:

维度JavaScriptTypeScript
类型系统无类型检查,变量随意赋值有静态类型检查
错误发现时间运行时编译时
运行环境直接运行需要编译成 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

思路:先计算两个链表的长度 lenAlenB,让长链表先走 |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]