浅谈使用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 相关文章推荐
checkbox全选/取消全选以及checkbox遍历jQuery实现代码
Dec 02 Javascript
asp.net网站开发中用jquery实现滚动浏览器滚动条加载数据(类似于腾讯微博)
Mar 14 Javascript
JS+DIV+CSS实现仿表单下拉列表效果
Aug 18 Javascript
详解在Angular项目中添加插件ng-bootstrap
Jul 04 Javascript
React Native时间转换格式工具类分享
Oct 24 Javascript
浅谈React碰到v-if
Nov 04 Javascript
详解Vue底部导航栏组件
May 02 Javascript
适合前端Vue开发童鞋的跨平台Weex的使用详解
Oct 16 Javascript
JavaScript代理模式原理与用法实例详解
Mar 10 Javascript
微信小程序返回上一级页面的实现代码
Jun 19 Javascript
解决vue项目中遇到 Cannot find module ‘chalk‘ 报错的问题
Nov 05 Javascript
详解JavaScript执行模型
Nov 16 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
为IP查询添加GOOGLE地图功能的代码
2010/08/08 PHP
不使用php api函数实现数组的交换排序示例
2014/04/13 PHP
PHP编写daemon process 实例详解
2016/11/13 PHP
LaravelS通过Swoole加速Laravel/Lumen详解
2018/03/02 PHP
使用户点击后退按钮使效三行代码
2007/07/07 Javascript
javascript代码运行不出来执行错误的可能情况整理
2013/10/18 Javascript
jQuery实现HTML5 placeholder效果实例
2014/12/09 Javascript
简介JavaScript中Boolean.toSource()方法的使用
2015/06/05 Javascript
基于javascript实现表格的简单操作
2016/05/21 Javascript
输入框点击时边框变色效果的实现方法
2016/12/26 Javascript
微信小程序 下拉菜单简单实例
2017/04/13 Javascript
react-router JS 控制路由跳转实例
2017/06/15 Javascript
基于bootstrap实现多个下拉框同时搜索功能
2017/07/19 Javascript
vue mixins组件复用的几种方式(小结)
2017/09/06 Javascript
three.js实现3D模型展示的示例代码
2017/12/31 Javascript
Spring Boot/VUE中路由传递参数的实现代码
2018/03/02 Javascript
如何构建一个Vue插件并生成npm包
2020/10/26 Javascript
python实现简单的socket server实例
2015/04/29 Python
caffe binaryproto 与 npy相互转换的实例讲解
2018/07/09 Python
Python3实现配置文件差异对比脚本
2019/11/18 Python
python Plotly绘图工具的简单使用
2020/03/03 Python
Python Tkinter图形工具使用方法及实例解析
2020/06/15 Python
css3制作动态进度条以及附加jQuery百分比数字显示
2012/12/13 HTML / CSS
HTML5触摸事件(touchstart、touchmove和touchend)的实现
2020/05/08 HTML / CSS
法国综合购物网站:RueDuCommerce
2016/09/12 全球购物
全球性的在线鞋类品牌:Public Desire
2019/04/03 全球购物
美国台面电器和厨具品牌:KitchenAid
2019/04/12 全球购物
斯洛伐克家具和时尚装饰品购物网站:Butlers.sk
2019/09/08 全球购物
如何获取某个日期是当月的最后一天
2013/12/05 面试题
医学生自我鉴定范文
2013/11/08 职场文书
物流管理专业毕业生求职信
2014/03/23 职场文书
竞选文艺委员演讲稿
2014/04/28 职场文书
2016年中秋节晚会领导致辞
2015/11/26 职场文书
Nginx实现高可用集群构建(Keepalived+Haproxy+Nginx)
2021/05/27 Servers
十大必看国产动漫排名,魁拔上线,第二曾在日本播出
2022/03/18 国漫
MySQL分区表管理命令汇总
2022/03/21 MySQL