前端八股文经验分享:面试拷打经历 与 知识总结(纯个人总结)(八) - 持续更新ing

1. 浏览器的一帧都会干些什么?

页面时一帧一帧绘制出来的,目前大多浏览器时 60Hz,每一帧耗时 16.6ms

浏览器一帧所经历的过程:

  • 接收输入事件
  • 执行回调事件
  • 开始一帧
  • 执行 RAF
  • 页面布局,样式计算
  • 绘制渲染
  • 执行 RIC

2. Objet.defineProperty 与 Proxy 的区别

在 Vue2.x 的版本中,双向绑定是基于 Object.defineProperty 方式实现的。而 Vue3.x 版本中,使用了 ES6 中的 Proxy 代理的方式实现。


1. 使用 Object.defineProperty 会产生三个主要的问题

  • 不能监听数组的变化
  • 必须遍历对象的每个属性。可以通过 Object.keys() 来实现
  • 必须深层遍历嵌套的对象。通过递归深层遍历嵌套对象,然后通过 Object.keys() 来实现对每个属性的劫持

2. 关于Proxy

  • Proxy 针对的整个对象,Object.defineProperty  针对单个属性,这就解决了需要对对象进行深度递归(支持嵌套的复杂对象劫持)实现对每个属性劫持的问题
  • Proxy 解决了 Object.defineProperty 无法劫持数组的问题
  • Object.defineProperty 有更多的拦截方法,对比一些新的浏览器,可能会对 Proxy 针对性的优化,有助于性能提升

3. 虚拟DOM

虚拟 DOM 是通过 JS 对象模拟出来得 DOM 节点,DOM 操作时性能杀手,操作 DOM 会引起页面得回流或重绘,因此使用虚拟 DOM 可以提高代码的性能下限,并极大的优化大量的操作 DOM 时产生的性能损耗

4. new 和 Object.create 的区别

比较 new Object.create
构造函数 保留原构造函数属性 丢失原构造函数属性

原型链

原构造函数prototype属性 原构造函数 / (对象)本身
作用对象 function function 和 object

5. Websocket 中的心跳机制是为了解决什么问题

  • 为了定时发送消息,使连接不超时自动断线,避免后端设了超时时间自动断线。所以需要定时发送消息给后端,让后端服务器知道连接还在通消息不能断。
  • 为了检测在正常连接的状态下,后端是否正常。如果我们发了一个定时检测给后端,后端按照约定要下发一个检测消息给前端,这样才是正常的。如果后端没有正常下发,就要根据设定的超时进行重连。

6. Promise中,resolve后面的语句是否会执行?

会被执行。如果不需要执行,需要在 resolve 语句前面加上 return

7. CSR 和 SSR 分别是什么?

CSR对于 html 的加载,以 React 为例,我们习惯的做法是加载 js 文件中的 React 代码,去生成页面渲染,同时,js 也完成页面交互事件的绑定,这样的一个过程就是 CSR (客户端渲染)。


SSR:但如果这个 js 文件比较大的话,加载起来就会比较慢,到达页面渲染的时间就会比较长,导致首屏白屏。这时候,SSR (服务端渲染)就出来了:由服务端直接生成 html 内容返回给浏览器渲染首屏内容。


但是服务端渲染的页面交互能力有限,如果要实现复杂交互,还是要通过引入 js 文件来辅助实
现,我们把页面的展示内容和交互写在一起,让代码执行两次,这种方式就叫同构。


CSR 和 SSR 的区别在于,最终的 html 代码是从客户端添加的还是从服务端。

8. 函数式编程的理解,以及有何优缺点

函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而非设计一个复杂的执行过程

优点:

  • 更好的管理状态
  • 更简单的复用
  • 更优雅的组合
  • 隐性好处,减少代码量


缺点:

  • 性能
  • 资源占用
  • 递归陷阱

9. JavaScript 中执行上下文和执行栈是什么?

执行上下文:是一种对 JS 代码执行环境的抽象概念,也就是说,只要有JS代码执行,那么它就一定运行在执行上下文中

(全局执行上下文、函数执行上下文,Eval 函数执行上下文)


执行栈:执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文

10. 对ES6中Module(模块化)的理解

理解: 模块,(Module),是能够单独命名并独立地完成一

### 实现带有自动回溯功能的历史记录 为了实现具备自动回溯特性的历史记录,可以考虑采用栈(Stack)这一基本的数据结构来保存每一次的状态变化。栈是一种后进先出(LIFO, Last In First Out) 的线性数据结构[^1]。 当用户执行某个动作时,当前状态被压入栈中;若需撤销上一步操作,则弹出栈顶元素恢复至前一状态。此过程类似于浏览器中的前进/后退按钮机制。具体来说: - **添加新纪录**:每当发生一次新的有效变更事件时,创建一个新的状态对象并将其推入栈底; - **撤消操作**:通过移除最新的条目来回滚到最后一个已知的良好位置; - **重做功能**:除了简单的撤消外,还可以维护第二个辅助栈用来暂存已经被撤消的动作以便支持重做的需求。 下面给出一段Python代码作为演示,展示了如何利用两个列表模拟上述提到的双栈模型来进行简单版本控制系统的构建: ```python class HistoryManager: def __init__(self): self._history = [] # 存储所有的历史版本 self._redo_stack = [] # 用于存储已经撤销掉的内容 def save_state(self, state): """保存当前状态""" self._history.append(state) self._redo_stack.clear() # 清空重做堆栈 def undo(self): """返回至上一个状态""" if not self.can_undo(): raise Exception("无法再撤销") last_state = self._history.pop() self._redo_stack.append(last_state) return self.current_state() def redo(self): """重新应用刚刚撤销过的最后一个更改""" if not self.can_redo(): raise Exception("无可重复的操作") next_action = self._redo_stack.pop() self._history.append(next_action) return self.current_state() def current_state(self): """获取最新状态""" if len(self._history) == 0: return None return self._history[-1] def can_undo(self): """判断是否存在可撤销项""" return bool(len(self._history)) def can_redo(self): """判断是否有可用作重做的项目""" return bool(len(self._redo_stack)) ``` 以上实现了基础的功能框架,实际应用场景下可能还需要加入更多细节处理逻辑,比如最大长度限制、持久化存储等优化措施以满足特定业务的需求。 #### 时间复杂度分析 对于`save_state()` 方法而言,由于每次都是追加到列表末端,因此平均情况下只需常量级别的时间开销 O(1)[^3] 。而对于 `undo()` 和 `redo()` 操作则涉及到从两端取的过程,在 Python 中同样能够保持较好的性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值