用过jQuery的朋友都知道他强大的链式操作,方便,简洁,易于理解,如下

  1. $("has_children").click(function(){
  2. $(this).addClass("highlight").children("a").show().end().siblings().removeClass("highlight").children("a").hide();
  3. });

1.jQuery的链式操作是如何实现的?

2.为什么要用链式操作?

链式操作

原理相信百度一下一大把,实际上链式操作仅仅是通过对象上的方法最后

1
return this

把对象再返回回来,对象当然可以继续调用方法啦,所以就可以链式操作了。那么,简单实现一个:

  1. //定义一个JS类
  2. function Demo() {
  3.  
  4. }
  5. //扩展它的prototype
  6. Demo.prototype ={
  7. setName:function (name) {
  8. this.name = name;
  9. return this;
  10. },
  11. getName:function () {
  12. return this.name;
  13. },
  14. setAge:function (age) {
  15. this.age = age;
  16. return this;
  17. }
  18. };
  19.  
  20. ////工厂函数
  21. function D() {
  22. return new Demo();
  23. }
  24. //去实现可链式的调用
  25. D().setName("CJ").setAge(18).setName();

但……为什么要用呢?

一般的解释:节省代码量,代码看起来更优雅。

例如如果没有链式,那么你可能需要这样写代码:

  1. document.getElementById("ele").dosomething();
  2. document.getElementById("ele").dootherthing();

这个代码中调用了两次document.getElementById来获取DOM树的元素,这样消耗比较大,而且要写两行,而链式只要写一行,节省了代码……

但我们也可以用缓存元素啊。比如:

  1. var ele = document.getElementById("ele");
  2. ele.dosomething();
  3. ele.dootherthing();

而且两行并没有比一行多多少代码,甚至相应的封装反而使得代码更多了。

最糟糕的是所有对象的方法返回的都是对象本身,也就是说没有返回值,这不一定在任何环境下都适合。

举个例子,我们想弄一个超大整数BigInteger(意思是如果用Javascript的Number保存可能会溢出的整数),顺便扩展他的运算方法,会适合用链式操作么?

例如运算31415926535 * 4 - 271828182,如果设计成链式风格的方法可能会是这样的:

  1. var result = (new BigInteger("31415926535")).multiply(new BigInteger("4")).subtract(new BigInteger("271828182")).val();
  2. console.log("result == " + result);

这看起来似乎也很优雅,但是如果我们想要中间的结果怎么办呢?或许会写成这样:

  1. var bigInteger = new BigInteger("31415926535");
  2. var result1 = bigInteger.multiply(new BigInteger("4")).val();
  3. var result2 = bigInteger.subtract(new BigInteger("271828182")).val();
  4. console.log("result1 == " + result1 + ", result2 == " + result2);

这似乎一点也不优雅了,和不用链式操作没啥不同嘛!

那么如果要求是原来的BigInteger不能改变呢?好吧,链式操作似乎不能满足这个需求了。

jQuery专注于DOM对象操作,而DOM的操作会在页面上体现,不需要在Javascript中通过返回值来表示,但计算操作却不一样,我们很可能需要通过Javascript返回中间过程值另作他用。

在设计的时候,我们需要考虑链式带来的好处和坏处,因为别人用了链式,所以就用链式,可能并不是一个很好的方案。

那么到底为什么要用链式操作呢?

为了更好的异步体验

Javascript是无阻塞语言,所以他不是没阻塞,而是不能阻塞,所以他需要通过事件来驱动,异步来完成一些本需要阻塞进程的操作。

但是异步编程是一种令人疯狂的东西……运行时候是分离的倒不要紧,但是编写代码时候也是分离的就……

常见的异步编程模型有哪些呢?

    • 回调函数  所谓的回调函数,意指先在系统的某个地方对函数进行注册,让系统知道这个函数的存在,然后在以后,当某个事件发生时,再调用这个函数对事件进行响应。

  1. function f(num, callback){
  2. if(num<0) {
  3. alert("调用低层函数处理!");
  4. alert("分数不能为负,输入错误!");
  5. }else if(num==0){
  6. alert("调用低层函数处理!");
  7. alert("该学生可能未参加考试!");
  8. }else{
  9. alert("调用高层函数处理!");
  10. setTimeout(function(){callback();}, 1000);
  11. }
  12. }

这里callback则是回调函数。可以发现只有当num为非负数时候callback才会调用。

但是问题,如果我们不看函数内部,我们并不知道callback会几时调用,在什么情况下调用,代码间产生了一定耦合,流程上也会产生一定的混乱。

虽然回调函数是一种简单而易于部署的实现异步的方法,但从编程体验来说它却不够好。

    • 事件监听   也就是采用事件驱动,执行顺序取决于事件顺序。

  1. function EventTarget(){
  2. this.handlers = {};
  3. }
  4.  
  5. EventTarget.prototype = {
  6. constructor: EventTarget,
  7. addHandler: function(type, handler){
  8. this.handlers[type] = [];
  9. },
  10. fire: function(){
  11. if(!event.target){
  12. event.target = this;
  13. }
  14. if(this.handlers[event.type instanceof Array]){
  15. var handlers = this.handlers[event.type];
  16. for(var i = 0, len = handlers.length, i < len; i++){
  17. handlers[i](event);
  18. }
  19. }
  20. },
  21. removeHandler: function(type, handler){
  22. if(this.handlers[type] instanceof Array){
  23. var handlers = this.handlers[type];
  24. for(var i = 0, le = handlers.length; i < len; i++){
  25. if(handlers[i] === handler){
  26. break;
  27. }
  28. }
  29.  
  30. handlers.splice(i, 1);
  31. }
  32. }
  33. };

上面是《JavaScript高级程序设计》中的自定义事件实现。于是我们就可以通过addHandler来绑定事件处理函数,用fire来触发事件,用removeHandler来删除事件处理函数。

虽然通过事件解耦了,但流程顺序更加混乱了。

    • 链式异步

个人觉得链式操作最值得称赞的还是其解决了异步编程模型的执行流程不清晰的问题。jQuery中$(document).ready就非常好的阐释了这一理念。DOMCotentLoaded是一个事件,在DOM并未加载前,jQuery的大部分操作都不会奏效,但jQuery的设计者并没有把他当成事件一样来处理,而是转成一种“选其对象,对其操作”的思路。$选择了document对象,ready是其方法进行操作。这样子流程问题就非常清晰了,在链条越后位置的方法就越后执行。

  1. (function(){
  2. var isReady=false; //判断onDOMReady方法是否已经被执行过
  3. var readyList= [];//把需要执行的方法先暂存在这个数组里
  4. var timer;//定时器句柄
  5. ready=function(fn) {
  6. if (isReady )
  7. fn.call( document);
  8. else
  9. readyList.push( function() { return fn.call(this);});
  10. return this;
  11. }
  12. var onDOMReady=function(){
  13. for(var i=0;i<readyList.length;i++){
  14. readyList[i].apply(document);
  15. }
  16. readyList = null;
  17. }
  18. var bindReady = function(evt){
  19. if(isReady) return;
  20. isReady=true;
  21. onDOMReady.call(window);
  22. if(document.removeEventListener){
  23. document.removeEventListener("DOMContentLoaded", bindReady, false);
  24. }else if(document.attachEvent){
  25. document.detachEvent("onreadystatechange", bindReady);
  26. if(window == window.top){
  27. clearInterval(timer);
  28. timer = null;
  29. }
  30. }
  31. };
  32. if(document.addEventListener){
  33. document.addEventListener("DOMContentLoaded", bindReady, false);
  34. }else if(document.attachEvent){
  35. document.attachEvent("onreadystatechange", function(){
  36. if((/loaded|complete/).test(document.readyState))
  37. bindReady();
  38. });
  39. if(window == window.top){
  40. timer = setInterval(function(){
  41. try{
  42. isReady||document.documentElement.doScroll('left');//在IE下用能否执行doScroll判断dom是否加载完毕
  43. }catch(e){
  44. return;
  45. }
  46. bindReady();
  47. },5);
  48. }
  49. }
  50. })();

上面的代码不能用$(document).ready,而应该是window.ready。

    • Deferred & Promise

CommonJS中的异步编程模型也延续了这一想法,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。

所以我们可以这样写:

  1. f1().then(f2).then(f3);

jQuery链式操作[转]的更多相关文章

  1. jQuery链式操作

    讨论jQuery的文章很多.然而,关于jQuery的链式操作的文章并无多少.好的代码会带来速度的提升.快速渲染和响应意味着更好的用户体验. 下面就来讲讲jQuery的链式操作. 很多时候我们写代码的时 ...

  2. JQUERY链式操作实例分析

    本文实例讲述了jQuery链式操作.分享给大家供大家参考,具体如下: 从过去的实例中,我们知道jQuery语句可以链接在一起,这不仅可以缩短代码长度,而且很多时候可以实现特殊的效果. <scri ...

  3. jQuery链式操作如何返回上一级DOM

    有时候我们在链式操作的时候,选择到了其他的DOM进行操作,如何再返回先前的dom呢,有一下几个方法,end(); addBack(); add(); 使用形式 $("#divFather&q ...

  4. 强大的JQuery链式操作风格

    实例代码 <style type="text/css"> #menu {width: 300px;} .has_children {background:#555;co ...

  5. 如何一行jquery代码写出tab标签页(链式操作)

    啦啦!今天又学了一招,js写几十行的tab标签页jquery写一行就行啦,用到了链式操作!以下是代码: <!DOCTYPE html> <html lang="en&quo ...

  6. jquery中链式操作的this指向

    jquery中链式操作是如何实现? 例如:$(obj).children().css('color','red').next().css('color','red').siblings().css(' ...

  7. jQuery对象的链式操作用法分析

    可以使用下面的原则判断一个函数返回的时候是jQuery对象,即是否可以用于链式操作. 除了获取某些数据的函数,比如获取属性值"attr(name)",获取集合大小"siz ...

  8. PHP链式操作输出excel(csv)

    工作中经常会遇到产品运营让导出一些简单的比较规范的数据,这时候要是有一个简单的方法可以用就简单多了.下面是我的一个输出简单的excel(csv)的方法类,用到了链式操作.说到链式操作,在jquery中 ...

  9. js实现链式操作

    前言:前不久阿里远程面试时问了我一个问题,如下: function Person(){}; var person = new Person(); //实现person.set(10).get()返回2 ...

随机推荐

  1. [转]HDFS中JAVA API的使用

    HDFS是一个分布式文件系统,既然是文件系统,就可以对其文件进行操作,比如说新建文件.删除文件.读取文件内容等操作.下面记录一下使用JAVA API对HDFS中的文件进行操作的过程. 对分HDFS中的 ...

  2. 下一代Asp.net开发规范OWIN(3)—— Middleware

    Middleware是OWIN管道的基本组成单元,最后拼接的OWIN管道来处理客户端请求,输出网页.这篇文章,首先看看Web Form, MVC, Web API如何结合OWIN使用. 然后将如何编写 ...

  3. 聊下git merge --squash

    你经常会面临着将dev分支或者很多零散的分支merge到一个公共release分支里. 但是有一种情况是需要你处理的,就是在你的dev的分支里有很多commit记录.而这些commit是无需在rele ...

  4. Snapshot Instance 操作详解 - 每天5分钟玩转 OpenStack(36)

    本节我们通过日志详细讨论 instance 的 snapshot 操作. 有时候操作系统损坏得很严重,通过 Rescue 操作无法修复,那么我们就得考虑通过备份恢复了.当然前提是我们之前对instan ...

  5. shell脚本中生成延时

    #!/bin/bash echo -n count: tput sc count=; while true; do ]; then let count++; ; tput rc tput ed ech ...

  6. Mysql 主从热备份

    工作原理 首先锁定并备份主服务器数据库,从服务器导入备份的数据库,实现两个数据库的初态一样.然后把主服务器上执行过的sql语句都记录到二进制日志 Binarylog 中,从服务器会来读取这个log, ...

  7. ARM嵌入式开发板

    iTOP-4412 ARM嵌入式开发板----主要特点 iTOP-4412开发平台是北京迅为电子研发设计的嵌入式开发板平台,核心板配备64位双通道2GB DDR3,16GBEMMC存储,三星原厂S5M ...

  8. JavaScript函数的概念

    函数是这样的一段代码,它只定义一次,但可能被执行或调用任意多次. JavaScript函数是参数化的:函数的定义会包含形参,这些参数在函数的整体中像局部变量一样工作.函数调用时会为形参提供实参的值.除 ...

  9. 【小白的CFD之旅】15 四种境界

    天气不错,小白一大早就起床了,吃过早餐就往奔实验室而去.路上碰到了同去实验室的小牛师兄. "小白,这么早啊",小牛师兄老远就发现了小白,打招呼道. "早啊,牛师兄,刚吃完 ...

  10. Tomcat服务无法开启,点击start不一会就变成stopped

    前天在学习J2EE方面技术时,运行一个调试示例,需要用到Tomcat服务,结果使用Myeclipse怎么也打不开服务.之后去尝试手动打开Tomcat服务也无法成功,一直弄了好几个小时.后来,问了一下隔 ...