对JavaScript客户端应用编程的一些建议


Posted in Javascript onJune 24, 2015

你可能注意到了,最近的一段时间越来越多的Web应用有变复杂的趋势,重心从服务端慢慢向着客户端转移。 这是个正常的趋势么?我不知道。支持和反对者的讨论就像是在讨论复活者和圣诞节哪一个更好一样; 很难说哪一方观点就是完全正确的。因此,本文不会探讨究竟哪一方是对的,不过我还是试图解释一下使用大家所熟知的面向对象编程也许可以成功的解决客户端编程中存在的一些问题。

不太规范的代码的示例

为了顾及一个应用的响应以及用户体验, 导致我们创建了持续增长的复杂的代码, 这些代码变得难于理解和维护。 你可以轻松的想到在没有任何构架和遵循规则构建出客户端的JavaScript应用代码将会这样:
 

$(function(){
  $('#form').submit(function(e) {
    e.preventDefault();
 
    $.ajax({
      url: '/animals',
      type: 'POST',
      dataType: 'json',
      data: { text: $('#new-animal').find('textarea').val() },
      success: function(data) {
        $('#animals').append('<li>' + data.text + '</li>');
        $('#new-animal').find('textarea').val('');
      }
     });
   });
});

维护这一类的代码将会很难。因为这短短的一段代码与很多地方都有关联: 它控制着很多的事件 (站点, 用户, 网络事件), 它要处理用户的操作事件, 要解析服务器返回的应答并且产生HTML代码。 有人可能说: “是的,你说的对, 但是如果这不是一个客户端单页的页面应用?这最多算是一次过度使用jQuery类库的例子” ——不是很有说服力的观点, 因为众所周知,易于维护和精心设计的代码是非常重要的。特别是许多的工具或者是框架致力于保持代码可用以便于我们能更简单的去测试、维护、重用、和扩展它。

MVC是什么?

谈到这里。我们能受益于那些基于MVC的JavaScript框架,但这些框架大部分不使用MVC,并且相当于Model和Videw的一种结合,或者在二都之间的一些东西,这很难去分清。这就是为什么说大部分的Javascript框架是基于MV*。

改变方法或许可以提供项目中客户端的组织和架构,这使得代码可以在很长的一段时间内容易维护,即使重构已经有的代码也变得相对容易。知道他如何工作和下面一些问题的答案是必需要要记住的。

  •     我的应用里有哪些类型的数据?-Model
  •     用户应该看到什么?-View
  •     谁是和用户交互的程序?-Controller

使用MVC框架重构代码

受用MVC重构代码有什么好处?

  •     解除DOM和Ajax的依赖
  •     代码有更好的结构,并且更容易测试。
  •     从 $(document).ready()中删除多余的代码,只留下使用Model创建Links的部分。

让我们使用一些简单步骤来重构一个典型的代码块
步骤 1: 创建视图并移动Ajax请求

我们开始解除DOM和Ajax的依赖. 使用prototypes建造者,模式创建'Animals' 对象,并且添加一个 'add' 方法.同时创建视图 'NewAnimalView' , 并且添加方法'addAnimal'、 'appendAnimal' 、'clearInput'.

代码如下:
 

var Animals = function() {
};
 
Animals.prototype.add = function (options) {
   $.ajax({
     url: '/animals',
     type: 'POST',
     dataType: 'json',
     data: { text: options.text },
     success: options.success
   });
};
 
 var NewAnimalView = function (options) {
  this.animals = options.animals;
  var add = $.proxy(this.addAnimal, this);
  $('# form').submit(add);
 };
 
 NewAnimalView.prototype.addAnimal = function(e) {
   e.preventDefault();
   var self = this;
 
   this.animals.add({
     text: $('#new-animal textarea').val(),
     success: function(data) {
       self.appendAnimal (data.text);
       self.clearInput();     
     }
   });
 };
 
NewAnimalView.prototype.appendAnimal = function(text) {
  $('#animals ul').append('<li>' + data.text + '</li>');
};
NewAnimalView.prototype.clearInput = function() {
  $('#new-animal textarea').val('');
};
 
 $(document).ready(function() {
   var animals = new Animals();
   new NewAnimalView({ animals: animals });
 });

步骤 2: 使用事件解除依赖.

这个例子,利用MVC框架是关键。我们将会用到事件机制, 事件使我们结合和触发自定义事件. 因此,我们创建新的“AnimalsView”和“NewAnimalView”,并且赋予它们不同的显示animals的职责。 使用事件就来区别职责非常简单。如果在方法和事件之间传递职责,如下所示:
 

var events = _.clone(Backbone.Events);
var Animals = function() {
};
 
Animals.prototype.add = function(text) {
   $.ajax({
     url: '/animals',
     type: 'POST',
     dataType: 'json',
     data: { text: text },
     success: function(data) {
      events.trigger('animal:add', data.text);
     }
   });
};
 
var NewAnimalView = function(options) {
  this.animals = options.animals;
  events.on('animal:add', this.clearAnimal, this);
  var add = $.proxy(this.addAnimal, this);
  $('# form').submit(add);
 };
 
NewAnimalView.prototype.addAnimal = function(e) {
   e.preventDefault();
   this.animals.add($('#new-animal textarea').val());
 };
 
NewAnimalView.prototype.clearInput = function() {
  $('#new-animal textarea').val('');
};
 
var AnimalsView = function() {
  events.on('animal:add', this.appendAnimal, this);
};
 
AnimalsView.prototype.appendAnimal = function(text) {
  $('#animals ul').append('<li>' + data.text + '</li>');
};
 
$(document).ready(function() {
   var animals = new Animals();
   new NewAnimalView({ animals: animals });
   new AnimalsView();
});

步骤 3: 传递数据结构到核心框架

最后,最重要的一步,我们使用: models, views and collections.
 

var Animal = Backbone.Model.extend({
  url: '/animals'
});
 
var Animals = Backbone.Collection.extend({
  model: Animal
});
 
var AnimalsView = Backbone.View.extend({
  initialize: function() {
    this.collection.on('add', this.appendAnimal, this);
  },
 
  appendAnimal: function(animal) {
    this.$('ul').append('<li>' + animal.escape('text') + '</li>');
  }
});
 
 
var NewAnimalView = Backbone.View.extend({
  events: {
    'submit form': 'addAnimal'
  },
 
  initialize: function() {
    this.collection.on('add', this.clearInput, this);
  },
 
  addAnimal: function(e) {
    e.preventDefault();
    this.collection.create({ text: this.$('textarea').val() });
  },
 
  clearInput: function() {
    this.$('textarea').val('');
  }
});
 
$(document).ready(function() {
  var animals = new Animals();
  new NewAnimalView({ el: $('#new-animal'), collection: animals });
  new AnimalsView({ el: $('#animals'), collection: animals });
});

总结

我们已经实现什么呢?我们在高度的抽象上工作。代码的维护、重构和扩展变得更容易。我们极大的优化了代码结果,是不是很迷人?太棒了。但是,我可能要给你泼冷水,即使最好的框架,开发的代码仍旧是脆弱并且难以维护。因此,如果你认为使用了一个较好的MV*框架能解决所有代码上的问题是错误的。记住在重构过程中,经历了第二步,代码会变得好很多,我们不使用框架的主要组件。

记住MV*框架是好的这一点,但是所有关注在‘How'去开发一个应用,这让程序开发人员头决定‘What'。每个框架的一个补充,尤其是当项目的Domain很复杂,将是Domain驱动设计方法,这将更关注与下面的方面:“what”, 把需求转化为真正的产品的一个过程。但是,这是我们要讨论的另外一个主题。

Javascript 相关文章推荐
Javascript打印网页部分内容的脚本
Nov 17 Javascript
javascript 日期常用的方法
Nov 11 Javascript
jquery学习笔记二 实现可编辑的表格
Apr 09 Javascript
IE6不能修改NAME问题的解决方法
Sep 03 Javascript
jquery实现个人中心导航菜单效果和美观都非常不错
Sep 02 Javascript
javascript制作sql转换为stringBuffer的小工具
Apr 03 Javascript
jQuery设置图片等比例缩小的方法
Apr 29 jQuery
JavaScript之class继承_动力节点Java学院整理
Jul 03 Javascript
关于Webpack dev server热加载失败的解决方法
Feb 22 Javascript
优雅的使用javascript递归画一棵结构树示例代码
Sep 22 Javascript
mpvue网易云短信接口实现小程序短信登录的示例代码
Apr 03 Javascript
nuxt 每个页面head标签内容设置方式
Nov 05 Javascript
javascript删除数组重复元素的方法汇总
Jun 24 #Javascript
js实现跨域的方法实例详解
Jun 24 #Javascript
JavaScript中的Promise使用详解
Jun 24 #Javascript
JavaScript面对国际化编程时的一些建议
Jun 24 #Javascript
对JavaScript的全文搜索实现相关度评分的功能的方法
Jun 24 #Javascript
在Mac OS下使用Node.js的简单教程
Jun 24 #Javascript
在Node.js应用中使用Redis的方法简介
Jun 24 #Javascript
You might like
PHP对象转换为数组函数(递归方法)
2012/02/04 PHP
PHP 万年历实现代码
2012/10/18 PHP
php求数组全排列,元素所有组合的方法
2016/05/05 PHP
老生常谈php 正则中的i,m,s,x,e分别表示什么
2017/03/02 PHP
掌握PHP垃圾回收机制详解
2019/03/13 PHP
javascript学习笔记(八) js内置对象
2012/06/19 Javascript
JS原型对象通俗&quot;唱法&quot;
2012/12/27 Javascript
JQuery slideshow的一个小问题(如何发现及解决过程)
2013/02/06 Javascript
关于js遍历表格的实例
2013/07/10 Javascript
jquery 遍历数组 each 方法详解
2016/05/25 Javascript
浅析$(function) ready和onload 的区别
2016/09/03 Javascript
jquery中封装函数传递当前元素的方法示例
2017/05/05 jQuery
vue服务端渲染页面缓存和组件缓存的实例详解
2018/09/18 Javascript
微信小程序自定义组件传值 页面和组件相互传数据操作示例
2019/05/05 Javascript
微信小程序利用云函数获取手机号码
2019/12/17 Javascript
JS原型对象操作实例分析
2020/06/06 Javascript
[01:38]2018DOTA2亚洲邀请赛主赛事第二日现场采访 神秘商人痛陈生计不易
2018/04/05 DOTA
[01:03]PWL开团时刻DAY6——别打我
2020/11/05 DOTA
从零学python系列之从文件读取和保存数据
2014/05/23 Python
python实现比较类的两个instance(对象)是否相等的方法分析
2019/06/26 Python
解决Django no such table: django_session的问题
2020/04/07 Python
css3闪亮进度条效果实现思路及代码
2013/04/17 HTML / CSS
纯CSS3制作页面切换效果的实例代码
2019/05/30 HTML / CSS
canvas实现圆形进度条动画的示例代码
2017/12/26 HTML / CSS
美国专业级皮肤病和spa品质护肤品的高级零售网站:SkinCareRx
2017/02/06 全球购物
澳大利亚有机化妆品网上商店:The Well Store
2020/02/20 全球购物
早会主持词
2014/03/17 职场文书
募捐倡议书怎么写
2014/05/14 职场文书
关于感恩的演讲稿400字
2014/08/26 职场文书
2015届本科毕业生自我鉴定
2014/09/27 职场文书
乱丢垃圾袋检讨书
2014/10/08 职场文书
幼儿园老师新年寄语2015
2014/12/08 职场文书
有关浪费资源的建议书
2015/09/14 职场文书
CSS filter 有什么神奇用途
2021/05/25 HTML / CSS
Win11如何修改dns?Win11修改dns图文教程
2022/01/18 数码科技
vue/cli 配置动态代理无需重启服务的方法
2022/05/20 Vue.js