Skip to content
返回

交叉面试

目录

点击展开

交叉面试

二面结束以后,有可能会再找隔壁部门的高级/资深工程师交叉面试。交叉面试会综合考察候选人的技术能力。

注意,不一定所有面试都会有交叉面试,但这些面试题还是要刷一遍的,都是常考题。

求两个数组的交集和并集

给两个数组,求数组的交集和并集

const arr1 = [1, 3, 4, 6, 7]
const arr2 = [2, 5, 3, 6, 1]

function getIntersection(arr1, arr2) {
  // 交集...
}

function getUnion(arr1, arr2) {
  // 并集...
}

参考答案

::: details

要点

代码

const arr1 = [1, 3, 4, 6, 7]
const arr2 = [2, 5, 3, 6, 1]

// 交集
function getIntersection(arr1, arr2) {
  const res = new Set()
  const set2 = new Set(arr2)
  for (let item of arr1) {
    if (set2.has(item)) {
      // 注意,这里要用 Set has 方法,比数组的 includes 快很多
      res.add(item)
    }
  }
  return Array.from(res)
}

// 并集
function getUnion(arr1, arr2) {
  const res = new Set(arr1)
  for (let item of arr2) {
    res.add(item) // 利用 Set 自动去重的特性
  }
  return Array.from(res)
}

// 测试
console.log('交集', getIntersection(arr1, arr2))
console.log('并集', getUnion(arr1, arr2))

:::

数组转树

通常我们有一个包含父子关系的数组,目标是将其转化为树形结构。

示例数据:

const arr = [
  { id: 1, parentId: null, name: 'Root' },
  { id: 2, parentId: 1, name: 'Child 1' },
  { id: 3, parentId: 1, name: 'Child 2' },
  { id: 4, parentId: 2, name: 'Grandchild 1' },
]

目标生成:

const tree = [
  {
    id: 1,
    name: 'Root',
    children: [
      {
        id: 2,
        name: 'Child 1',
        children: [{ id: 4, name: 'Grandchild 1', children: [] }],
      },
      {
        id: 3,
        name: 'Child 2',
        children: [],
      },
    ],
  },
]

参考答案:

::: details

实现思路:

  1. 遍历数组,将每个元素存储到一个以 id 为键的 Map 中。
  2. 再次遍历数组,根据 parentId 将子节点挂载到父节点的 children 属性上。
  3. 提取 parentIdnull 的顶层节点作为树的根。

代码实现:

function arrayToTree(arr) {
  const idMap = new Map()
  const result = []

  // 初始化 Map
  arr.forEach((item) => {
    idMap.set(item.id, { ...item, children: [] })
  })

  // 构建树
  arr.forEach((item) => {
    const parent = idMap.get(item.parentId)
    if (parent) {
      parent.children.push(idMap.get(item.id))
    } else {
      result.push(idMap.get(item.id))
    }
  })

  return result
}

console.log(JSON.stringify(arrayToTree(arr), null, 2))

注意点:

树转数组

将树形结构扁平化为数组,保留原有的层级关系。

示例数据:

const tree = [
  {
    id: 1,
    name: 'Root',
    children: [
      {
        id: 2,
        name: 'Child 1',
        children: [{ id: 4, name: 'Grandchild 1', children: [] }],
      },
      {
        id: 3,
        name: 'Child 2',
        children: [],
      },
    ],
  },
]

目标生成:

const arr = [
  { id: 1, name: 'Root', parentId: null },
  { id: 2, name: 'Child 1', parentId: 1 },
  { id: 3, name: 'Child 2', parentId: 1 },
  { id: 4, name: 'Grandchild 1', parentId: 2 },
]

参考答案:

::: details

实现思路:

  1. 使用递归遍历树。
  2. 在每次递归中记录当前节点的 parentId
  3. 将节点及其子节点逐一添加到结果数组中。

代码实现:

function treeToArray(tree, parentId = null) {
  const result = []

  tree.forEach((node) => {
    const { id, name, children } = node
    result.push({ id, name, parentId })
    if (children && children.length > 0) {
      result.push(...treeToArray(children, id))
    }
  })

  return result
}

console.log(JSON.stringify(treeToArray(tree), null, 2))

注意点:

:::

参考答案: :::details 区别:

特性CookieLocalStorageSessionStorage
写入方式服务端和前端都可写入,不过http-only情况下只允许服务端写入前端前端
存储大小4KB 左右5~10MB5~10MB
生命周期手动设置,默认关闭浏览器失效长期保留,直至用户手动清理缓存当前会话,关闭页面清除
服务器交互 随请求发送到服务器不会不会
数据共享同域下所有页面共享同域下所有页面共享当前页面及子页面共享

应用场景:

前端会有哪些安全问题?该如何预防?

先从应用架构的角度来看,前端可以分为多个核心模块,每个模块都有可能成为攻击目标。

:::details

  1. 用户界面与数据展示层
  1. 业务逻辑层
  1. 数据交互层
  1. 数据存储层
  1. 资源加载与依赖管理层
  1. 构建与部署流程

综上所述,只有从整体应用架构的角度出发,针对各个模块的不同攻击面采取多层次防御措施,才能真正保障前端系统的安全性和稳定性。 :::

常见的 git 命令有哪些?

::: details

  1. 克隆远程仓库 :每个开发者首先需要将远程仓库克隆到本地,以获取项目的最新代码。

    git clone <远程仓库URL>
  2. 创建并切换到功能分支 :在主分支(如 mainmaster)上创建一个新的功能分支,以便在该分支上进行开发,避免直接在主分支上工作。

    git checkout -b feature-branch
  3. 进行开发并提交更改 :在功能分支上进行开发,完成后将更改添加到暂存区并提交。

    git add .
    git commit -m "描述本次提交的内容"
  4. 同步远程主分支的最新更改 :在推送之前,先拉取远程主分支的最新更改,以避免推送时发生冲突。

    git fetch origin main
    git merge origin/main
  5. 推送功能分支到远程仓库 :将本地的功能分支推送到远程仓库,以便其他团队成员可以访问。

    git push origin feature-branch
  6. 创建 Pull Request(PR) :在 GitHub 等平台上,从功能分支向主分支发起 PR,请求将功能分支的更改合并到主分支。

  7. 代码审查与合并 :团队成员对 PR 进行审查,提出修改建议或直接在网页上进行评论。审查通过后,项目管理员或有权限的成员将 PR 合并到主分支。

  8. 删除已合并的功能分支(可选) :为保持仓库整洁,合并后可考虑删除远程和本地的功能分支。

    git branch -d feature-branch
    git push origin --delete feature-branch

注意事项

:::

如何使用 git 多人协作开发?

根据项目的规模、性质和团队需求有不同的安排。

::: details

  1. 小型项目 (例如:1-3 人的小型开发团队)
  1. 中型项目 (例如:3-10 人的团队)
  1. 大型项目 (例如:10 人以上的团队)
  1. 开源项目
  1. 闭源项目

总结

:::

是否熟悉 Linux 系统,常见的 Linux 命令有哪些?

::: details

  1. 文件与目录操作
  1. 文件内容查看与编辑
  1. 权限管理
  1. Git 与版本控制
  1. 系统管理与监控
  1. 网络操作
  1. 日志查看
  1. 包管理
  1. 前端开发相关
  1. 自动化与调度

:::

如何调试前端代码?

::: details 调试前端代码的关键考点是调试流程和工具的掌握。

调试的目标是识别和修复代码中的问题。

我们可以从以下几个方面来看:

  1. 调试流程

    • 重现问题 :确保你能准确重现问题,了解问题发生的条件。
    • 隔离问题范围 :通过分段注释、简化代码等方式,将问题范围逐渐缩小,便于定位问题。
    • 检查错误信息 :查看浏览器的控制台,检查是否有报错或警告,通常浏览器会提供比较详细的错误信息和堆栈跟踪。
  2. 常用调试工具

    • 浏览器开发者工具 :Chrome、Firefox 等浏览器都自带强大的开发者工具,可以用来检查 DOM、样式、网络请求、控制台输出等。
    • 断点调试 :通过在代码中设置断点,逐步执行程序,查看各个变量的值,帮助定位问题。
    • 调试输出 :使用 console.log() 或更专业的调试工具(如 debugger)来输出变量或执行状态。
  3. 调试策略

    • 逐步排查 :将代码分解成小模块,逐个排查,确认是哪个环节出了问题。
    • 日志与错误追踪 :在应用中嵌入日志功能,尤其是在生产环境中,利用像 Sentry 这样的工具收集并分析错误信息。

最终,调试的关键是高效的定位和快速的修复。你在进行调试时,首先要了解应用的整体架构,然后再根据问题定位具体的模块或环节进行深入分析。

:::

移动端 H5 如何抓包网络请求?

::: details

抓包网络请求的关键考点是如何能够在移动端环境下监控和捕获网络流量。

尤其是在 H5 应用中,通常需要处理多种协议(如 HTTP、HTTPS)和不同的网络层(如请求、响应、WebSocket 等)。

我们可以从以下几个方面来进行分析:

  1. 抓包工具的选择

    • Charles Proxy :一款功能强大的跨平台抓包工具,支持 HTTP、HTTPS 等协议的抓包,能够分析移动端应用的网络请求。可以通过在手机上设置代理,将手机的流量转发到电脑上进行抓包。
    • Fiddler :类似于 Charles,也是一个常用的抓包工具,可以抓取本地和移动设备的 HTTP 和 HTTPS 请求。通过配置代理服务器,将移动设备的流量通过它进行捕获。
    • Wireshark :适用于更低层次的网络分析,能够捕捉各种网络协议的数据包,但需要更高的网络知识。
    • Chrome DevTools :如果是调试 Web 移动版的 H5 页面,可以使用 Chrome 的开发者工具,直接通过远程调试功能抓取网络请求。
  2. 如何抓包

    • 设置代理 :一般需要在移动端设备上设置代理,指向本地电脑的抓包工具。这样,所有移动设备的流量就会通过你的电脑转发,可以在抓包工具中查看和分析。
      • 在手机的 Wi-Fi 设置中修改代理设置,填写电脑的 IP 地址和抓包工具的端口(通常是 8888 或 8889)。
    • HTTPS 证书问题 :为了抓取 HTTPS 流量,抓包工具(如 Charles 或 Fiddler)通常需要安装它们的根证书。安装后,它们就能解密 HTTPS 请求,从而显示加密流量内容。
    • 查看和分析数据 :通过抓包工具,你可以看到每个请求的详细信息,如请求头、响应头、请求体、响应体等,帮助你诊断请求问题或调试接口。
  3. 调试时注意事项

    • 隐私和安全性 :确保你只在合法的环境下抓包,避免捕获到敏感信息或违反用户隐私。
    • 网络状态 :抓包时可以模拟不同的网络环境(如模拟 3G、4G、Wi-Fi 等),帮助你排查网络质量对请求的影响。

总结来说,抓包的关键是理解代理机制和 HTTPS 解密的过程,掌握合适的工具和流程,才能有效地分析移动端 H5 应用的网络请求。

:::

网页重绘 repaint 和重排 reflow 有什么区别

::: details

网页 重绘(Repaint)重排(Reflow) 的区别可以从性能开销、触发原因和渲染机制三个关键点来分析:

1. 定义与触发条件

2. 性能开销

3. 如何优化

总结来说,重绘和重排的关键区别在于是否涉及布局计算。前者只影响视觉样式,后者会改变页面结构,性能开销也显著不同。

:::

网页多标签页之间如何通讯?和 iframe 如何通讯?

::: details 网页多标签页和 iframe 通讯的关键考点是跨窗口和跨域通信模型的选择,以及不同场景下的适用方法。可以从以下几个方面分析:

1. 多标签页之间的通讯方法


2. iframe 通讯方法


3. 注意事项

总结来说,选择通讯方法的关键在于是否同源、跨域需求、实时性要求等因素。 :::

什么是 axios 拦截器,能用来做什么?

Axios 拦截器的关键是提供了网络请求生命周期的可控节点,能够有效地简化和规范前端网络请求的管理。

::: details

Axios 拦截器 的关键考点在于它是请求与响应流程中的中间层,用来在网络请求前后进行处理,满足业务需求和性能优化。可以从以下几个方面分析其用途和实践方法:


1. 什么是 Axios 拦截器?

Axios 拦截器是 Axios 库提供的功能,可以在请求发出之前和响应数据返回之后进行拦截和处理。 拦截器主要分为两类:


2. Axios 拦截器的应用场景


3. 注意事项

:::

是否熟悉 Performance API ,是否了解常见的性能指标?

::: details

Performance API 的关键考点是提供了一组 Web 标准接口来获取和分析页面性能数据,帮助开发者定位性能瓶颈并优化体验。其中涉及到的常见性能指标如 FP、FCP、LCP 等能直观反映用户的视觉加载体验。


1. 什么是 Performance API?

Performance API 是浏览器提供的内置接口,用于测量网页的加载时间、资源性能和用户体验。

常用接口


2. 常见性能指标


3. 如何使用 Performance API

示例:获取 FCP

new PerformanceObserver((entryList) => {
  const entries = entryList.getEntries()
  entries.forEach((entry) => {
    if (entry.name === 'first-contentful-paint') {
      console.log('FCP:', entry.startTime)
    }
  })
}).observe({ type: 'paint', buffered: true })

4. 注意事项

:::

sourcemap 有何作用,如何配置?

::: details

1. Source Map 的作用及配置

Source Map 是一种将压缩、混淆后的代码映射回源代码的文件,用于调试和定位错误。它的主要作用如下:

配置方法

  1. Webpack 中配置

    module.exports = {
      mode: 'production',
      devtool: 'source-map', // 生成 Source Map
    }

    常见选项:

    • source-map: 完整映射,适合生产环境。
    • cheap-module-source-map: 生成更快,但映射不包括列信息。
    • eval-source-map: 适合开发环境,生成速度快。
  2. Vite 配置

    export default {
      build: {
        sourcemap: true,
      },
    }

:::

什么是 HTTPS 中间人攻击,如何预防

::: details

中间人攻击(MITM, Man-In-The-Middle) 是指攻击者拦截客户端与服务器之间的通信,获取敏感信息或篡改数据。

攻击原理

攻击者通过伪造证书或劫持网络流量,冒充服务器或客户端,使通信双方无法察觉中间人的存在。

预防措施

  1. 启用 HTTPS 和强证书验证

    • 配置 TLS 并购买可信的 SSL 证书。
    • 使用 HSTS(HTTP Strict Transport Security)强制 HTTPS 访问。
  2. 证书固定(Certificate Pinning) 确保客户端只接受特定 CA 签发的证书。

  3. 开启 CORS 配置 配置严格的跨域策略,减少不必要的网络暴露。

  4. 安全头部配置

    • 设置 Content-Security-Policy 防止资源篡改。
    • 设置 Strict-Transport-Security 强制使用 HTTPS。
  5. 客户端验证 通过双向 TLS(Mutual TLS)验证客户端身份。

:::

什么是 OOP ,面向对象三要素是什么?

::: details

1. 什么是 OOP (Object-Oriented Programming)?

面向对象编程(Object-Oriented Programming,简称 OOP)是一种编程范式,通过将程序中的功能和数据封装为对象来实现模块化和复用。对象是具有属性(状态)和方法(行为)的实体,能够与其他对象进行交互。OOP 的核心思想是通过模拟现实世界的模型来提高软件开发的灵活性与维护性

2. 面向对象的三要素

  1. 封装(Encapsulation)

    • 概念 :将数据和操作数据的方法绑定在一起,对外隐藏对象的内部实现细节。

    • 作用

      • 提高代码安全性,避免外部直接修改数据。
      • 便于代码维护,减少不同模块之间的耦合。
    • 示例

      class Person {
        constructor(name, age) {
          this._name = name // 私有变量(约定形式)
          this._age = age
        }
      
        get name() {
          return this._name
        }
      
        set name(newName) {
          if (newName) this._name = newName
        }
      }
      const person = new Person('Alice', 25)
      console.log(person.name) // Alice
  2. 继承(Inheritance)

    • 概念 :子类继承父类的属性和方法,从而避免重复代码。

    • 作用

      • 代码复用,减少重复。
      • 建立层次结构,实现多态。
    • 示例

      class Animal {
        speak() {
          console.log('Animal sound')
        }
      }
      
      class Dog extends Animal {
        speak() {
          console.log('Woof!')
        }
      }
      const dog = new Dog()
      dog.speak() // Woof!
  3. 多态(Polymorphism)

    • 概念 :不同对象可以以不同的形式执行相同的方法调用。

    • 作用

      • 增强代码的灵活性。
      • 提高系统的扩展性。
    • 示例

      class Shape {
        draw() {
          console.log('Drawing shape')
        }
      }
      
      class Circle extends Shape {
        draw() {
          console.log('Drawing circle')
        }
      }
      
      const shapes = [new Shape(), new Circle()]
      shapes.forEach((shape) => shape.draw())

:::

前端常见的设计模式有哪些?以及应用场景

::: details

  1. 单例模式(Singleton Pattern)

  1. 工厂模式(Factory Pattern)

  1. 观察者模式(Observer Pattern)

  1. 策略模式(Strategy Pattern)

  1. 代理模式(Proxy Pattern)

  1. 装饰器模式(Decorator Pattern)

  1. 中介者模式(Mediator Pattern)

  1. 命令模式(Command Pattern)

  1. 适配器模式(Adapter Pattern)

  1. 组合模式(Composite Pattern)

:::

观察者模式和发布订阅模式的区别

::: details

核心区别

详细解释

1. 定义与结构

2. 示例代码

观察者模式

class Subject {
  constructor() {
    this.observers = []
  }

  addObserver(observer) {
    this.observers.push(observer)
  }

  notify(data) {
    this.observers.forEach((observer) => observer.update(data))
  }
}

class Observer {
  update(data) {
    console.log(`Received: ${data}`)
  }
}

const subject = new Subject()
subject.addObserver(new Observer())
subject.notify('Hello')

发布订阅模式

class EventBus {
  constructor() {
    this.events = {}
  }

  subscribe(event, callback) {
    if (!this.events[event]) this.events[event] = []
    this.events[event].push(callback)
  }

  publish(event, data) {
    ;(this.events[event] || []).forEach((callback) => callback(data))
  }
}

const eventBus = new EventBus()
eventBus.subscribe('greet', (data) => console.log(`Received: ${data}`))
eventBus.publish('greet', 'Hello Subscribers!')

区别总结

特性观察者模式发布订阅模式
依赖关系被观察者直接通知观察者发布者与订阅者解耦
中介角色事件中心
适用场景状态变化通知广播消息,模块解耦
耦合度
触发方式被观察者主动触发发布者通过事件中心触发

选择建议

实践应用

总结类比帮助记忆

:::

后端返回 10w 条数据,前端该如何处理?

::: details

当前如果后端一次返回 10w(100,000)条数据,直接在前端全部加载和渲染会导致内存占用高、页面卡顿、响应缓慢等性能问题。因此,处理这类大数据集时应采用以下策略:

  1. 服务器端分页和过滤
  1. 前端虚拟化技术
  1. 异步数据处理
  1. 数据缓存与状态管理

总结

最佳实践是尽量避免一次性将所有 10w 条数据传输到前端显示,优先在服务器端进行分页和过滤;如果确实需要在前端处理大量数据,则应采用虚拟化、懒加载和异步处理等技术以保障页面性能和用户体验。

这种综合策略能有效平衡用户体验与数据处理能力,避免前端资源耗尽的问题。

:::

一个网页,一开始很流畅,越用越卡顿,你怎么办?

::: details

1. 内存泄漏检查


2. 不必要的状态和数据堆积


3. 节流和防抖优化


4. DOM 操作与渲染性能优化


5. 垃圾回收 (GC) 问题


6. 资源管理优化


7. 工具与监控

通过系统化分析和优化,逐步解决页面卡顿问题,提升用户体验。

:::

一个 web 系统,加载很慢,交给你来优化,你会怎么办?

::: details

1. 性能分析与瓶颈定位


2. 资源加载优化


3. 静态资源缓存


4. 网络传输优化


5. 渲染与框架性能优化


6. 后端与 API 优化


7. 用户体验提升


8. 监控与持续优化

通过系统化分析和持续优化,可以显著提升 Web 系统的加载性能,带来更流畅的用户体验。

:::

你知道哪些前端或 JS 工具链?它们分别什么作用?

::: details

前端和 JavaScript 工具链中包含构建、打包、编译、优化等工具,它们为前端开发提供高效的开发和生产环境支持。以下是一些常见工具及其作用:

1. 构建与打包工具

Webpack

Vite

Rollup


2. 编译与转译工具

Babel

SWC (Speedy Web Compiler)

esbuild


3. 包管理工具

npm (Node Package Manager)

Yarn

pnpm


4. 静态代码检查与格式化

ESLint

Prettier


5. 任务自动化工具

Gulp

Parcel


6. 测试工具

Jest

Cypress


总结

选择工具需要结合项目规模、性能要求和团队技术栈,例如:

:::


Share this post on:

上一篇文章
前端 Leader 面试
下一篇文章
项目难点/成绩