一篇通关:从 MVVM 到渲染优化,Vue 基础核心 5 大模块全解析

以往文章

📚 JS 基础笔记:前端面试复习笔记:JS 基础核心知识点梳理

📚 CSS基础:10 个基础模块笔记(Flex/Sticky/BFC 全拆解 + 陷阱提示)

📚 浏览器原理笔记:前端面试复习笔记:浏览器原理核心知识点梳理

📚 前端项目优化(一):前端面试复习笔记:前端项目优化知识点梳理

📚 前端项目优化(二):前端面试复习笔记:前端项目优化知识点梳理

📚 前端项目优化(三):前端面试复习笔记:前端项目优化知识点梳理

📚 前端项目优化(四):前端面试复习笔记:前端项目优化知识点梳理

引言

都说 Vue.js 上手简单,但你是否真正"吃透"了它的底层逻辑?从经典的 MVC 与 MVVM 模式之辩,到其巧妙运用的多种设计模式,再到实例挂载与渲染的完整流程,每一个环节都值得深挖。本篇笔记将带你系统梳理 Vue 的核心基础,搞懂 Vite 与 Webpack 的优劣,并掌握实用的优化技巧,为你的 Vue 技能树打下最坚实的地基。

开始

本节聚焦 Vue 基础知识,为你构建完整的知识体系:

序号 专栏方向 本节聚焦 核心价值
1 前端基础(JS/CSS/浏览器) 已更 掌握前端三驾马车
2 前端项目优化 已更 学习工程化与性能调优
3 Vue 专题(基础) 本节内容 系统梳理核心概念,打好坚实基础
4 Vue 专题(进阶) 待更新 深入源码与复杂应用场景

本节将围绕以下五大模块 展开,全是高频面试 考点与实战重点

  1. MVC 和 MVVM:剖析两种架构模式的演进与区别。
  2. VUE 使用了哪些设计模式:揭秘 Vue 源码中蕴含的编程智慧。
  3. VUE 实例挂载和渲染流程:一步步理清从创建到渲染的全过程。
  4. Vite 和 Webpack 的区别:搞懂现代构建工具的选择之道。
  5. VUE 优化:学习立竿见影的性能提升技巧。

介绍

1:MVC和MVVM

一、MVC(Model-View-Controller):传统分层架构

1. 核心思想

MVC 是一种将应用程序分为三个核心部分的设计模式,通过分离数据、界面和交互逻辑,实现代码解耦和复用。

2. 各层职责与协作流程

  • Model(模型) :负责管理应用数据和业务逻辑(如数据验证、数据库交互),不依赖于视图和控制器。当数据发生变化时,可通知视图更新(通过观察者模式等)。

  • View(视图) :负责展示数据(用户界面),是模型的可视化表现(如 HTML 页面、移动端界面)。不处理业务逻辑,仅接收用户输入并传递给控制器。

  • Controller(控制器) :负责协调模型和视图,是用户交互的 "中间人"。

    • 流程

      1. 接收 View 传递的用户输入(如点击按钮、表单提交);

      2. 调用 Model 处理数据(如新增、修改数据);

      3. 通知 View 更新(如 Model 数据变化后,让 View 重新渲染)。

3. 典型协作示例(以 "用户修改名称" 为例)

用户点击修改按钮 → View将事件传给Controller → Controller调用Model的updateName方法 → Model更新数据并通知Controller → Controller告诉View"数据变了,重新渲染" → View从Model获取新数据并展示

4. 优缺点

  • 优点:分离了数据、界面和逻辑,适合中小型应用,早期后端和前端(如 jQuery 时代)广泛使用。

  • 缺点

    • Controller 职责较重,可能变得臃肿(既要处理用户输入,又要协调 Model 和 View);

    • View 和 Model 存在间接依赖(Controller 需同时操作两者),耦合度高于 MVVM。

二、MVVM(Model-View-ViewModel):数据驱动的现代架构

1. 核心思想

MVVM 是 MVC 的演进模式,核心是通过 "数据双向绑定" 减少视图与模型的直接交互,让开发者从 "手动操作 DOM" 转向 "关注数据逻辑"。

2. 各层职责与协作流程

  • Model(模型) :与 MVC 中的 Model 一致,负责管理数据和业务逻辑,不依赖于视图。

  • View(视图) :负责展示数据,但不再直接与 Model 交互,而是通过 ViewModel 间接关联。视图中的用户操作(如输入框变化)会自动同步到 ViewModel。

  • ViewModel(视图模型) :是View 和 Model 之间的桥梁,负责双向绑定数据:

    • 数据绑定:将 Model 的数据同步到 View(Model→ViewModel→View);

    • 事件处理:将 View 的用户操作(如点击、输入)同步到 Model(View→ViewModel→Model)。

    • 封装了视图所需的所有数据和方法(如格式化数据、处理表单验证),是 MVVM 的核心。

3. 典型协作示例(以 "输入框实时更新名称" 为例)

用户在输入框输入文字 → View通过双向绑定通知ViewModel → ViewModel更新Model中的name属性 → Model数据变化后,ViewModel自动将新值同步到View → 输入框实时显示新内容(无需手动操作DOM)

4. 优缺点

  • 优点

    • 数据双向绑定,开发者无需手动操作 DOM("数据驱动视图"),减少模板代码;

    • View 与 Model 完全解耦(通过 ViewModel 中转),耦合度低,适合复杂前端应用(如 SPA)。

  • 缺点

    • ViewModel 的逻辑可能变得复杂(尤其是双向绑定的实现);

    • 对简单应用而言,可能增加额外的学习成本。

三、MVC 与 MVVM 的核心区别

对比维度 MVC MVVM
核心目标 分离数据、视图、逻辑(通过 Controller 协调) 数据双向绑定,减少 DOM 操作(数据驱动视图)
View 与 Model 关系 间接依赖(通过 Controller 交互) 完全解耦(通过 ViewModel 中转)
开发者关注点 需手动同步 View 和 Model(如操作 DOM) 只需关注数据逻辑,View 自动同步
典型场景 后端应用、jQuery 时代前端 现代前端框架(Vue、React、Angular)

四、关于 Vue 与 MVVM 的关系

  • Vue 的设计理念接近 MVVM

    • Vue 中,el挂载的 DOM 是 "View",data是 "Model",Vue 实例本身承担了 "ViewModel" 的角色(实现数据双向绑定、事件处理)。
  • 为什么说 "没有完全遵循"

    • 严格的 MVVM 要求 View 和 Model "绝对不能直接通信",但 Vue 提供了$refs允许直接操作 DOM(View),也允许通过this.$data直接修改 Model,打破了严格的隔离性。

    • 不过这是 Vue 为了灵活性的设计取舍,核心思想(数据驱动ViewModel 中介)仍符合 MVVM 的精神。

五、总结

  • MVC 是 "通过 Controller 协调的分层架构",适合分离传统应用的逻辑和界面;

  • MVVM 是 "数据双向绑定的现代架构 ",通过 ViewModel 实现数据与视图的自动同步,是前端框架的主流设计模式;

  • 两者的演进体现了从 "手动操作 DOM" 到 "数据驱动视图 " 的转变,核心都是为了降低耦合提升代码可维护性


2:VUE使用了哪些设计模式

  • 工厂模式

    • 核心思想:通过传入参数,统一创建不同类型的实例,隐藏创建细节。

    • Vue 中的应用

      • 虚拟 DOM(VNode)的创建createVNode 函数根据传入的标签名(如div)、组件对象(如MyComponent)等参数,返回对应的基础标签 VNode 或组件 VNode,无需手动区分创建逻辑。

      • 异步组件创建defineAsyncComponent 接收配置参数(如loader函数),返回一个异步组件实例,内部处理加载、错误等逻辑。

  • 单例模式

    • 核心思想:确保一个类 / 模块在全局只有一个实例,且提供全局访问点。

    • Vue 中的应用

      • Vuex/Pinia 的 Store :通过createStore(Vuex)或defineStore(Pinia)创建的状态管理实例,在应用中全局唯一,避免多实例导致的状态混乱。

      • Vue RoutercreateRouter 创建的路由实例,通过app.use(router) 注入后全局唯一,确保路由状态一致。

      • 插件注册逻辑install 方法中通常会判断实例是否已存在(如if (app._provided[pluginSymbol]) return),避免重复安装。

  • 发布-订阅模式

    • 核心思想:通过事件中心,实现发布者与订阅者的解耦(多对多关系)。

    • Vue 中的应用

      • 组件事件机制$on(Vue2)、emitter.on(Vue3 中结合mitt)用于订阅事件,$emit 用于发布事件,组件间通过事件中心通信(如非父子组件的总线模式)。

      • 生命周期钩子 :组件的mountedupdated等钩子本质是订阅了 Vue 内部的生命周期事件,当对应阶段触发时,执行订阅的回调。

  • 观察者模式

    • 核心思想:观察者监听目标对象的状态变化,当状态改变时,目标主动通知所有观察者(一对多关系,目标与观察者直接关联)。

    • Vue 中的应用

      • 响应式数据原理

        • 目标对象(响应式数据)通过Proxy(Vue3)或Object.defineProperty(Vue2)拦截数据变化。

        • 观察者(Watcher)在依赖收集阶段订阅数据,当数据变化时,目标触发setter,通知所有关联的Watcher更新(如视图重新渲染、计算属性重新计算)。

  • 装饰模式

    • 核心思想:在不修改原对象的前提下,动态给对象添加额外功能(扩展行为)。

    • Vue 中的应用

      • 装饰器语法(如 Vue Class Component) :通过@Component@Prop等装饰器,为类组件添加选项式 API 的功能(如 props 声明、生命周期),而无需修改类本身的结构。

      • 插件对实例的扩展 :例如vue-router通过install方法,给 Vue 实例添加$router$route属性,扩展路由功能。

  • 策略模式

    • 核心思想:定义一系列算法(策略),将其封装为独立对象,可根据场景动态切换使用哪种算法。

    • Vue 中的应用

      • 选项合并策略 :Vue 在初始化组件时,会根据不同选项(如datamethodscomponents)的类型,使用不同的合并策略(如data是函数合并,methods是对象合并),内部通过mergeOptions函数和策略映射表实现。

      • 指令的钩子函数 :同一指令(如v-model)在不同场景(元素、组件)下有不同的处理逻辑(如输入框的input事件、组件的update:modelValue事件),本质是策略的切换。

  • 代理模式

    • 核心思想:通过代理对象控制对原对象的访问,实现增强或限制。

    • Vue 中的应用

      • 响应式数据的Proxy(Vue3)Proxy作为代理对象,拦截对原数据的读取(get)、修改(set)等操作,实现依赖收集和触发更新,而不直接操作原数据。

      • ** <math xmlns="http://www.w3.org/1998/Math/MathML"> a t t r s 透传 ∗ ∗ :父组件传递的属性通过 ' attrs透传**:父组件传递的属性通过` </math>attrs透传∗∗:父组件传递的属性通过'attrs代理,子组件可决定是否将其透传给内部元素(如v-bind="$attrs"`),控制属性的传递逻辑。

  • 模板方法模式

    • 核心思想:定义一个算法骨架(模板),将步骤延迟到子类中实现,确保流程一致但细节可定制。

    • Vue 中的应用

      • 组件生命周期 :Vue 定义了beforeCreatecreatedbeforeMountmounted等固定生命周期流程(模板),开发者在组件中自定义各阶段的钩子函数(具体实现),框架按顺序执行。

      • 自定义组件的渲染 :组件的render函数或模板编译后的渲染函数,遵循 Vue 的虚拟 DOM 渲染流程(模板),开发者只需关注具体的 UI 结构(细节实现)。


3:VUE实例挂载和渲染流程

Vue 实例渲染流程的核心是 "初始化状态→解析模板为 render→生成 VNode→通过 patch 转换为真实 DOM"。通过虚拟 DOM 和响应式系统,实现数据驱动视图的高效更新。理解这一流程不仅能掌握 Vue 的工作原理,也能更好地优化性能(如减少不必要的响应式数据、合理使用v-if/v-show等)。

一、初始化阶段:Vue 实例的创建与配置初始化

核心目标:初始化实例状态(数据、方法、生命周期等),为后续挂载做准备。

1. 实例创建:new Vue(options)

  • 入口 :通过new Vue(options)创建实例时,Vue 构造函数会先校验调用方式(非new调用则报错),随后执行核心初始化方法this._init(options)

    javascript 复制代码
    function Vue(options) {
      if (!(this instanceof Vue)) {
        warn('Vue is a constructor and should be called with the `new` keyword');
      }
      this._init(options); // 核心初始化方法
    }

2. 核心初始化:_init(options)

_init方法是实例初始化的总入口,定义在initMixin(Vue)中,主要完成以下工作:

步骤 核心操作 作用
1. 生命周期初始化 initLifecycle(vm) 初始化生命周期标志(如$parent$children_isMounted等),建立组件层级关系。
2. 事件初始化 initEvents(vm) 初始化事件监听(如父组件传递的@event),将事件回调存储到_events中。
3. 渲染初始化 initRender(vm) 初始化渲染相关方法: - 绑定vm._c(编译生成的 render 用)和vm.$createElement(用户自定义 render 用),用于创建 VNode。 - 初始化$slots$scopedSlots,支持插槽功能。
4. 触发beforeCreate 无具体方法,直接调用钩子。此时实例刚完成生命周期、事件、渲染初始化,但未初始化数据(props/data 等),无法访问dataprops等。
5. 状态初始化 initState(vm) 按顺序初始化: - initProps:解析props,建立响应式。 - initMethods:绑定methods到实例,确保this指向当前实例。 - initData:解析data,将数据响应式化(Vue2 用Object.defineProperty,Vue3 用Proxy),并代理到vm上(如vm.name对应data.name)。 - initComputed:初始化计算属性,依赖收集 + 缓存结果。 - initWatch:初始化watch,创建 Watcher 监听数据变化。
6. 触发created 无具体方法,直接调用钩子。此时数据(dataprops等)已初始化完成,可访问实例属性和方法,但DOM 未挂载($el不存在)。

二、挂载阶段:从模板到 DOM 的转换

  1. 触发挂载:$mount(el)

    created后,实例需通过$mount(el)(或配置el自动调用$mount)完成 DOM 挂载完成 DOM 挂载,核心逻辑:

    • 参数处理el为挂载点(如#app),Vue 会先获取对应的 DOM 元素(避免直接挂载到body/html)。

    • 模板解析 :将模板(template)或el对应的 HTML 转换为render函数(若已配置render函数则直接使用)。

  2. 模板→Render 函数:compileToFunctions

    若未直接提供render函数,Vue 会通过compileToFunctions将模板编译为render函数,分 3 步:

    • Step 1:解析 HTML 为 AST :通过parse函数将模板字符串(如<div>{{ name }}</div>)解析为抽象语法树(AST),描述 DOM 结构、指令(v-if/v-for)、插值({{ }})等。

    • Step 2:优化 AST :通过optimize函数标记静态节点(如纯文本、无动态绑定的节点),后续更新时可跳过这些节点,优化性能。

    • Step 3:生成 Render 函数 :通过generate函数将 AST 转换为render函数字符串(如"with(this){return _c('div',[_v(_s(name))])}"),再通过new Function转为可执行函数。

  3. 渲染组件:mountComponent(vm, el)

    $mount的核心是调用mountComponent,完成从 VNode 到真实 DOM 的渲染,流程:

    步骤 核心操作 作用
    1. 触发beforeMount 调用钩子函数。此时模板已解析为render函数,但真实 DOM 未生成,$el仍为初始挂载点的 DOM(未替换)。
    2. 定义更新函数:updateComponent vm._update(vm._render(), hydrating)。核心逻辑: - vm._render():生成虚拟 DOM(VNode)。 - vm._update(vnode):将 VNode 转换为真实 DOM(首次渲染)或更新 DOM(数据变化时)。
    3. 创建渲染 Watcher new Watcher(vm, updateComponent, noop, { before: () => vm._beforeUpdate() })。 - 首次执行updateComponent,触发初始渲染。 - 当数据变化时,Watcher 会重新执行updateComponent,触发 DOM 更新(触发beforeUpdate钩子)。
    4. 触发mounted 调用钩子函数。此时真实 DOM 已挂载完成,$el指向最终渲染的 DOM 节点,所有子组件也已挂载完成(递归触发mounted),可访问和操作 DOM。

三、核心渲染逻辑:_render_update

  1. vm._render():生成虚拟 DOM(VNode)

    _render方法定义在renderMixin(Vue)中,核心是执行render函数生成 VNode(虚拟 DOM,描述 DOM 结构的 JavaScript 对象)。

    • render函数执行render函数通过vm._cvm.$createElement创建 VNode,例如:

      kotlin 复制代码
      // 模板: <div>{{ name }}</div>
      // 编译后的render函数
      render: function() {
        return this._c('div', [this._v(this._s(this.name))])
      }
      • _v(text):创建文本 VNode。

      • _s(value):将值转为字符串(处理插值)。

    • createElement:VNode 创建核心vm._cvm.$createElement最终调用createElement方法,完成:

      • 子节点规范化 :将传入的children(可能是字符串、数组、VNode 等)统一转换为 VNode 数组。

      • VNode 类型判断

        • tag是字符串(如div或组件名),则创建普通元素 VNode 或组件 VNode。

        • tag是组件构造函数,则直接创建组件 VNode。

  2. vm._update(vnode):VNode→真实 DOM(patch过程)

    _update方法定义在lifecycleMixin(Vue)中,核心是调用patch方法,将 VNode 转换为真实 DOM(首次渲染)或更新 DOM(数据变化时)。

    • patch方法核心逻辑

      • 首次渲染oldVNode为真实 DOM):

        1. 调用createElm(vnode)递归创建真实 DOM 树。
        2. 将新 DOM 树插入到旧节点的父节点中,再移除旧节点。
      • 数据更新patch(oldVNode, newVNode)):

        1. 通过 diff 算法 比较新旧 VNode 的差异。
        2. 针对差异执行最小化 DOM 操作(如更新属性、移动节点、增删节点)。

四、生命周期钩子总结

钩子函数 触发时机 可操作内容
beforeCreate 实例初始化后,数据未就绪 无(无法访问dataprops
created 数据初始化完成,DOM 未挂载 访问数据、发送请求(不操作 DOM)
beforeMount 模板解析完成,DOM 未生成 准备 DOM 操作(但$el未就绪)
mounted DOM 挂载完成,子组件也已挂载 操作 DOM、初始化第三方库
beforeUpdate 数据变化,DOM 更新前 访问更新前的 DOM 状态
updated DOM 更新完成 访问更新后的 DOM 状态
beforeDestroy 实例销毁前 清理定时器、移除事件监听
destroyed 实例销毁完成,事件/数据响应式失效 无(实例已不可用)

五、Vue3 的关键改进

  • 响应式原理 :用Proxy替代Object.defineProperty,支持监听对象新增/删除属性、数组索引变化等。

  • 编译优化 :生成render函数时标记静态节点(PatchFlag),更新时直接跳过,并提升静态节点(hoistStatic)避免重复创建。

  • 渲染流程 :简化 VNode 结构,patch过程对静态和动态节点分类处理,减少比较成本。


4:Vite和Webpack的区别

Vite 更适合用于快速迭代的前端项目,尤其是以现代 JavaScript 框架(如 Vue、React)为主的单页面应用和小型多页面应用。
Webpack 则在大型复杂项目、对兼容性要求极高的项目(需要对各种资源进行深度定制化处理)中表现出色,因为它能够通过各种插件实现对不同类型资源的精细控制和复杂的构建流程。

一、Vite

  • 开发环境

    • 快速冷启动:直接利用浏览器对 ES Modules 的支持,跳过了打包步骤,实现 dev server 秒开。当浏览器需要相关模块时,再向 dev server 发起请求,服务器按需处理并返回模块。

    • 高效热更新:热更新在原生 ESM 上执行,当编辑一个文件时,Vite 只需要精确地使该模块和少数相关模块失活并重新请求,速度极快。

    • 依赖预构建:使用 esbuild(Go 语言编写,速度极快)处理项目依赖,将其预构建为 ES Modules 格式,并进行 Tree Shaking,减少浏览器请求。

  • 生产环境

    • 集成 Rollup:在生产环境中,Vite 集成 Rollup 进行代码打包。Rollup 能高效地进行 Tree Shaking,移除未使用的代码,生成的包体积更小,并支持代码压缩、分割等优化。

二、Webpack

  • 开发环境

    • 打包启动:需要先将整个应用的代码和资源通过 loader 和 plugin 处理,打包成浏览器能够识别的格式,再启动 dev server。项目越大,启动越慢。

    • 热更新机制:当代码发生变化时,会重新构建受影响的模块及其依赖,并将更新发送到浏览器。相比 Vite,在某些场景下热更新效率较低。

    • 依赖处理:使用各种基于 Node.js 的 loader 和 plugin 来处理依赖,功能强大但速度相对 esbuild 较慢。

  • 生产环境

    • 强大的插件生态:Webpack 拥有丰富成熟的插件生态,几乎可以满足各种复杂的生产环境需求,如代码压缩、CSS 提取、代码分割等,但配置相对复杂。

    • 代码分割 :通过splitChunks等功能,可以灵活地将代码分割成多个 chunk,实现按需加载和公共代码提取。

三、其他差异

  • 配置复杂度:Vite 的配置相对简单,开箱即用。Webpack 的配置非常灵活,但也相对复杂,上手难度较高。

  • 适用场景

    • Vite:适合快速迭代的现代前端项目、SPA 和小型多页面应用。

    • Webpack:适合大型复杂项目、需要深度定制构建流程和高度兼容性的项目。


5:VUE优化

一、数据层面优化

  • 控制数据响应式范围

    • 非响应式数据避免放入data,可直接定义在组件实例上(this.xxx = ...)或使用Object.freeze()冻结。

    • 尽量扁平化数据结构,避免深层嵌套。

  • 合理使用computedwatch

    • computed:用于缓存依赖固定数据的高频计算。

    • watch:用于异步操作或数据变化后的副作用。

二、模板与渲染优化

  • v-ifv-show的区分

    • v-if:适合条件不常变化的场景(完全销毁/重建 DOM)。

    • v-show:适合频繁切换的场景(基于display属性切换)。

  • 列表渲染优化

    • 遍历必加key(且用唯一标识如id)。

    • 避免v-forv-if同用,可先用computed过滤数据再渲染。

    • 大数据列表使用虚拟列表(如vue-virtual-scroller)。

三、组件与生命周期优化

  • 组件缓存与复用

    • keep-alive缓存频繁切换的组件。

    • 拆分大型组件为小型功能组件。

  • 避免内存泄漏

    • 组件销毁时(beforeUnmount/destroyed),清理全局事件监听、定时器、第三方实例。

    • 避免在模板中使用匿名函数或动态表达式。

四、资源加载优化

  • 路由与组件懒加载

    • 路由懒加载 :用() => import('@/views/xxx.vue')动态导入路由组件。

    • 组件懒加载 :对非首屏组件用defineAsyncComponent异步加载。

  • 资源按需加载

    • 图片懒加载 :用v-lazy或原生loading="lazy"

    • 第三方库按需引入:如 Element UI、echarts 等。

五、渲染与更新优化

  • 减少不必要的 DOM 操作

    • 避免在模板中使用复杂表达式,移至computed预处理。

    • v-text/v-html代替{{ }},但注意v-html的 XSS 风险。

  • 防抖与节流 :对高频触发事件(如input搜索、窗口resize)使用。

  • 合理使用v-memo(Vue3) :缓存模板片段,当依赖数据未变化时跳过渲染。

六、高级优化方案

  • 服务端渲染(SSR)或预渲染(Prerendering)

    • SSR(如 Nuxt.js) :优化首屏加载和 SEO。

    • 预渲染:适合纯静态内容站点。

  • 构建优化

    • 用 Vite 替代 Webpack

    • 开启 Tree-Shaking、代码分割、压缩资源

最后

本篇系统梳理了 Vue 的几大核心基础模块,从架构模式、设计模式到实例生命周期,再到构建工具对比和性能优化,希望能帮你把零散的知识点串联成一个体系。基础决定上层建筑,理解这些才能在开发中游刃有余。
基础篇暂告一段落,觉得有用的话还请点赞收藏哦!下一节,我们将深入探讨另一个高频重点:Vue2 和 Vue3 的区别,敬请期待!你在学习 Vue 时最大的困惑是什么?欢迎在评论区留言讨论!

更多

💻 Vue3 多端统一开发框架:vue3-multi-platform

📊 HuggingFaceAI论文智能分析系统:ai-paper-analyzer

相关推荐
Jolyne_18 分钟前
树节点key不唯一的勾选、展开状态的处理思路
前端·算法·react.js
饺子不放糖19 分钟前
workspace:你真的会用吗?
前端
饺子不放糖22 分钟前
dependencies vs devDependencies:别再傻傻分不清,你的 package.json 可能早就"胖"了!
前端
岁忧26 分钟前
(LeetCode 面试经典 150 题) 104. 二叉树的最大深度 (深度优先搜索dfs)
java·c++·leetcode·面试·go·深度优先
Kevin@wust28 分钟前
axios的封装
前端·vue
teeeeeeemo30 分钟前
Ajax、Axios、Fetch核心区别
开发语言·前端·javascript·笔记·ajax
柏成36 分钟前
基于 pnpm + monorepo 的 Qiankun微前端解决方案(内置模块联邦)
前端·javascript·面试
唐诗1 小时前
VMware Mac m系列安装 Windws 11,保姆级教程
前端·后端·github
ZXT1 小时前
Chrome Devtool
前端
wycode1 小时前
web缓存问题的解决方案
前端