Appearance
MVC / MVVM 架构模式:从命令式到数据驱动
最后更新:2026-08-19
本主题要回答的问题
- 前端为什么要"架构模式"?直接用 jQuery 操作 DOM 不行吗?
- MVC → MVVM 演进中,核心变量是什么?
- "数据驱动"为什么能取代"命令式 DOM 操作"成为前端主流?
一、问题起源:SPA 规模失控
SPA 出现后,页面里的 JS 逻辑迅速膨胀。没有架构约束的代码长这样:
js
// 命令式:每个操作都手动同步 UI 与数据
$('#btn').click(function () {
var count = parseInt($('#count').text()) + 1;
$('#count').text(count); // 改视图
$.post('/api/count', { count }); // 同步数据
if (count > 10) { $('#warn').show(); } // 又一个手动分支
});数据、视图、事件分散在互相调用的函数里,改一处 UI 要追着所有 $('#xxx') 手动改。当页面状态几十个、事件几百个时,手动同步必然出错——这就是"状态越多,bug 越多"的命令式诅咒。
二、MVC:先给前端搬来后端的三层模型
Backbone.js(2010)把服务端 MVC 思想搬进浏览器:

| 角色 | 职责 | Backbone 中的形态 |
|---|---|---|
| Model | 数据 + 校验 + 同步 | Backbone.Model,change 事件 |
| View | 渲染 DOM + 绑定事件 | Backbone.View |
| Controller/Router | 路由分发 | Backbone.Router |
进步:单向数据流雏形(事件 → 数据 → 视图)。局限:View 层仍要自己写"数据变了怎么更新 DOM"的代码(this.$el.html(_.template(...))),双向绑定不存在,还是要手动同步。
三、MVVM:让"同步"自动发生
AngularJS(2010)提出 MVVM:引入 ViewModel + 双向绑定,声明模板里写 ,数据一变视图自动变,视图一变(输入框)数据自动变。

| 对比项 | MVC(Backbone) | MVVM(AngularJS/Vue) |
|---|---|---|
| 同步方式 | 手动(写 render 逻辑) | 自动(框架监听变化) |
| 编程范式 | 命令式 | 声明式 |
| 心智负担 | 低门槛但易乱 | 初始概念多但状态好管理 |
| 典型代表 | Backbone.js | AngularJS、Vue、Knockout |
四、数据驱动:本质是"状态即真相"
从 MVC 到 MVVM,真正的范式转换是命令式 → 声明式(数据驱动):
| 范式 | 思考方式 | 代码形态 | 出错概率 |
|---|---|---|---|
| 命令式(jQuery) | "我要一步步改哪个 DOM" | 操作分散、互相调用 | 状态多时高 |
| 声明式(React/Vue) | "我要页面处于什么状态" | 只管状态,DOM 交给框架 | 大幅降低 |
jsx
// 声明式(React):只声明"count 应该显示在哪"
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}"数据驱动"的关键承诺:开发者声明"UI = f(状态)",框架负责"状态变了 → 精确更新 DOM"。这引出了下一篇文章的核心问题——框架靠什么机制高效完成这个"自动同步",答案就是虚拟 DOM 与响应式。
五、现代组件化:MVC/MVVM 的最终形态
2013 年后的 React/Vue 把 MVVM 演进为组件化:组件 = 状态 + 模板 + 生命周期,是 MVVM 的最小自治单元。至此前端的架构问题从"全局怎么分层"变为"组件怎么划分与组合"。
一句话总结
MVC/MVVM 的演进本质是把"同步数据与视图"的机械劳动从开发者手里转交给框架:MVC 划清了分层,MVVM 实现了自动绑定,数据驱动把编程范式从"操作 DOM"升级为"声明状态"——前端从此进入了"写状态、不写 DOM"的时代,也把性能优化的难题一并交给了框架内部。