浅谈使用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 delete 属性的使用
Oct 08 Javascript
JQuery插件iScroll实现下拉刷新,滚动翻页特效
Jun 22 Javascript
javascript实现超炫的向上滑行菜单实例
Aug 03 Javascript
window.onload绑定多个事件的两种解决方案
May 15 Javascript
几种二级联动案例(jQuery\Array\Ajax php)
Aug 13 Javascript
使用bootstrap validator的remote验证代码经验分享(推荐)
Sep 21 Javascript
JS多文件上传的实例代码
Jan 11 Javascript
Vue调试神器vue-devtools安装方法
Dec 12 Javascript
JS中Object对象的原型概念基础
Jan 29 Javascript
了解javascript中let和var及const关键字的区别
May 24 Javascript
详解webpack引用jquery(第三方模块)的三种办法
Aug 21 jQuery
vuex根据不同的用户权限展示不同的路由列表功能
Sep 20 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与ASP
2006/10/09 PHP
改进的IP计数器
2006/10/09 PHP
PHP 无限分类三种方式 非函数的递归调用!
2011/08/26 PHP
php去除HTML标签实例
2013/11/06 PHP
使用php记录用户通过搜索引擎进网站的关键词
2014/02/13 PHP
php无限遍历文件夹示例分享
2014/03/04 PHP
php面向对象中static静态属性与方法的内存位置分析
2015/02/08 PHP
php实现图片缩略图的方法
2016/03/29 PHP
php实现生成验证码实例分享
2016/04/10 PHP
thinkphp框架实现删除和批量删除
2016/06/29 PHP
AJAX PHP无刷新form表单提交的简单实现(推荐)
2016/09/09 PHP
php检查函数必传参数是否存在的实例详解
2017/08/28 PHP
JS Pro-深入面向对象的程序设计之继承的详解
2013/05/07 Javascript
利用jquery写的左右轮播图特效
2014/02/12 Javascript
JS实现仿google、百度搜索框输入信息智能提示的实现方法
2015/04/20 Javascript
jQuery中 delegate使用的问题
2015/07/03 Javascript
jQuery使用deferreds串行多个ajax请求
2016/08/22 Javascript
vuex中的 mapState,mapGetters,mapActions,mapMutations 的使用
2018/04/13 Javascript
用Node提供静态文件服务的方法
2018/07/06 Javascript
从0到1构建vueSSR项目之路由的构建
2019/03/07 Javascript
如何写好一个vue组件,老夫的一年经验全在这了(推荐)
2019/05/18 Javascript
vue 实现v-for循环回来的数据动态绑定id
2019/11/07 Javascript
JavaScript中的全局属性与方法深入解析
2020/06/14 Javascript
Python中使用item()方法遍历字典的例子
2014/08/26 Python
处理Python中的URLError异常的方法
2015/04/30 Python
Python基于TCP实现会聊天的小机器人功能示例
2018/04/09 Python
Pycharm中import torch报错的快速解决方法
2020/03/05 Python
python 实现图像快速替换某种颜色
2020/06/04 Python
Python制作一个仿QQ办公版的图形登录界面
2020/09/22 Python
python语言实现贪吃蛇游戏
2020/11/13 Python
关于前端上传文件全面基础扫盲贴(入门)
2019/08/01 HTML / CSS
HTML5制作表格样式
2016/11/15 HTML / CSS
施华洛世奇天猫官方旗舰店:SWAROVSKI
2017/04/17 全球购物
波兰快递服务:Globkurier.pl
2019/11/08 全球购物
四年级科学教学反思
2014/02/10 职场文书
秸秆管理实施方案
2014/03/15 职场文书