浅谈使用MVC模式进行JavaScript程序开发


Posted in Javascript onNovember 10, 2015

随着前台开发日益受到重视,客户端代码比重日益增加的今天,如何在javascript开发里应用MVC模式,这个问题似乎会一直被提到,所以偶在这里粗略的谈一下自己的看法吧。

MVC模式的基本理念,是通过把一个application封装成model, view和controller三个部分达到降低耦合,简化开发的目的。这么说很空洞,大家可以实际看个例子:

<select id="selAnimal">
  <option value="cat">cat</option>
  <option value="fish">fish</option>
  <option value="bird">bird</option>
</select>
<p id="whatDoesThisAnimalDo"></p>

<script type="text/javascript">
document.getElementById('selAnimal').onchange = function() {
  var thisAnimalDoes;
  switch ( this.value ) {
    case 'cat':
      thisAnimalDoes = "cat meows";
      break;
    case 'fish':
      thisAnimalDoes = "fish swims";
      break;
    case 'bird':
      thisAnimalDoes = "bird flies";
      break;
    default:
      thisAnimalDoes = "wuff?";
  }
  document.getElementById('whatDoesThisAnimalDo').innerHTML = thisAnimalDoes;
}
</script>

这个小程序会把你从下拉菜单"selAnimal"中选择的动物能做什么事回显到网页上。以上是没有应用任何设计模式和编成思想写出的代码。如果要在这里应用MVC模式,代码又会变成怎样的呢?

<select id="selAnimal">
  <option value="cat">cat</option>
  <option value="fish">fish</option>
  <option value="bird">bird</option>
</select>
<p id="whatDoesThisAnimalDo"></p>

<script type="text/javascript">
// whatDoesAnimalDo 就是一个controller
var whatDoesAnimalDo = {
  // 选择视图
  start: function() {
    this.view.start();
  },
  // 将用户的操作映射到模型的更新上
  set: function(animalName) {
    this.model.setAnimal(animalName);
  },
};
// whatDoesAnimalDo的数据model
whatDoesAnimalDo.model = {
  // animal的数据
  animalDictionary: {
    cat: "meows",
    fish: "swims",
    bird: "flies"
  },
  // 当前的animal,也就是这个application的状态
  currentAnimal: null,
  // 数据模型负责业务逻辑和数据存储
  setAnimal: function(animalName) {
    this.currentAnimal = this.animalDictionary[animalName] ? animalName : null;
    this.onchange();
  },
  // 并且通知视图更新显示
  onchange: function() {
    whatDoesAnimalDo.view.update();
  },
  // 还需要响应视图对当前状态的查询
  getAnimalAction: function() {
    return this.currentAnimal ? this.currentAnimal + " " + this.animalDictionary[this.currentAnimal] : "wuff?";
  }
};
// whatDoesAnimalDo的视图
whatDoesAnimalDo.view = {
  // 用户输入触发onchange事件
  start: function() {
    document.getElementById('selAnimal').onchange = this.onchange;
  },
  // 该事件将用户请求发送给控制器
  onchange: function() {
    whatDoesAnimalDo.set(document.getElementById('selAnimal').value);
  },
  // 视图更新显示的方法,其中视图会向model查询当前的状态,并将其显示给用户
  update: function() {
    document.getElementById('whatDoesThisAnimalDo').innerHTML = whatDoesAnimalDo.model.getAnimalAction();
  }
};
whatDoesAnimalDo.start();
</script>

……突然一下代码变得好夸张e....
——偶都还没有在里面实现观察者模式呢...
实在太不良好了。

 

这样就带出了MVC模式最大的诟病:在简单的系统中应用MVC模式,会增加结构的复杂性,并且降低效率。

所以偶觉得除了少数javascript控件,比如click-anywhere-to-edit datagrid/tree control, 或者FckEditor/tinyMCE这样的支持自定义plugin的富文本编辑器非常适合应用MVC之外,在大多数的实用B/S系统中,javascript开发只要遵循工厂模式就足够让你受益匪浅了。这是由于前端开发和后段开发的性质不同引起的。如果在ASP.net或者JSP项目中应用MVC模式,SDK或多或少会自动生成一些view和controller的代码。但是javascript呢——javascript甚至连个好用的SDK都没有,虽然有不少成熟的framework,但最终还是会大大增加开发量。

与开发量相比,更加令人头疼的是效率的问题。三层之间的相互通信都是额外的开销。对于服务器端,这些通信造成的开销几乎可以忽略不计。但对于javascript这样相对低效率的语言,多几重调用和事件侦听就能明显感觉到性能的下降了。而且,因为javascrip的闭包特性,一不小心就搞出内存泄漏,这可是正宗的偷鸡不成蚀把米了...
所以,对于javascript开发,适度开发可能比应用你所学到的学术知识更重要,毕竟前端开发是以解决实际问题为基础,而不是为了炫技。当然,Dflying gg有句话叫“重构无处不在”——如果你觉得你自己的代码越来越乱,维护起来越来越困难,那么,你就该考虑是不是该用MVC重构一下了~

 

再额外的说一句:是不是整个前端开发就不必使用MVC了呢?no no~ 其实整个前端开发就是一个大大的MVC架构啊——

Model: HTML/XHTML中的信息
View: Style sheet
Controller: EMAScripts等等脚本
这不正是web标准的最终目的么....

所以,把握好整个前端代码的结构,永远比在javascript开发中过量应用设计模重要的多!

不过,也有一些优秀的MVC框架,对此西雅图的一位黑客和设计师Gordon L. Hempton做了一下对比,这里我们拉过来看一下:

1. Backbone.js——优点:强大的社区,强劲的势头;缺点:抽象较弱,很多功能亟待增加。
2. SproutCore——优点:对绑定的支持,可靠的社区,大量特性;缺点:过度规范,难以和不需要的特性解耦。
3. Sammy.js——优点:易于学习,更容易和现存的服务端应用程序整合;缺点:过于简单,无法应用于大型应用程序中。
4. Spine.js——优点:轻量级,文档很完备;缺点:它的核心概念“spine”是异步的用户界面,这意味着理想状况用户界面永远不会发生堵塞,而这个基础有缺陷。
5. Cappuccino——优点:大型深思熟虑后的框架,良好的社区,很棒的继承模型;缺点:由iOS开发者创建,使用JavaScript模拟Objective-C。
6. Knockout.js——优点:对绑定的支持,完备的文档和教程;缺点:绑定语法拙劣,缺少统一的视图组件层级关系。
7. Javascript MVC——优点:可靠的社区;缺点:基于字符串的继承模型很差,控制器与视图关系过密而缺少绑定。
8. GWT(Google Web Toolkit)——优点:全面的框架,良好的社区,可靠的基于Java的组件继承模型;缺点:可能无法经受时间的考验,另外,Java在客户端上的抽象有些笨拙。
9. Google Closure——优点:很好的基于组件的UI组合系统。缺点:缺少UI绑定支持。
10. Ember.js——优点:很丰富的模板系统,拥有复合视图和UI绑定;缺点:相对较新,文档不够完备。
11. Angular.js——优点:对模板范围和控制器设计有很好的考虑,拥有依赖注入系统,支持丰富的UI绑定语法。缺点:代码的模块性不强,视图的模块化也不够。
12. Batman.js——优点:代码清晰,绑定、持久化的方法简单;缺点:使用了单例控制器。

Javascript 相关文章推荐
有道JavaScript监听浏览器的问题
Jun 23 Javascript
javaScript复制功能调用实现方案
Dec 13 Javascript
jQuery获取Radio,CheckBox选择的Value值(示例代码)
Dec 12 Javascript
Javascript中引用示例介绍
Feb 21 Javascript
浅谈JavaScript 框架分类
Nov 10 Javascript
JavaScript中length属性的使用方法
Jun 05 Javascript
JavaScript中的Promise使用详解
Jun 24 Javascript
详解用node-images 打造简易图片服务器
May 08 Javascript
jQuery pjax 应用简单示例
Sep 20 jQuery
Vue+Express实现登录注销功能的实例代码
May 05 Javascript
vue路由传参的基本实现方式小结【三种方式】
Feb 05 Javascript
Javascript 模拟mvc实现点餐程序案例详解
Dec 24 Javascript
每天一篇javascript学习小结(基础知识)
Nov 10 #Javascript
jQuery+CSS3实现3D立方体旋转效果
Nov 10 #Javascript
JavaScript中利用各种循环进行遍历的方式总结
Nov 10 #Javascript
简单学习JavaScript中的for语句循环结构
Nov 10 #Javascript
js密码强度校验
Nov 10 #Javascript
详解javascript函数的参数
Nov 10 #Javascript
JavaScript函数的一些注意要点小结及js匿名函数
Nov 10 #Javascript
You might like
php读取富文本的时p标签会出现红线是怎么回事
2014/05/13 PHP
PHP中strnatcmp()函数“自然排序算法”进行字符串比较用法分析(对比strcmp函数)
2016/01/07 PHP
laravel框架上传图片实现实时预览功能
2019/10/14 PHP
tp5.1框架数据库子查询操作实例分析
2020/05/26 PHP
tp5.1 框架数据库-数据集操作实例分析
2020/05/26 PHP
Javascript 圆角div的实现代码
2009/10/15 Javascript
ashx文件获取$.ajax()方法发送的数据
2016/05/26 Javascript
jQuery图片左右滚动代码 有左右按钮实例
2016/06/20 Javascript
js控制一个按钮是否可点击(可使用)disabled的实例
2017/02/14 Javascript
javascript实现下雨效果
2017/03/27 Javascript
使用vue + less 实现简单换肤功能的示例
2018/02/21 Javascript
js中document.write和document.writeln的区别
2018/03/11 Javascript
JS实现获取当前所在周的周六、周日示例分析
2019/05/11 Javascript
微信小程序利用Canvas绘制图片和竖排文字详解
2019/06/25 Javascript
在博客园博文中添加自定义右键菜单的方法详解
2020/02/05 Javascript
JS箭头函数和常规函数之间的区别实例分析【 5 个区别】
2020/05/27 Javascript
小程序实现左滑删除的效果的实例代码
2020/10/19 Javascript
Flask框架学习笔记(一)安装篇(windows安装与centos安装)
2014/06/25 Python
在numpy矩阵中令小于0的元素改为0的实例
2019/01/26 Python
python重试装饰器的简单实现方法
2019/01/31 Python
python代码 FTP备份交换机配置脚本实例解析
2019/08/01 Python
python集成开发环境配置(pycharm)
2020/02/14 Python
详解python 内存优化
2020/08/17 Python
Python如何使用vars返回对象的属性列表
2020/10/17 Python
一款html5 canvas实现的图片玻璃碎片特效
2014/09/11 HTML / CSS
static全局变量与普通的全局变量有什么区别
2014/05/27 面试题
文化大革命观后感
2015/06/17 职场文书
会议室管理制度范本
2015/08/06 职场文书
2015年行政管理人员工作总结
2015/10/15 职场文书
大学班长竞选稿
2015/11/20 职场文书
教师听课学习心得体会
2016/01/15 职场文书
《我是什么》教学反思
2016/02/16 职场文书
小学作文指导之如何写人?
2019/07/08 职场文书
python numpy中setdiff1d的用法说明
2021/04/22 Python
java如何实现获取客户端ip地址的示例代码
2022/04/07 Java/Android
html解决浏览器记住密码输入框的问题
2023/05/07 HTML / CSS