前端百问面试题之鱼龙混杂(第二篇)

  if (distance > 0 && document.documentElement.scrollTop === 0) {
    e.preventDefault(); // 阻止页面滚动
    handleRefresh(); // 下拉到一定程度,执行下拉刷新
  }
});

27.说说你对 useReducer 的理解?

理解:

1.useReducer 是 React 提供的一个 Hook,用于实现状态管理和状态更新,它的作用类似于类组件中的 this.setState 方法。通过 useReducer,可以将组件的状态逻辑抽离出来,以更清晰、可维护的方式管理组件的状态。

2.使用 useReducer 需要提供两个参数:reducer 函数和初始状态。其中,reducer 函数接收当前状态和动作(action),并返回新的 状态。

3.useReducer 返回的数组包含当前状态和 dispatch 方法,通过解构赋值可以分别获取它们

useReducer的好处:

1.当状态逻辑较复杂时,可以将其拆分为多个 case,每个 case 只关注自己的逻辑,使代码更易于理解和维护。

2.useReducer 还可以结合 Context API 实现全局状态管理,或者与其他 Hook 如 useEffectuseContext 等搭配使用,实现更强大的功能。

28.谈谈你对BFC的理解?

  1. BFC,或者块级格式上下文(Block Formatting Context),是CSS中的一个重要概念,用于控制和规范块级元素在布局中的表现。理解BFC对于解决布局问题和处理元素之间的相互影响非常有帮助。

BFC是一种重要的CSS布局概念,用于控制块级元素的布局和相互关系。了解BFC如何创建以及它的特性和作用可以帮助开发者更好地控制页面布局,解决一些常见的布局问题。

1. **创建条件**:BFC是在以下情况下创建的:


	* 根元素(HTML根元素)。
	* 浮动元素(`float`属性不为`none`)。
	* 绝对定位元素(`position`属性为`absolute`或`fixed`)。
	* 行内块元素(`display`属性为`inline-block`)。
	* 表格单元格元素(`display`属性为`table-cell`)。
	* `overflow`属性不为`visible`的元素。
2. **特性和作用**:BFC具有以下特性和作用:


	* 内部的块级盒子会在垂直方向上一个接一个地排列。
	* BFC内部的元素不会与浮动元素重叠。
	* BFC可以包含浮动元素,将浮动元素的边界框包含在内。
	* BFC内部的元素会忽略浮动元素,不会与浮动元素重叠。
	* BFC内部的元素不会溢出其容器,它们会在容器内重新布局,不会影响外部元素的位置。
3. **应用场景**:BFC的理解对于解决以下一些常见的布局问题非常有用:


	* 清除浮动:将包含浮动元素的父元素创建为BFC,以清除浮动。
	* 防止外边距合并:在两个垂直外边距发生合并时,将一个元素包含在BFC中,以防止合并。
	* 自适应两栏布局:实现两栏布局时,将左侧栏创建为BFC,以防止右侧栏覆盖。
	* 防止元素溢出:将包含溢出元素的容器创建为BFC,以确保不会影响其他元素的布局。

29.我们应该在什么场景下使用 useMemo 和 useCallback?

useMemouseCallback 都是 React 提供的 Hook,它们都可以用于优化函数组件的性能。

useMemo 的作用是对函数的计算结果进行缓存,只有在依赖项发生变化时才会重新计算

当一个组件中渲染内容需要根据一些复杂的计算结果得出,这个计算过程可能会非常耗时,就可以考虑使用 useMemo 来缓存计算结果,避免不必要的重复计算,并且能够有效地提高渲染性能。

useCallback 的作用是对函数进行缓存,只有依赖项发生变化时才会创建新的函数。

当一个组件中传递给子组件的回调函数需要大量计算,或者是传递给子组件的回调函数会引起子组件的重复渲染时,就可以使用 useCallback 来缓存回调函数。

30.为什么 useState 返回的是数组而不是对象?

在 React 中,useState 是一个用于在函数组件中声明状态的钩子函数。它的返回值是一个长度固定为 2 的数组,而不是一个对象,这是由设计选择所决定的。

使用数组来表示状态,是因为它具有以下优势:

  1. 简单直观:将状态以数组的形式进行管理,可以更容易地理解和使用。
  2. 顺序保持一致:使用 useState 声明多个状态时,它们的顺序和声明的顺序是完全一致的。你可以根据索引访问和更新每个状态,而不需要命名或记住状态的特定名称。
  3. 无需每次指定键:当更新状态时,不需要像使用对象那样指定键。只要调用 useState 返回的第二个元素(通常命名为 setXXX)即可。

31.虚拟DOM一定更快吗?

虚拟 DOM 本身并不一定比直接操作真实 DOM 更快。它的性能优势主要体现在以下几个方面:

  1. 高效的批量更新:虚拟 DOM 可以将多次状态变更批量处理,并通过算法进行优化,最终只更新真实 DOM 中需要变更的部分。这种批量更新的方式可以有效减少对真实 DOM 的频繁操作,提高性能。
  2. 减少重绘和回流:虚拟 DOM 会通过 diff 算法,比较新旧虚拟 DOM 树的差异,并最小化对真实 DOM 的修改。通过最小化修改操作,可以减少浏览器的重绘(repaint)和回流(reflow)操作,从而提升性能。
  3. 跨平台能力:虚拟 DOM 是一个抽象层,可以使得 React 这样的框架同时运行在多个平台上,如浏览器、移动端等。它可以将用户界面渲染为虚拟 DOM,然后再根据具体平台的特性将其转化为真实的 UI。

尽管虚拟 DOM 可以提供性能上的优势,但并不意味着它一定比直接操作真实 DOM 更快。在某些简单场景下,直接操作真实 DOM 可能更加高效。而且虚拟 DOM 本身也会引入一定的开销,比如虚拟 DOM 的生成和 diff 算法的计算等。

32.React中,能否直接将 props 的值复制给 state?

在 React 中,可以把 props 直接赋值给 state,但这样不一定是一个好的做法,因为 propsstate 有不同的含义和用途。

props 表示从父组件传递给子组件的属性,主要用于组件之间传递数据。而 state 则表示组件自身的状态,主要用于保存交互状态或控制组件行为。

虽然 propsstate 的数据形式相同,但它们存在本质的区别:

  1. props 是从父组件传递下来的,子组件不能修改。而 state 是组件自己管理的,可以通过 setState() 方法进行修改。
  2. props 可以用于组件之间传递数据,而 state 主要用于保存组件内部的交互状态。

因此,直接将 props 复制给 state 忽略了组件自身状态的更新和控制,容易导致数据不一致或不可控的情况。在一些特殊场景下,可以将 props 赋值给 state,但需要认真考虑并仔细分析其影响和后果。

33.什么是高阶组件?

高阶组件(Higher-Order Component,简称 HOC)是一个函数,它接收一个组件作为参数,并返回一个新的组件。这个新的组件可以对原组件进行扩展或增强,例如添加一些通用的逻辑、状态、行为等。

高阶组件本质上是一个装饰器模式,通过把通用逻辑从组件中抽离出来,实现代码复用和组件的解耦。高阶组件可以用于很多场景,例如添加权限控制、添加数据逻辑、动态渲染等等。

在 React 中,高阶组件主要通过以下方式实现:

  1. 属性代理:通过 props 将新的属性传递给被包裹的组件。
  2. 反向继承:通过继承被包裹的组件,可以覆盖或增加它的生命周期方法和渲染函数。

使用高阶组件可以有效避免代码冗余和逻辑耦合,提高代码的可维护性和重用性。但需要注意,过度使用高阶组件可能会导致组件层级过深、代码难以理解等问题,因此需要根据具体场景进行评估和使用。

34. React.PureComponent 和 React.Component 有什么区别?

1.React.PureComponentReact.Component会浅比较组件的 props 和 state 的变化,如果相同则不会重新渲染组件。而 React.Component 每次更新都会重新渲染组件。

2.React.PureComponent 会帮助我们优化组件性能,避免不必要的组件重渲染,从而提升应用的性能和用户体验

3.React.PureComponent 的浅比较只检查对象引用是否相等,不会检查对象内部属性的变化,如果使用不当可能会导致错误或不可预期的结果。

4.React.PureComponent,因为每次渲染都会生成新的对象,无法享受到性能优化的好处。

目录

1.清除浮动的几种方式,各自的优缺点,推荐使用哪种?

2.Sass、LESS区别是什么?大家为什么要使用他们?

3.说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?(2)

4.说说React中setState执行机制?

5.如果需要手动写动画,你认为最小时间间隔是多久,为什么?

6.React组件之间如何通信?(4)

7.说说你对受控组件和非受控组件的理解?应用场景?*//**

8.说说你对fiber架构的理解?解决了什么问题?(2)

9.说说react diff的原理是什么?(2)

10.说说你对redux中间件的理解?常用的中间件有哪些?实现原理?(2)

11.路由原理 history 和 hash 两种路由方式的特点?

12.什么是强缓存和协商缓存?(2)

13.iframe有那些缺点?

14.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?(3)

15.window.onload和$(document).ready?

16.React性能优化的手段有哪些?(3)

17.如何通过原生js实现一个节流函数和防抖函数?

18.说说webpack中常见的loader?解决了什么问题?(2)

19.说说如何借助webpack来优化前端性能?(2)

20.重绘和回流(重排)是什么,如何避免?

21.React 和 Vue 在技术层面有哪些区别?

22.React 中的 ref 有什么用,如果获取子组件中的方法?

23.单页应用如何提高加载速度?

24.说说javascript内存泄漏的几种情况?(2)

25.怎么实现图片懒加载,要求写一下思路?

26.原生js如何实现上拉加载下拉刷新?

27.说说你对 useReducer 的理解?

28.谈谈你对BFC的理解?

29.我们应该在什么场景下使用 useMemo 和 useCallback?

32.为什么 useState 返回的是数组而不是对象?

33.虚拟DOM一定更快吗?

34.React中,能否直接将 props 的值复制给 state?

35.什么是高阶组件?

36 React.PureComponent 和 React.Component 有什么区别?

39.props和state相同点和不同点?render方法在哪些情况下会执行?

40.shouldComponentUpdate有什么作用?

41.说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?

42.react新出来两个钩子函数是什么?和删掉的will系列有什么区别?

43.React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?

44.谈谈你对immutable.js的理解?

45.redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的实现原理是什么?

46.redux中同步action与异步action最大的区别是什么?

47.redux-saga和redux-thunk的区别与使用场景?

48.在使用redux过程中,如何防止定义的action-type的常量重复?

49.CDN的特点及意义?

50.为什么for循环比forEach性能高?

51.React render方法的原理,在什么时候会触发?

[52.外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

53.什么是闭包,应用场景是什么?

54.谈谈你是如何做移动端适配的?

55.移动端1像素的解决方案?

56.弹性盒中的缩放机制是怎样的?

57.说说你对useEffect的理解,可以模拟哪些生命周期?

58.说说Real DOM和Virtual DOM的区别?优缺点?

59.说说React中setState和replaceState的区别?

60.说说react中onClick绑定后的工作原理?

61.Redux的实现原理,写出其核心实现代码?

62.什么是垂直外边距合并?说说合并后的几种情况?

63.useEffect的依赖为引用类型如何处理?

64.知道react里面的createPortal么,说说其使用场景?

65.Provider和connect的底层原理实现,写出其核心代码?


35.props和state相同点和不同点?render方法在哪些情况下会执行?

Props(属性)和 State(状态)是 React 组件中用于管理数据的两个概念。

相同点:

  1. 它们都是用于存储和管理组件数据的。
  2. 当它们的值发生变化时,都可以触发组件重新渲染。

不同点:

  1. Source(数据来源):Props 是从父组件传递给子组件的,而 State 则是在组件内部定义和管理的。
  2. Mutability(可变性):Props 是只读的,无法在子组件内部直接修改,只能通过父组件重新传递新的 Props。而 State 可以在组件内部进行修改和更新。
  3. 更新方式:当 Props 发生变化时,React 会自动进行组件的重新渲染。而 State 的更新需要调用组件的 setState 方法来触发重新渲染。

关于 render 方法的执行情况:

  1. 初始渲染:组件首次被渲染时,render 方法会被调用,并生成对应的虚拟 DOM 树。
  2. 数据变化:当组件的 Props 或 State 发生变化时,React 会重新调用 render 方法来更新虚拟 DOM,并与之前的虚拟 DOM 进行对比。
  3. 强制更新:通过调用组件的 forceUpdate 方法可以强制触发 render 方法的执行,即使 Props 和 State 没有发生变化。
  4. 父组件更新:如果父组件进行重新渲染,子组件的 render 方法也会被调用。

需要注意的是,只有在 render 方法中返回的虚拟 DOM 与之前的虚拟 DOM 不同,React 才会重新渲染真实 DOM,并更新到页面上。

36.shouldComponentUpdate有什么作用?

shouldComponentUpdate 是 React 组件的生命周期函数之一,用于控制组件是否需要重新渲染。

当组件的 Props 或 State 发生变化时,React 会自动触发组件的重新渲染,但是在渲染之前,React 会调用 shouldComponentUpdate 方法来判断是否需要重新渲染。如果 shouldComponentUpdate 返回 true,则组件将继续进行重新渲染;如果返回 false,则组件将停止重新渲染,直接使用之前的结果。

shouldComponentUpdate 的作用主要有以下两个方面:

  1. 性能优化:在某些情况下,组件可能会因为不必要的重新渲染而浪费大量性能。比如,在组件的某个 Prop 值没有发生变化时,我们可以通过重写 shouldComponentUpdate 方法来告诉 React 直接复用上次的渲染结果,从而避免不必要的计算和渲染,提升应用性能。
  2. 控制组件渲染的粒度:有些组件可能包含多个子组件,当 Props 或 State 发生变化时,所有子组件都会被重新渲染,即使对于某些子组件来说,数据并没有发生变化。此时,我们可以通过在父组件中重写 shouldComponentUpdate 来手动控制子组件的重新渲染,从而优化渲染性能和用户体验。

需要注意的是,shouldComponentUpdate 每次在重新渲染之前都会被调用,因此返回 false 可以有效地防止组件重复渲染。

37.说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?

虚拟 DOM(Virtual DOM)是 React 中的一种机制,通过在内存中构建一棵轻量级的虚拟 DOM 树来代替操作浏览器 DOM,从而提高组件的渲染性能和用户体验。

在 React 中,当组件的 Props 或 State 发生变化时,React 会根据最新的数据重新生成一棵虚拟 DOM 树,并与之前的虚拟 DOM 树进行对比。在对比的过程中,React 会找到两棵树中不同的节点,并将它们对应的真实 DOM 节点进行修改、删除或添加,最终将更新后的 DOM 渲染到页面上。

虚拟 DOM 的 diff 算法是 React 优化渲染性能的核心。在 diff 算法中,每个节点都有一个唯一的标识符,称为 key。当新旧虚拟 DOM 树进行对比时,React 会通过 key 来判断两个节点是否表示相同的内容。在判断过程中,React 会先以新节点为基准,在旧节点中查找对应的节点。如果找到了相同的节点,则进行更新;否则,将新节点插入到旧节点中或从旧节点中删除。

在使用 React 进行开发时,我们应该尽量避免使用索引作为 key,因为索引本身并没有表示唯一性,容易造成错误的判断结果和性能问题。相反,我们应该在数据中为每个元素提供一个唯一的标识符,例如数据库中的 ID 或者全局唯一的 UUID。

需要注意的是,虽然虚拟 DOM 可以有效地降低浏览器对真实 DOM 的操作次数,但也会带来一些额外的开销。例如,在生成和比较虚拟 DOM 树时,需要进行大量的计算和判断,可能会影响应用的整体性能。因此,在实际开发中,我们需要根据具体情况,权衡使用虚拟 DOM 的益处和代价,选择最适合自己应用的方案。

38.react新出来两个钩子函数是什么?和删掉的will系列有什么区别?

React 新增的两个钩子函数是 useEffectuseLayoutEffect

useEffect 用于处理组件中的副作用,它在渲染结束后执行一次,并且可以通过参数控制何时重新执行。

useEffect 接收两个参数:第一个参数是回调函数,在组件渲染后执行副作用逻辑;第二个参数是一个数组,用于指定依赖项,当依赖项变化时才会重新执行副作用逻辑。

useEffectcomponentDidMountcomponentDidUpdatecomponentWillUnmount 等方法类似,但是与这些生命周期函数不同的是,useEffect 中的回调函数是异步执行的,也就是说,它可能会在页面渲染完成之后执行。因此,我们需要注意在回调函数中访问组件的 Props、State 或 Ref 等变量时,要确保它们的值是最新的。

useLayoutEffect 的作用和 useEffect 类似,但是它的执行时机不同。useLayoutEffect 在渲染后、浏览器执行绘制之前执行,因此可以在这个回调函数中访问布局信息,并修改元素的样式等。需要注意的是,由于 useLayoutEffect 是同步执行的,因此如果执行的逻辑比较耗时,可能会影响页面的性能,应该谨慎使用。

相比于被删除的 will 系列生命周期函数,useEffectuseLayoutEffect 是基于钩子函数的,而不是基于类的生命周期函数。它们是 React Hooks 的一部分,旨在帮助开发者更加方便地编写组件逻辑和处理副作用。与以前的生命周期函数相比,Hooks 更加经济高效,使代码更加简洁易懂,并且更容易实现复用。

39.React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?

如果你的props.children包含单个React元素或组件,map函数将无法直接使用,因为它期望一个数组来进行映射操作。如果你只有一个子元素,你可以将其包装在一个数组中,然后使用map函数遍历

另一种常见情况是props.children包含多个子元素,每个子元素都有自己的类型。在这种情况下,你可以使用React.Children.map来处理props.children,它会为你处理各种类型的子元素

使用React.Children.map可以避免一些潜在的异常,因为它会处理各种类型的子元素,包括字符串、数字和React元素。如果props.children包含非React元素,直接使用map函数可能会导致异常。

40.谈谈你对immutable.js的理解?

Immutable.js 是 Facebook 开发的一个 JavaScript 库,用于处理不可变(Immutable)数据。它提供了一组用于创建、操作和使用不可变数据结构的 API。不可变数据是指一旦创建就无法被修改的数据,任何对不可变数据的修改都会返回一个新的不可变数据结构,而原始数据结构不会受到影响。

下面是我对 Immutable.js 的理解:

  1. 不可变性:Immutable.js 的核心思想是通过不可变性来管理数据。当我们对不可变数据进行修改时,实际上是创建了一个全新的数据结构,而不是修改原始数据。这样做的好处是可以避免副作用,使代码更加可靠和可预测。
  2. 持久性:Immutable.js 中的数据结构是持久化的,这意味着即使进行了修改,原始数据依然保持不变。这对于性能优化非常重要,因为在大规模数据集上进行修改时,可以复用原始数据的共享部分,而不需要完全复制整个数据结构。
  3. API:Immutable.js 提供了一组强大的 API,用于创建和操作不可变数据。这些 API 包括 List、Map、Set 等各种数据结构,以及一些函数式编程的方法(如 map、filter、reduce 等),用于对数据进行转换和处理。
  4. 并发安全:由于不可变数据是无法修改的,所以多个线程或并发操作可以安全地共享和访问不可变数据。这使得在并发环境下编写可靠和高效的代码变得更加容易。
  5. 性能考虑:尽管创建不可变数据结构可能会产生一些额外的开销,但 Immutable.js 通过使用持久化数据结构、结构共享和结构共享的引用透明性等技术来优化性能,并提供了一些针对特定场景的优化方法。

总的来说,Immutable.js 提供了一种管理不可变数据的方式,通过避免数据的变异和副作用,使代码更加可靠和可维护。它在大规模数据处理、函数式编程和并发操作等方面具有很大的优势。

需要注意的是,使用 Immutable.js 需要权衡数据的复杂度和性能要求,不是所有情况都适合使用不可变数据。在某些简单的场景下,使用原生 JavaScript 的数据结构也可以达到类似的效果。

41.redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的实现原理是什么?

Redux 是一个使用单一数据源和不可变数据的状态管理库,它本身是同步的,但通过中间件可以实现异步操作。Redux 中最常用的异步中间件是 Redux Thunk、Redux Saga 和 Redux Observable。

具体来说,当我们需要在 Redux 中执行异步代码时,通常会使用如下流程:

  1. 在 View 中触发一个异步 Action。
  2. Action 发送到 Reducer,Reducer 更新 Store 中的状态。
  3. 如果需要执行异步操作,Middleware 捕获到这个 Action,并执行异步代码。
  4. 异步代码完成后, Middleware 发送新的 Action 到 Reducer,Reducer 再次更新 Store 中的状态。

实现原理是中间件利用了 Redux 提供的 action 和 reducer 的单向数据流机制,使得 action 可以被拦截并且异步处理后再次派发出去。中间件本质上是对 dispatch 函数的重写,并且它可以执行某些操作,例如异步处理、日志记录、错误报告等。

中间件的原理是 Redux 通过在 dispatch 中间注入中间件的执行代码,在 action 到达 reducer 之前对 action 进行了修改或者是对应的 side effect 操作。具体来说,每个中间件都是一个函数,它接收 store 的 dispatch 和 getState 函数作为参数,返回一个新的函数,这个函数被用来包装 action creator,在 dispatch 前后进行操作。这种方式支持链式调用多个中间件,以便进行不同操作,例如数据处理、异步调用、日志记录、错误报告等。

42.redux中同步action与异步action最大的区别是什么?

Redux中的同步action和异步action的最大区别在于它们处理动作(actions)的方式和触发时间:

  1. 同步Action

    • 同步action是指立即执行的操作,不涉及任何异步操作。
    • 同步action的动作创建函数会立即返回一个包含动作类型和数据的action对象,通常使用dispatch函数触发。
    • 同步action用于处理立即执行的操作,例如用户点击按钮、输入框变化等。
    • 由于同步action是立即执行的,所以它们通常用于处理简单的状态变更,不需要等待异步操作的结果。
  2. 异步Action

    • 异步action是指涉及异步操作的动作,需要等待异步操作的结果,例如网络请求或定时任务。
    • 异步action的动作创建函数通常会返回一个函数,而不是一个包含动作对象的函数。
    • 异步action用于处理需要等待异步操作结果的情况

总之,同步action用于立即触发状态变更,而异步action用于处理需要等待异步操作结果的情况。

43.redux-saga和redux-thunk的区别与使用场景?

Redux Saga 和 Redux Thunk 都是用于处理异步操作的 Redux 中间件,它们在实现和使用上有一些区别,适用于不同的场景。

  1. 区别:
  • 实现方式:Redux Thunk 是一个函数,允许我们在 Action Creator 中返回一个函数,这个函数可以进行异步操作并手动调用 dispatch。而 Redux Saga 则基于 ES6 的 Generator 函数,通过使用特定的语法来处理异步操作。
  • 控制流程:Redux Thunk 使用简单的回调函数来处理异步操作,通常是通过链式调用多个 Action,从而实现异步流程控制。而 Redux Saga 则使用生成器来定义和控制异步操作的流程,通过监听和响应不同的 Action 来执行相应的操作。
  • 异常处理:Redux Thunk 需要手动处理错误,通过 try-catch 捕获异常,并在回调函数中 dispatch 错误信息。而 Redux Saga 具备异常捕获和处理的能力,在 Generator 函数内部可以使用 try-catch 捕获异常,并且可以派发不同的 Action 处理异常情况。
  1. 使用场景:
  • Redux Thunk 适用于简单的异步场景,例如发起一个 AJAX 请求并在请求成功后更新状态。它的学习曲线比较低,容易上手,适合于对异步处理需求不复杂的项目。
  • Redux Saga 适用于复杂的异步场景,例如需要处理多个连续的异步操作、任务取消、并发请求等。它提供了更强大和灵活的异步处理能力,并且通过 Generator 函数的形式使得异步流程易于阅读和维护。但是相对复杂性也较高,需要掌握 Generator 函数和 Saga 相关的代码结构。

总而言之,Redux Thunk 适用于简单的异步操作,学习曲线较低;而 Redux Saga 适用于复杂的异步场景,提供了更强大和灵活的异步处理能力。选择哪个中间件取决于项目的具体需求和开发团队的技术背景。

44.在使用redux过程中,如何防止定义的action-type的常量重复?

在 Redux 中,确保定义的 action type 常量不重复可以通过以下几种方式来实现:

  1. 使用单独的文件来存放 action type 常量:可以创建一个名为 actionTypes.jsconstants.js 的文件,在其中定义并导出所有的 action type 常量。这样做可以集中管理常量,减少重复定义的可能性。
javascriptCopy Code// actionTypes.js
export const ACTION_TYPE_1 = 'ACTION_TYPE_1';
export const ACTION_TYPE_2 = 'ACTION_TYPE_2';
// ...
  1. 使用命名空间或前缀来限定 action type:在定义 action type 常量时,给它们添加命名空间或前缀,以确保全局唯一性。
javascriptCopy Codeexport const NAMESPACE_ACTION_TYPE_1 = 'NAMESPACE/ACTION_TYPE_1';
export const NAMESPACE_ACTION_TYPE_2 = 'NAMESPACE/ACTION_TYPE_2';
// ...
  1. 使用工具库来生成唯一的 action type:可以使用第三方工具库(如uuid)来生成唯一的字符串作为 action type。这样可以防止手动定义的常量重复。
javascriptCopy Codeimport { v4 as uuidv4 } from 'uuid';
export const UNIQUE_ACTION_TYPE = uuidv4();

无论选择哪一种方式,重要的是在整个项目中保持一致性,避免重复定义相同的 action type 常量。这样做可以避免潜在的错误,并提高代码的可维护性。

45.CDN的特点及意义?

CDN(Content Delivery Network,内容分发网络)是一种分布式的网络架构,其目标是通过将内容缓存在离用户较近的边缘节点上,提供更快速、稳定的内容分发服务。CDN的特点和意义如下:

  1. 高效快速:CDN利用分布在全球各地的边缘节点,将内容缓存到离用户最近的节点上,当用户请求内容时,可以从最近的节点获取,减少了传输距离和网络拥堵,提供了更快的响应速度和较低的延迟。
  2. 负载均衡:CDN通过智能路由和负载均衡技术,将用户请求分配到最优的节点,避免了单一服务器的过载,提高了整体的系统吞吐量和可用性。
  3. 提升用户体验:由于CDN提供了更快的响应速度和较低的延迟,用户可以更快速地访问和加载网页、图片、视频等内容,提升了用户的体验感受,降低了用户的等待时间。
  4. 减轻源站压力:通过将静态内容缓存到CDN节点上,可以减轻源站的负载压力,提高源站的可扩展性和稳定性,同时减少了源站与用户之间的直接流量,降低了网络成本。
  5. 抵御网络攻击:CDN可以通过分布式的架构和安全防护机制,提供一定程度的网络攻击防护,如分布式拒绝服务攻击(DDoS)的缓解。
  6. 全球覆盖:CDN网络分布在全球各地的节点,可以实现全球范围内的内容分发,无论用户身处何地,都可以享受到较快速的网络访问。

综上所述,CDN具有高效快速、负载均衡、提升用户体验、减轻源站压力、抵御网络攻击和全球覆盖等特点。在大规模的网络应用中,使用CDN能够显著提升网站性能、可靠性和安全性,为用户提供更好的体验,并降低运营成本。

46.为什么for循环比forEach性能高?

在 JavaScript 中,常用的循环有 for 循环和 forEach 循环。虽然两者都可以遍历数组,但它们的实现方式不同,因此性能也有所不同。

for 循环是一种基于索引值(或下标)的循环方式,通过数组的下标索引来访问数组元素。而 forEach 循环则是一种迭代器,对数组中的每个元素都执行一次回调函数。

因此,for 循环相对于 forEach 循环具有以下优势:

  1. for 循环不需要编写额外的函数,可以直接对数组进行操作,因此其执行过程相对更加高效。
  2. 在 for 循环中,可以通过定义一个本地变量(如var len = arr.length)将数组长度缓存起来,避免多次访问 arr.length 属性导致的性能损失。
  3. 在需要对数组进行修改时,for 循环比 forEach 循环更为方便且高效。因为在 for 循环中,可以通过获取数组的下标索引来修改数组元素,而在 forEach 循环中无法直接修改数组元素。

总体而言,在大多数情况下,for 循环比 forEach 循环更具有优势。但是,对于需要进行异步操作的情况,forEach 循环可能更为适用,因为它可以支持 async/await 操作,而 for 循环不支持。

需要注意的是,虽然 for 循环比 forEach 循环更快,但在实际应用中,在性能方面的差别通常不会太大。因此,选择使用哪种循环方式应该根据实际情况而定,以符合代码的可读性、可维护性和执行效率等方面的要求。

47.React render方法的原理,在什么时候会触发?

render() 方法的原理:

根据组件的状态和属性(props)来生成对应的虚拟 DOM 树。React 使用虚拟 DOM 来表示组件的界面结构,并通过比较更新前后 的虚拟 DOM 树找出差异,然后将差异部分进行高效地更新到真实的 DOM 上,从而实现页面的局部更新

render() 方法会在以下情况下触发:

1.组件首次挂载:当组件第一次被渲染到真实的 DOM 上时,render() 方法会被调用

2.组件的状态或属性发生变化:当组件的状态(通过 setState() 方法更新)或属性发生变化时,React 会自动重新调用 render() 方法,生成新的虚拟 DOM,并进行比较和更新

3.父组件重新渲染:如果父组件的 render() 方法被调用,那么其中包含的子组件的 render() 方法也会被触发

48.![] == ![],![] == [],结果是什么?为什么?

在 JavaScript 中,比较操作符 “==” 用于比较两个值是否相等。对于给定的表达式:

  1. ![] == ![]:表示将两个空数组 [] 进行逻辑非运算,得到的结果都是 false。因此,该表达式相当于 false == false,即比较两个布尔值 false 是否相等。根据 JavaScript 的规则,两个布尔值相等仅在它们的值都为 false 或都为 true 时成立。所以,该表达式的结果是 true
  2. ①、根据运算符优先级 ,! 的优先级是大于 == 的,所以先会执行 ![]

!可将变量转换成boolean类型,null、undefined、NaN以及空字符串(’’)取反都为true,其余都为false。

所以 ! [] 运算后的结果就是 false

也就是 [] == ! [] 相当于 [] == false

②、根据上面提到的规则(如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false转换为0,而true转换为1),则需要把 false 转成 0

也就是 [] == ! [] 相当于 [] == false 相当于 [] == 0

③、根据上面提到的规则(如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较,如果对象没有valueOf()方法,则调用 toString())

而对于空数组,[].toString() -> ‘’ (返回的是空字符串)

也就是 [] == 0 相当于 ‘’ == 0

④、根据上面提到的规则(如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值)

Number(’’) -> 返回的是 0

相当于 0 == 0 自然就返回 true了

综上所述,![] == ![] 的结果是 true![] == [] 的结果是 true

这里需要注意的是,在 JavaScript 中,比较操作符 “" 的规则相对复杂,并且涉及到类型转换。为了避免出现意外的比较结果,推荐使用严格相等操作符 "=”,它会在比较时同时考虑值和类型是否相等,更加准确和可靠。

49.什么是闭包,应用场景是什么?

闭包是指在函数内部创建的函数,并且该函数能够访问到其外部函数的作用域。换句话说,闭包是一个函数以及在该函数被创建时所处的词法环境的组合。

闭包有以下特点:

  1. 内部函数可以访问外部函数中的变量和参数。
  2. 外部函数的执行上下文被保留在内存中,即使外部函数执行完成后,内部函数仍然可以访问外部函数的作用域。
  3. 多个内部函数可以共享同一个父级作用域,形成一个闭包函数族。

闭包的应用场景包括但不限于:

  1. 保护变量:通过使用闭包,可以隐藏变量,只提供对外部函数公开的接口。这样,可以确保变量不会被外部直接修改,增加了数据的安全性。
  2. 计数器和累加器:通过闭包,可以在函数外部保存一个内部状态,并在每次调用内部函数时修改该状态。这一特性可用于实现计数器、累加器等功能。
  3. 延迟执行和回调函数:将函数作为返回值,可以实现延迟执行或者在特定条件满足时回调执行。

50.谈谈你是如何做移动端适配的?

对于移动端适配,一种常用的方法是响应式布局(Responsive Layout)和媒体查询(Media Queries)。以下是一些常见的移动端适配策略:

  1. 使用Viewport meta标签:在HTML文档的头部添加Viewport meta标签,通过设置width=device-width,可以告诉浏览器使用设备的宽度作为页面的宽度。另外,还可以设置initial-scalemaximum-scaleminimum-scale等属性来控制缩放行为。
  2. 使用相对单位:在样式表中使用相对单位(如百分比、em、rem)来定义元素的尺寸和布局,相对单位可以根据屏幕尺寸进行适配。
  3. 弹性布局:使用弹性盒模型(Flexbox)或网格布局(Grid)等弹性布局方式,使得元素能够根据可用空间自动调整大小和位置。
  4. 媒体查询:利用CSS3中的媒体查询功能,根据不同的屏幕尺寸和设备特性,为不同的屏幕宽度范围应用不同的样式规则。可以根据需要调整字体大小、布局结构、隐藏或显示某些元素等。
  5. 图片适配:通过设置图片的最大宽度为100%来保证图片在不同尺寸的屏幕上自适应。同时,使用高分辨率的图片(如Retina屏幕),以提供更清晰的图像。
  6. 测试和调试:在开发过程中,使用模拟器或真实设备进行测试,并通过调试工具(如Chrome开发者工具)来检查和优化页面在不同屏幕大小下的样式和布局。

综合使用以上方法,可以使网页在不同尺寸的移动设备上呈现出良好的用户体验,适应不同的屏幕大小和设备特性。

当然,对于较为复杂的移动端适配需求,可以考虑使用CSS预处理器(如Sass、Less)或CSS框架(如Bootstrap、Foundation)等工具来简化和优化适配过程。

51.移动端1像素的解决方案?

在移动端开发中,由于不同设备的像素密度差异,1像素问题成为了一个常见的难题。如果我们不对这个问题进行针对性的解决,那么会导致页面显示效果不美观,甚至影响用户体验。

以下是一些解决方案:

  1. 使用css3的scale属性:将要渲染的元素放大一倍,然后通过scale缩小回去。例如,将一个1像素的边框放大到2像素,再通过scale(0.5)恢复原来大小。这种方法可以使边框看起来更加清晰,但是可能会影响元素的布局和性能。
  2. 通过伪元素实现:使用伪元素before或after,并设置其content属性为空,然后通过border设置为1像素粗细的边框。例如:
cssCopy Code.box::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    border: 1px solid #ddd;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    z-index: -1;
}

这种方法可以避免影响元素布局,但是可能会增加HTML代码量和CSS复杂度。
3. 通过JavaScript动态设置viewport缩放比例: 使用JavaScript获取设备物理像素和设备独立像素的比例,然后动态设置viewport的缩放比例,从而实现1像素问题的解决。例如:

javascriptCopy Codevar scale = 1 / window.devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width,initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale + ',user-scalable=no');

这种方法可以根据设备分辨率进行动态适配,但是可能会对页面布局和性能产生影响。
4. 使用第三方库:有一些开源的第三方库可以帮助我们解决1像素问题,例如border.csspostcss-1px等。这些库可以通过CSS预处理器或者PostCSS等工具使用。

52.弹性盒中的缩放机制是怎样的?

在弹性盒(Flexbox)布局中,存在一种缩放机制,可以通过调整弹性盒子的基准尺寸和剩余空间的分配方式来实现元素的缩放。这个机制称为「Flex的缩放」。

Flex缩放是通过flex-growflex-shrinkflex-basis这三个属性来控制的:

  1. flex-grow属性:确定弹性盒子在剩余空间中分配的比例,它决定了元素在主轴方向上的扩展能力。默认值为0,即不进行扩展。如果多个弹性盒子都设置了flex-grow,它们将按照数值比例分配剩余空间。
  2. flex-shrink属性:定义了元素在空间不足时的收缩能力,即在元素溢出容器时的缩放比例。默认值为1,表示会收缩。如果多个弹性盒子都设置了flex-shrink,它们将按照数值比例进行收缩。
  3. flex-basis属性:指定了弹性盒子在分配多余空间之前的初始尺寸。可以用像素(px)、百分比(%)或者auto(根据内容大小自动计算)来设置。默认值为auto

下面是一个示例代码,演示了Flex缩放的效果:

htmlCopy Code<div class="container">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>
cssCopy Code.container {
  display: flex;
}
.box {
  flex-grow: 1; /* 元素扩展比例为1 */
  flex-shrink: 1; /* 元素收缩比例为1 */
  flex-basis: 100px; /* 初始尺寸为100px */
  background-color: gray;
  margin: 10px;
}

在上述示例中,.box元素设置了flex-grow: 1;,表示在剩余空间中按比例进行扩展。当容器宽度增加时,.box元素会根据比例分配到的空间进行水平扩展。当容器宽度减小时,.box元素会根据flex-shrink属性进行水平收缩。

需要注意的是,Flex缩放只会发生在弹性盒子的主轴方向上。在交叉轴方向上,元素的尺寸由align-self属性来控制,默认情况下不进行缩放。

53.说说你对useEffect的理解,可以模拟哪些生命周期?

(一)理解:

1)useEffect 是 React Hook 中的一个函数,用于处理副作用操作。副作用操作是指在组件渲染过程中需要进行的除了更新 UI 以外的 其他操作,例如发送网络请求、订阅事件、操作 DOM 等。

2)useEffect 接收两个参数:一个是副作用函数,另一个是依赖项数组。副作用函数会在每次组件渲染完成后执行,而依赖项数组用 于控制副作用函数的执行时机。

(二)可以模拟以下类似的生命周期:

    1)componentDidMount: 在组件初始渲染完毕后执行副作用函数,可以使用空的依赖项数组来模拟。

2)componentDidUpdate: 在组件更新后执行副作用函数,可以使用有依赖项的数组来模拟。

3)componentWillUnmount: 在组件即将销毁前执行清理操作,可以在副作用函数中返回一个清理函数来模拟。

54.说说Real DOM和Virtual DOM的区别?优缺点?

Real DOM(真实DOM)

  1. 优点:Real DOM 是浏览器的底层实现,具有广泛的浏览器支持,并能够直接与硬件和操作系统交互,提供原生性能。

Virtual DOM(虚拟DOM)

  1. 优点

    • 提高性能:减少了对Real DOM的直接操作,从而减少了浏览器的回流(reflow)和重绘(repaint)次数。
    • 更容易进行跨平台开发
    • 更容易实现开发者工具和调试
  2. 缺点

    • 需要额外的内存:虚拟DOM需要在内存中维护一份DOM树的拷贝,占用了一些额外的内存。
    • 学习曲线:使用虚拟DOM需要开发者理解和掌握相应的概念,可能需要一定的学习成本。

Virtual DOM 的优点在于其性能优化和跨平台能力,使得前端开发更加高效。然而,它并不是适用于所有场景的银弹,因为在一些简单的应用中,Real DOM 可能更加直观和高效。在选择使用哪种方式时,开发者需要综合考虑应用的复杂性和性能需求。

55.说说React中setState和replaceState的区别?

在 React 中,setState()和 replaceState()是用于更新组件状态的两个方法。它们之间有一些区别。

1)setState(newState):setState() 方法用于更新组件的状态。它接收一个新状态对象作为参数,并将新状态与当前状态合并。React 会合并状态更新并自动触发组件的重新渲染。这意味着 setState() 是基于当前状态的增量更新方式。例如:

2)replaceState(newState):replaceState()方法也用于更新组件状态,但它不会自动合并新旧状态。相反,它会完全替换掉当前状 态,使用提供的新状态对象来更新组件。这意味着调用 replaceState() 会完全重置组件状态,并强制触发重新渲染。

3)在 React v16.3 之后的版本中,官方不再推荐使用 replaceState(),并且将其作为不稳定的方法。相反,推荐使用函数形式的 setState(),可以更好地处理并发更新的情况,并且可以确保基于最新状态计算的正确结果。

56.说说react中onClick绑定后的工作原理?

在 React 中,onClick是用于绑定点击事件的属性。当元素被点击时,绑定的 onClick事件处理函数会被触发执行。

具体工作原理如下:

1)绑定事件处理函数:在 JSX 中,你可以将 onClick 设置为一个函数

2)渲染并呈现元素:React 会将 JSX 渲染为虚拟 DOM,并将其呈现在浏览器中。在渲染过程中,React 会为每个元素添加事件监听器。

3) 监听点击事件:当元素被点击时,浏览器会触发相应的点击事件。

4)执行事件处理函数:当点击事件被触发时,绑定的事件处理函数会被执行。例如,当点击上述按钮时,handleClick 函数将被调用。

5)需要注意的是,在 React 中,所有事件处理函数都会被自动绑定到组件实例的上下文中。这意味着你不需要手动绑定函数的上下文或使用箭头函数来避免上下文问题。React 会自动确保事件处理函数中的 this指向正确的组件实例。

57.Redux的实现原理,写出其核心实现代码?

下面是 Redux 核心实现的简化代码示例:



// 定义初始状态


const initialState = {


count: 0


};



// 定义 reducer 函数


const reducer = (state = initialState, action) => {


switch (action.type) {


case 'INCREMENT':


return {


...state,


count: state.count + 1


};


case 'DECREMENT':


return {


...state,


count: state.count - 1


};


default:


return state;


}


};



// 创建 Redux store


const store = createStore(reducer);



// 监听状态变化


store.subscribe(() => {


console.log(store.getState());


});



// 派发动作更新状态


store.dispatch({ type: 'INCREMENT' });


store.dispatch({ type: 'DECREMENT' });


## 58.什么是垂直外边距合并?说说合并后的几种情况?


垂直外边距合并(Vertical Margin Collapse)是 CSS 盒模型中的一个特性,指的是两个或多个垂直相邻的元素的上下外边距重叠在一起,合并成一个外边距的现象。



垂直外边距合并可能会导致一些不直观的结果,下面是合并后的几种情况:



1. 兄弟元素的合并:当两个相邻的兄弟元素没有边框、内边距、块格式化上下文分隔或清除浮动的元素,它们的垂直外边距会合并成一个外边距。合并后的外边距大小为两个外边距中的较大值。



1. 嵌套元素的合并:如果一个元素内部没有发生块格式化上下文的分隔,它的上外边距会和第一个子元素的上外边距以及最后一个子元素的下外边距合并。合并后的外边距大小仍然是两个外边距中的较大值。



1. 空块元素的合并:如果一个没有边框、内边距、行内内容和高度的块级元素,它的上下外边距会合并成一个外边距。合并后的外边距大小由元素自身的外边距决定。



1. 父元素与第一个/最后一个子元素的外边距合并:在某些情况下,父元素的上外边距可能会和第一个子元素的上外边距或者父元素的下外边距会和最后一个子元素的下外边距合并。这种情况下,合并后的外边距大小由外层的边界决定。


## 59.useEffect的依赖为引用类型如何处理?


在 React 的 useEffect 钩子中,依赖项(dependencies)用于确定何时执行 effect 函数。默认情况下,React 使用浅比较(shallow comparison)来比较依赖项的值,以确定是否触发 effect。



当依赖项是引用类型(如数组或对象)时,可能会遇到一些问题。因为浅比较只会比较引用值而不会递归比较对象或数组的值,所以当引用类型的值发生改变时,浅比较无法捕获到这些变化。



如果你希望在引用类型的值发生改变时触发 effect,有几种处理方式:


1. 使用深比较(Deep Comparison):手动在 effect 中进行深比较,比较引用类型的值的具体内容,然后根据需要执行相应的操作。可以使用工具库(如 lodash 的深比较函数 isEqual)来简化深比较的过程。



1. 使用唯一标识符:给引用类型的值添加一个唯一的标识符,并将该标识符作为依赖项。当引用类型的值发生改变时,其标识符也会改变,从而触发 effect。



1. 使用 useRef 进行比较:使用 useRef 钩子创建一个可持久化的变量,保存上一次的依赖项值,并在 effect 内部进行比较。


## 60.知道react里面的createPortal么,说说其使用场景?



createPortal 是 React 提供的一个 API,它可以让你将子组件渲染到 DOM 结构中的不同位置(不仅仅是组件所在的容器)。



createPortal 的使用场景包括但不限于以下几种情况:



1. 在组件外部创建容器:有时候,你可能需要在组件的外部创建一个容器,然后将某个子组件渲染到该容器中。createPortal 可以帮助你做到这一点,例如在模态框(Modal)组件中,你可以使用 createPortal 将模态框的内容渲染到根节点之外的某个容器中,以防止样式和事件冲突。


1. 在布局中插入子组件:有时候,你可能希望将某个子组件插入到组件树的特定位置,而不是组件所在的容器中。createPortal 可以让你灵活地管理组件的渲染位置,例如在一个有固定布局的导航栏组件中,你可以使用 createPortal 将弹出菜单组件渲染到根节点之外的导航栏容器中。



1. 与第三方库的集成:有时候,你可能需要将 React 组件嵌入到已有的非 React 代码中(如 jQuery 或其他第三方库)。createPortal 可以帮助你将 React 组件渲染到这些外部代码所控制的 DOM 容器中。



1. 处理 z-index 排序:在某些情况下,你可能需要控制组件在层叠布局中的显示顺序。使用 createPortal 可以将组件渲染到其他 DOM 节点上,通过控制它们的位置来改变层叠顺序。


## 61.Provider和connect的底层原理实现,写出其核心代码?


Provider 和 connect 是 React Redux 中常用的两个组件,它们共同提供了状态管理的能力。下面是它们的底层实现的简化版本核心代码:


1)Provider 的核心代码:


```javascript


import React from 'react';


import PropTypes from 'prop-types';


import { createStore } from 'redux';



class Provider extends React.Component {


static propTypes = {


store: PropTypes.object.isRequired,


children: PropTypes.element.isRequired


};



static childContextTypes = {


store: PropTypes.object.isRequired


};



getChildContext() {


return {


store: this.props.store


};


}



render() {


return React.Children.only(this.props.children);


}


}



export default Provider;


2)connect 的核心代码:



import React from 'react';


import PropTypes from 'prop-types';



export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {


class Connect extends React.Component {


其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。



这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**

《前端开发四大模块核心知识笔记》  

![](https://img-blog.csdnimg.cn/img_convert/b6ecb2c71421efff2a0cd1db5a9d4251.png)



最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。



我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

常用的两个组件,它们共同提供了状态管理的能力。下面是它们的底层实现的简化版本核心代码:


1)Provider 的核心代码:


```javascript


import React from 'react';


import PropTypes from 'prop-types';


import { createStore } from 'redux';



class Provider extends React.Component {


static propTypes = {


store: PropTypes.object.isRequired,


children: PropTypes.element.isRequired


};



static childContextTypes = {


store: PropTypes.object.isRequired


};



getChildContext() {


return {


store: this.props.store


};


}



render() {


return React.Children.only(this.props.children);


}


}



export default Provider;


2)connect 的核心代码:



import React from 'react';


import PropTypes from 'prop-types';



export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {


class Connect extends React.Component {


其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。



这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**

《前端开发四大模块核心知识笔记》  

![](https://img-blog.csdnimg.cn/img_convert/b6ecb2c71421efff2a0cd1db5a9d4251.png)



最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。



我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值