前端面试题详解整理24|list2tree函数,diff源码,为啥react好(为什么要用diff,css作用域 less,diff是怎么优化的,

173 阅读13分钟

阿里云前端一面

  1. 复盘笔试题
  2. list2tree函数,我们实际用的pid是哈希值,不能用sort去解决,那么你的算法该怎么改 如果不能使用排序算法来处理节点的顺序,我们可以通过其他方法来构建树形结构。以下是一个基于哈希表的算法,用于将扁平的列表数据转换为树形结构:
function list2tree(list) {
    let hash = Object.create(null); // 使用空对象创建一个哈希表

    // 将列表中的每个节点以其id为键存储到哈希表中
    for (let node of list) {
        hash[node.id] = {...node, children: []}; // 添加一个children属性,用于存储子节点
    }

    // 构建树形结构
    let tree = [];
    for (let node of list) {
        if (node.pid !== null && hash[node.pid]) {
            hash[node.pid].children.push(hash[node.id]); // 将当前节点添加为父节点的子节点
        } else {
            tree.push(hash[node.id]); // 如果没有父节点,则当前节点为根节点
        }
    }

    return tree;
}

这个算法的基本思路是:

  1. 首先,我们创建一个空的哈希表,用于存储每个节点以其id为键的映射关系。
  2. 然后,遍历列表中的每个节点,将其存储到哈希表中,并为每个节点添加一个空数组children,用于存储其子节点。
  3. 最后,再次遍历列表中的每个节点,如果当前节点存在父节点(pid不为null),则将其添加为父节点的子节点;否则,将其添加为根节点。

这种方法的时间复杂度为O(n),其中n为列表中节点的数量。由于使用了哈希表,我们可以在O(1)的时间内获取到每个节点,因此整体的时间复杂度是非常高效的。

  1. 时间复杂度 空间复杂度是多少 对于上面提供的算法,时间复杂度和空间复杂度如下:

时间复杂度:

  • 哈希表构建阶段:遍历列表并将节点存储到哈希表中,时间复杂度为O(n),其中n为列表中节点的数量。
  • 树形结构构建阶段:再次遍历列表并将每个节点添加为其父节点的子节点,时间复杂度为O(n)。 因此,总的时间复杂度为O(n)。

空间复杂度:

  • 哈希表:使用了一个哈希表来存储节点以其id为键的映射关系,哈希表的空间复杂度为O(n),其中n为列表中节点的数量。
  • 树形结构:构建的树形结构仅使用了节点的引用,并不会复制节点的内容,因此树形结构的空间复杂度可以忽略不计。 因此,总的空间复杂度为O(n)。

综上所述,该算法的时间复杂度为O(n),空间复杂度为O(n)。

  1. 你提到说你有学react源码,那么你深入学习了哪个(react16 18 fiber diff )

6. 详细说一下diff源码

Vue.js 中的 Virtual DOM 实现了一种高效的 DOM 更新策略,其中的核心部分是 diff 算法。diff 算法用于比较前后两次 Virtual DOM 树的差异,并且仅对真正发生变化的部分进行更新,以提高性能。

下面是 Vue.js 中 diff 算法的基本实现思路:

  1. 初始化:

    • 当 Vue 组件首次渲染时,会生成当前组件的 Virtual DOM 树。
    • 将该 Virtual DOM 树转换为真实的 DOM,并挂载到页面上。
  2. 更新:

    • 当数据发生变化时,Vue 会重新生成 Virtual DOM 树。
    • 将新的 Virtual DOM 树与之前的 Virtual DOM 树进行比较,找出差异。
  3. 差异查找:

    • 从根节点开始逐层对比新旧 Virtual DOM 树的节点。
    • 如果节点类型不同,则直接替换整个节点。
    • 如果节点类型相同,比较节点的属性和子节点。
  4. 属性比较:

    • 对比新旧节点的属性,找出有变化的属性,并更新到真实 DOM 上。
    • 如果属性值发生变化,则更新真实 DOM 上的属性值。
  5. 子节点比较:

    • 对比新旧节点的子节点列表。
    • 使用 diff 算法找出最小的更新代价,将差异应用到真实 DOM 上。
    • 使用一些优化策略,如同级列表比较、利用唯一 key 进行列表比较等,以提高 diff 的效率。
  6. 更新 DOM:

    • 将找到的差异应用到真实 DOM 上,更新页面显示。

总的来说,Vue.js 中的 diff 算法通过高效地比较新旧 Virtual DOM 树,找出差异,并仅更新真正发生变化的部分,从而提高了页面的渲染性能。Vue.js 中的 diff 算法采用了一些优化策略,如同级列表比较、唯一 key 比较等,以进一步提高 diff 的效率。

React 中的 Virtual DOM 和 diff 算法与 Vue.js 类似,都是用于提高页面渲染性能的关键技术之一。下面是 React 中 diff 算法的基本实现思路:

  1. 初始化:

    • 当 React 组件首次渲染时,会生成当前组件的 Virtual DOM 树。
    • 将该 Virtual DOM 树转换为真实的 DOM,并挂载到页面上。
  2. 更新:

    • 当数据发生变化时,React 会重新生成 Virtual DOM 树。
    • 将新的 Virtual DOM 树与之前的 Virtual DOM 树进行比较,找出差异。
  3. 差异查找:

    • 从根节点开始逐层对比新旧 Virtual DOM 树的节点。
    • 如果节点类型不同,则直接替换整个节点。
    • 如果节点类型相同,比较节点的属性和子节点。
  4. 属性比较:

    • 对比新旧节点的属性,找出有变化的属性,并更新到真实 DOM 上。
    • 如果属性值发生变化,则更新真实 DOM 上的属性值。
  5. 子节点比较:

    • 对比新旧节点的子节点列表。
    • 使用 diff 算法找出最小的更新代价,将差异应用到真实 DOM 上。
    • 使用一些优化策略,如同级列表比较、利用唯一 key 进行列表比较等,以提高 diff 的效率。
  6. 更新 DOM:

    • 将找到的差异应用到真实 DOM 上,更新页面显示。

React 中的 diff 算法与 Vue.js 中的类似,都是通过高效地比较新旧 Virtual DOM 树,找出差异,并仅更新真正发生变化的部分,以提高页面的渲染性能。在实际应用中,React 也采用了一些优化策略来进一步提高 diff 的效率,例如利用组件的 shouldComponentUpdate 方法进行自定义的更新控制。

8. 那么为什么要用diff

使用 diff 算法主要是为了提高页面渲染性能,其原因如下:

  1. 减少 DOM 操作: 直接操作真实 DOM 是非常耗费性能的,因为浏览器需要执行布局和重绘等操作。而 diff 算法能够找出真正发生变化的部分,并只更新这些部分,从而减少了不必要的 DOM 操作,提高了性能。

  2. 减少重绘次数: 当数据发生变化时,如果直接重新渲染整个页面,会导致大量的 DOM 元素重新绘制,造成页面的重绘。而 diff 算法能够找出真正变化的部分,并只对这部分进行更新,从而减少了页面的重绘次数,提高了性能。

  3. 减少网络传输量: 在前端框架中,通常会将页面的状态保存在 Virtual DOM 中,然后通过 diff 算法找出变化的部分,并生成最终的 DOM 更新。这样做可以减少网络传输量,因为只需要传输变化的部分,而不是整个页面的内容。

  4. 提高用户体验: 使用 diff 算法能够实现快速的页面更新,用户可以更快地看到页面的变化,从而提高了用户体验。

综上所述,使用 diff 算法能够有效地提高页面的渲染性能,减少 DOM 操作、减少重绘次数、减少网络传输量,并提高用户体验。因此,现代前端框架都采用了 diff 算法来优化页面渲染过程。

  1. diff是怎么优化的(又扯到memo可以性能优化)

diff 算法主要通过以下几个方面来优化页面渲染:

  1. 同级比较: diff 算法会首先比较同级节点,即只比较同一层级的节点,而不会跨层级比较。这样做可以降低 diff 的复杂度,提高比较的效率。

  2. 利用唯一 key: 在进行列表比较时,diff 算法会利用节点的唯一 key 进行标记,从而快速定位到对应的节点。这样可以避免不必要的节点重新渲染,提高了页面的更新效率。

  3. 组件级别的更新控制: 在 React 中,组件可以通过 shouldComponentUpdate 方法进行自定义的更新控制。这个方法可以让组件决定是否需要重新渲染,从而避免不必要的 DOM 操作。

  4. Memoization: Memoization 是一种将函数的返回值缓存起来的技术。在 React 中,可以通过 useMemo 或 useCallback 来缓存计算结果,避免重复计算。这样可以提高组件的性能,特别是在处理大量计算的场景下。

  5. 虚拟 DOM: 使用虚拟 DOM 可以将页面状态保存在 JavaScript 内存中,然后通过 diff 算法找出变化的部分,并将这部分更新到真实 DOM 上。这样可以避免直接操作真实 DOM,减少了页面重绘的次数,提高了性能。

综上所述,diff 算法通过同级比较、利用唯一 key、组件级别的更新控制、Memoization 等技术来优化页面的渲染过程,减少了不必要的 DOM 操作,提高了页面的更新效率和性能。在实际应用中,可以根据具体场景选择合适的优化策略,从而达到更好的性能表现。

12. css的作用域 less的作用域(扯到css in modules,优化)

  1. 在 CSS 中,作用域指的是样式规则的生效范围,即规定了哪些元素会应用该样式。传统的 CSS 是全局作用域的,即样式规则会应用到整个页面上的所有相匹配的元素。而 Less 是一种 CSS 预处理器,它引入了一些新的概念,其中包括作用域的概念。下面分别介绍 CSS 和 Less 中的作用域:

  2. CSS 作用域:

    • CSS 中的样式规则是全局作用域的,即定义的样式规则会影响到整个页面中所有相匹配的元素。
    • 例如,如果你在 CSS 中定义了一个类 .button 的样式规则,那么所有具有该类的按钮元素都会应用该样式。
  3. Less 作用域:

    • Less 中引入了作用域的概念,可以通过一些特殊的语法来定义局部作用域的样式规则。
    • 使用 Less 中的 & 符号可以引用父选择器,从而实现局部作用域的样式定义。
    • 例如,你可以使用 Less 的嵌套语法来定义一个类 .container,并在其中定义一个局部作用域的 .button 类:
      .container {
        .button {
          // 这里的样式规则只会应用到.container元素内部的.button元素上
        }
      }
      
    • 在 Less 中,使用了嵌套语法后,生成的 CSS 中会自动地将嵌套的样式规则展开为全局作用域的样式规则。

总的来说,CSS 是全局作用域的,而 Less 中引入了局部作用域的概念,通过嵌套语法和 & 符号来实现。这样可以更好地组织样式代码,并减少样式规则之间的冲突。

  1. 你的实习是vue,自己用的是react,那么你自己觉得vue和react哪个好(react)

  2. 选择 Vue.js 还是 React 取决于项目需求、团队经验和个人偏好等因素,每个框架都有其优点和适用场景。虽然您表示偏向于 React,但下面我还是列举一些 Vue.js 的优点,以供参考:

  3. 简单易学: Vue.js 的 API 设计简单明了,学习曲线较为平缓,适合初学者快速上手。

  4. 模板语法: Vue.js 使用了直观的模板语法,可以直接在 HTML 中编写模板,易于理解和维护。

  5. 双向数据绑定: Vue.js 支持双向数据绑定,当数据发生变化时,视图会自动更新,简化了数据和视图的同步工作。

  6. 组件化开发: Vue.js 鼓励组件化开发,能够将页面拆分成多个独立的组件,便于复用和维护。

  7. 生态系统: Vue.js 有着丰富的生态系统,包括 Vue Router、Vuex 等官方插件,以及大量的第三方库和组件,可以满足各种需求。

  8. 性能优化: Vue.js 内置了一些性能优化的机制,如虚拟 DOM 和异步更新等,可以提高页面的渲染性能。

综上所述,虽然您偏向于 React,但在选择框架时仍然需要根据实际情况进行评估和选择。Vue.js 在某些方面可能更适合特定的项目需求或团队背景,因此也值得考虑和尝试。

16. 为啥react好(开始吟唱)

React 作为一种流行的前端框架,在很多方面具有优势,以下是一些常见的认为 React 好的原因:

  1. 组件化开发: React 提倡组件化开发,将 UI 拆分为独立的组件,每个组件负责自己的逻辑和渲染,提高了代码的可复用性和可维护性。

  2. 虚拟 DOM: React 使用虚拟 DOM 技术,通过比较前后两次虚拟 DOM 的差异,最小化 DOM 操作,提高了页面的渲染效率。

  3. 单向数据流: React 使用单向数据流的数据流模型,数据从顶层组件传递到底层组件,使数据流动更加可控,降低了数据流的复杂度。

  4. JSX: React 使用 JSX 语法,将 JavaScript 和 HTML 结合在一起,提高了开发效率和代码的可读性,使组件的编写更加直观和灵活。

  5. 生态系统: React 有着庞大的生态系统,包括 React Router、Redux、Material-UI 等众多优秀的第三方库和组件,可以满足各种需求,提供了丰富的开发工具和资源。

  6. 灵活性: React 本身只关注视图层,不涉及其他方面的逻辑,使其可以与其他库和框架灵活组合,适用于各种不同的项目和场景。

  7. 社区支持: React 有着庞大的社区支持,有很多活跃的开发者和贡献者,提供了丰富的文档、教程和社区资源,使学习和使用 React 变得更加容易和愉快。

综上所述,React 以其组件化开发、虚拟 DOM、单向数据流、JSX、生态系统、灵活性和社区支持等优势,成为了众多开发者和企业选择的首选前端框架之一。

  1. 为什么学习前端

反问

技术面一共几轮 3轮

部门业务 技术栈

通知结果时间

作者:Ditto___
链接:www.nowcoder.com/discuss/529…
来源:牛客网