前端面试十大必考面试题(一)

308 阅读10分钟

1.css position 定位属性

  • static: 静态定位,元素按文档流
  • relative: 相对定位,元素保持文档流,可以偏移,作为absolute定位元素的参考容器
  • absolute: 绝对定位,元素脱离文档流,定位基准是最近的祖先元素
  • fixed: 固定定位,脱离文档流,始终以视口为基准定位,页面滚动,元素位置不变
  • sticky: 粘性定位,元素滚动到指定阈值为relative,之后变为fixed(必须设置top,left等值),且父容器需有可滚动的区域

2.css 水平垂直居中

居中元素固定宽高盒模型

  • absolute + 负 margin top(50%)left(50%)
  • absolute + margin auto t0 r0 l0 b0
  • absolute calc(top:50%,-xxpx)

居中元素无宽高盒模型

  • display:flex;给父容器 jcc; aic
  • gird:给父容器设置 place-items:center;
  • absolute + transform top:50% left:50% transform: translate(-50%, -50%)
  • lineheight tac水平居中 设置行内元素 + vertical-align:middle line-height: initial

3.react当中常用的hooks

内置hooks

  • useState:可以使函数组件像类组件一样拥有state,函数组件通过useState可以让组件重新渲染,更新视图。
  • useEffect: 副作用函数
  • useLayoutEffect:是 React Hooks 中的一个函数,它在 DOM 更新后、浏览器绘制前同步执行,适合用于需要读取 DOM 布局并同步更新的场景,以避免视觉闪烁。
  • useMemo:①派生新状态 ②缓存计算结果 (返回的是函数运行的结果)接收一个计算函数
  • useCallback:和useMemo一样,都是在依赖项发生变化后才执行,都是返回缓存的值但是useCallback返回的是回调函数,而不是创建一个新函数。接收一个函数,
  • useImperativeHandle:可以自定义暴露给父组件的实例值
  • useContext:用来获取父级组件传递过来的context值,最近的父级组件Provider设置的value值
  • useReducer:状态管理,用来获取
  • useRef: 可以用来获取元素,缓存状态

自定义hooks

  • useTitle,useTodos,useMouse,useRepos 响应式业务或响应式场景封装到hooks目录下,方便复用,干净的UI

ahooks第三方库 hooks/vueuse 库

useToggle、useRequest(所有的请求 data,loading,error)业务当中经常用

4.map和forEach的区别

forEach()方法会针对每一个元素提供的函数,对数据的操作会改变原数组,该方法没有返回值 map()方法不会改变原数组的值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值

5.js当中什么是防抖和节流呢?手写防抖和节流

防抖

函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。

// 函数防抖的实现
function debounce(fn, wait) {
  let timer = null;

  return function() {
    let context = this,
        args = arguments;

    // 如果此时存在定时器的话,则取消之前的定时器重新记时
    if (timer) {
      clearTimeout(timer);
      timer = null;
    }

    // 设置定时器,使事件间隔指定事件后执行
    timer = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  };
}

节流

函数节流是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。

// 函数节流的实现;
function throttle(fn, delay) {
  let curTime = Date.now();

  return function() {
    let context = this,
        args = arguments,
        nowTime = Date.now();

    // 如果两次时间间隔超过了指定时间,则执行函数。
    if (nowTime - curTime >= delay) {
      curTime = Date.now();
      return fn.apply(context, args);
    }
  };
}

6.网络请求中常用的请求方式

  • GET:向服务器获取数据
  • POST:将实体提交到指定的资源,通常会造成服务器资源的修改
  • PUT: 上传文件,更新数据
  • DELETE:删除服务器上的对象
  • HEAD: 获取报文首部,与GET相比,不返回报文主体部分
  • OPTIONS:询问支持的请求方法,用来跨域请求
  • CONNECT: 要求在与代理服务器通信时建立隧道,使用隧道进行TCP通信

7.get和post的区别

  • 缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。

  • 编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。

  • 参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。

  • 幂等性的角度,GET幂等的,而POST不是。(幂等表示执行相同的操作,结果也是相同的)

  • TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

8.TCP当中的三次握手和四次挥手

三次握手

刚开始双方都处于CLOSED状态,进入了LISTEN状态

  • 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN,此时客户端处于 SYN_SEND 状态。
  • 第二次握手,服务端收到报文后,返回SYN和ACK(对应客户端发来的SYN),自己变成了SYN-REVD状态
  • 第三次握手,客户端发送ACK给服务端,自己变成了ESTABLISHED状态,服务端收到ESTABLISHED状态

四次挥手

刚开始双方都处于ESTABLISHED状态,

  • 第一次挥手:客户端要断开了向服务器发送FIN报文,报文中会指定一个序列号,此时客户端变成了FIN-WAIT-1状态,
  • 第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
  • 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK(最后确认) 的状态。
  • 第四次挥手:客户端收到FIN之后,一样发送一个ACK报文作为应答,且把服务端的序列号值+1作为自己ACK报文的序列号值,此时客服端处于TIME_WAIT状态。需要过一阵子确保服务端收到自己的ACK报文之后才会进入CLOSED状态,服务端收到ACK报文之后,就处于关闭连接了,处于CLOSED状态。

最后一次挥手中

客户端会等待一段时间再关闭的原因,是为了防止发送给服务器的确认报文段丢失或者出错,从而导致服务器 端不能正常关闭。

9.请你讲讲类组件和函数组件的差别

1.语法和结构上的区别

  • 类组件:使用ES6的class语法来定义,需要继承React.Componet,必须包含一个render()方法,返回JSX
  • 函数组件:本质上是一个JS函数,接受props作为参数,并返回JSX

2.状态管理

  • 类组件:通过this.state来存储状态,this.setState来更新状态(会触发组件的重新渲染)
  • 函数组件:通过useState函数组件也可以拥有和管理自己的状态,更接近函数式编程

3.生命周期方法

-类组件:依赖于特定的生命周期方法来执行副作用操作(componentDidMount/DidUpdate/WillUnmount) -函数组件:使用useEffect Hook来处理所有生命周期相关的副作用

4.this关键字和绑定

-类组件:经常需要处理this指向问题,确保this正确指向组件实例。 -函数组件:没有this的概念,避免了绑定this的麻烦,代码更清晰。

5.设计理念和趋势

  • 类组件:基于面向对象编程的思想
  • 函数组件+Hooks: 更符合函数式编程(FP)的理念,强调纯函数和状态的不可变性。

10.jwt

1.jwt是什么详细讲讲?

JWT,全称是 JSON Web Token,它是一种开放标准(RFC 7519),用于在网络应用环境间安全地传输信息(claims)。简单来说,JWT 就是一个经过加密签名的、紧凑的、URL 安全的字符串,通常用来做身份认证信息交换。JWT令牌通常由三部分组成

  • Header:包含签名算法和令牌类型,一般是JWT,会被Base64Url编码,形成JWT的第一部分
  • Payload:包含实际要传递的“声明”,有三类声明:(注册、公共、私有声明),同样会被Base64Url编码形成JWT的第二部分。
  • Signature(签名):JWT安全性的核心。将header和payload的Base64Url的编码用英文.连接起来形成一个字符串,然后通过算法和secret对这个字符串进行加密。

image.png

2.jwt的核心优势是什么?

  • 无状态 (Stateless) :这是 JWT 最大的优点。服务器不需要在内存或数据库中存储会话信息(session)。验证 JWT 所需的所有信息(包括用户身份和过期时间)都包含在令牌本身。这使得 JWT 非常适合构建可扩展的分布式系统和微服务架构,因为任何一台服务器都可以独立验证 JWT。
  • 自包含 (Self-contained) :JWT 的 Payload 部分可以包含用户所需的所有信息(除了敏感信息),减少了查询数据库的次数。
  • 跨域支持好:由于是基于 Token 的,天然支持跨域认证(CORS),不像传统的基于 Session/Cookie 的认证在跨域时可能遇到问题。
  • 广泛支持:作为一种开放标准,JWT 有多种语言的实现库,易于集成。

3.jwt的弊端是什么?

  • 令牌一旦签发,在过期前无法撤销:这是无状态带来的一个主要缺点。如果用户的令牌被盗用,或者用户在过期前修改了密码,服务器无法立即让这个已签发的 JWT 失效。解决方法包括:

    • 设置较短的过期时间(配合刷新令牌机制)。
    • 维护一个“黑名单”(这又引入了状态,违背了无状态原则)。
    • 使用刷新令牌(Refresh Token)来获取新的访问令牌(Access Token)。
  • Payload 不能存敏感信息:因为 Payload 是 Base64Url 编码,可以被轻易解码,所以绝不能存放密码、身份证号等敏感数据。

  • 令牌大小:相比于 Session ID,JWT 通常更长,会增加 HTTP 请求头的大小。如果 Payload 信息很多,这个问题会更明显。

  • 安全性依赖于密钥管理:签名密钥(secret)的安全至关重要。如果密钥泄露,攻击者就可以伪造任意 JWT。对于 RS256 等非对称算法,需要妥善保管私钥。

  • 不支持同域下的自动登录(像 Cookie 那样) :需要客户端主动存储和发送。

4.与传统Session/Cookie相比

特性JWT (Token)Session/Cookie
状态无状态 (服务器不存储会话)有状态 (服务器存储 Session)
存储位置客户端 (localStorage, Cookie)服务器 (内存/数据库) + 客户端 (Cookie 存 Session ID)
可扩展性高 (适合分布式)低 (需要 Session 共享或粘性会话)
跨域好 (通过 Authorization Header)差 (Cookie 有同源策略限制)
令牌撤销困难 (依赖过期时间)容易 (删除服务器端 Session)
网络开销较大 (每次请求携带完整 Token)较小 (只携带 Session ID)