在我们平常的web开发中,已经存在各种大型的专业Javascript类库(JQuery,Prototype,ExtJS)等,它们都充分利用了Javascript面向对象的思想,使得类库更加富有灵活性和健壮性,但其中最关键的是利用了Javascript的链式调用,这也就是我们今天要谈到的话题了。那什么是链式调用呢?简单的说,就是把一系列对DOM元素的操作以某种形式关联起来,使得使用很少的代码就能完成很强大的功能(Write Less, Do More)。下面我将一个示例来比较一下非链式调用和链式调用的区别所在。

//非链式调用addEvent($('test'), 'click', function() {    setStyle(this, 'color', 'green');    show(this);});//链式调用$("test").addEvent('click', function() {    $(this).setStyle('color', 'green').show();});

大家可能看出其中的一点不同了($,addEvent等类库函数我会逐步讲到),但可能感觉不到链式调用的简洁,至少对函数调用有了的新的认识。那我们将逐步来体现链式调用的价值,就以$()函数的实现为例。大家都知道,在JS中要获取一个ID为test的元素通过这样获取: document.getElementById('test'),也许写一次感觉没什么,但写多了造成到处布满document.getElementById,你既难得写也厌烦,那我们何不把它简化一下呢,假设$('test')就代表整个意思该多好。

function $() {var elements = [];for(var i = 0, len = arguments.length; i < len; i++) {var element = arguments[i];if(typeof element === 'string') {            element = document.getElementById(element);        }if(arguments.length === 1) {return element;        }         elements.push(element);    }return elements;}

再往深处想想,如果我们现在有大堆方法都是在test这个元素上操作,试想$('test').(...???)应该是怎么组织呢?首先我们必须将$()方法作为链式调用的开头并且要返回当前元素的引用,以便我们后来的调用,采用我们前面学的闭包知识,我们对$()进行改造。

(function() {//使用私有的方法    function _$(els) {this.elements = [];for(var i = 0, len = els.length; i < len; i++) {var element = els[i];if(typeof element === 'string') {                element = document.getElementById(element);            }this.elements.push(element);        }    }//提供与$()函数同样的公共接口    window.$ = function() {return new _$(arguments);    }})();

我们都知道JS所有的对象都会继承自它们的原型(prototype),我们就可以利用返回的引用实例以链式的方式的组织起来,代码如下:

(function() {//使用私有的方法    function _$(els) {this.elements = [];for(var i = 0, len = els.length; i < len; i++) {var element = els[i];if(typeof element === 'string') {                element = document.getElementById(element);            }this.elements.push(element);        }    }    _$.prototype = {        each: function(fn) {for(var i = 0, len = this.elements.length; i < len; i++) {                fn.call(this, this.elements[i]);             }return this;        },        setStyle: function(prop, val) {this.each(function(el) {                el.style[prop] = val;            });return this;        },        show: function() {var that = this;this.each(function(el) {                that.setStyle('display', 'block');            });return this;        },        addEvent: function(type, fn) {var add = function(el) {if(window.addEventListener) {                    el.addEventListener(type, fn, false);                }else if(window.attachEvent) {                    el.attachEvent('on' + type, fn);                }            };this.each(function(el) {                add(el);            });return this;        }    };//提供与$()函数同样的公共接口    window.$ = function() {return new _$(arguments);    }})();

从以上的代码我们可以看出,在原型方法中结尾处都是return this;这保证了在调用该方法的同时可以将当前对象引用以链式的方式传递到下一方法,从而实现链式调用,如:

$(window).addEvent('load', function() {    $('test1', 'test2').show()        .setStyle('color', 'red')        .addEvent('click', function() {        $(this).setStyle('color', 'blue');    });});

现在可以看出链式调用的简洁性了把。对于学习过JQuery的朋友来说,对这个代码非常熟悉同时也了解了JQuery代码背后的原理。到这里,我们已基本了解链式调用的原理以及实现,接下来我们试探性的设计一个JS类库的框架(可能适用于搭建企业内部结构的JS类库),了解了这种框架对你以后更好的应用JS有很大的帮助。在这里我们总结一下:大多数JS框架类库总是从以下3方面入手:

1). Events。即统一各大浏览器事件机制,使之彼此兼容。

2). DOM。即HTML中的大量元素的属性与行为管理。

3). AJAX。即统一并扩展XMLHttpRequest的异步调用机制。

利用我们今天学到的知识,利用链式调用建立一个JS简易版的类库。首先我们利用一下前面学过(面向对象的Javascript之一——初识Javascript)章节的内容。

Function.prototype.method = function(name, fn) {this.prototype[name] = fn;return this;};

再次改造一下上面的代码使之看起来像JS类库:

(function() {function _$(els) {//...    }//Events: addEvent, getEvent    _$.method('addEvent', function(type, fn) {//...    }).method('getEvent', function(e) {//...    }).//DOM: addClass, removeClass, replaceClass, hasClass, getStyle, setStyle       method('addClass', function(className){//...    }).method('removeClass', function(className) {//...    }).method('replaceClass', function(oldClass, newClass) {//...    }).method('hasClass', function(className) {//...    }).method('getStyle', function(prop) {//...    }).method('setStyle', function(prop, val) {//...    }).//AJAX: load       method('load', function(uri, method) {//...    });    window.$ = function() {return new _$(arguments);    }})();

现在就把这个JS类库发布出去,可能在短期内没有什么问题发生,但突然有一天$这个函数被另一个类库给占用了,那我们所有的代码将不会再有效。为了防止与外库的冲突,我们开始想办法解决。

window.$ = function() {return new _$(arguments);}//改造成以下代码window.installHelper = function(scope, interface) {    scope[interface] = function() {return new _$(arguments);    }}

这样我们就可以避免冲突了,按照以下方式就可以完成调用。

intallHelper(window, '$');

下面利用这种方式去解决一个已定义好的的命名空间中。

window.com = window.com || {};com.tms = com.tms || {};com.tms.util = com.tms.util || {};

installHelper(com.tms.util, 'get');(function() {var get = com.tms.util.get;    get('test').addEvent('click', function(e) {        get(this).addClass('hello');    });})();

并不是所有的链式调用都能解决所有问题,比如取值器和赋值器。对于赋值器很适合链式调用,取值器可能就不太好办了,下面我以一个例子来说明问题。

window.API = window.API || function() {var name = 'Miracle';this.setName = function(newName) {        name = newName;return this;    };this.getName = function() {return name;    };};//调用APIvar api = new API;console.log(api.getName());//Miracleconsole.log(api.setName('Miracle He').getName());//Miracle He

可以采用回调方法来返回数据,使赋值器和取值器都支持链式调用。

window.API = window.API || function() {var name = 'Miracle';this.setName = function(newName) {        name = newName;return this;    };this.getName = function(callback) {        callback(this, name);return this;    };};//调用APIvar api = new API;api.getName(console.log).setName('Miracle He').getName(console.log);//diaplay 'Miracle' and then 'Miracle He'

再次总结一下:链式调用就是让支持它的每个方法都返回对象的引用,使用链式调用可以避免多次重复使用一个对象变量以减少代码量。

转载于:https://www.cnblogs.com/hmiinyu/archive/2012/02/28/2372553.html

Javascript基础知识篇(5): 面向对象之链式调用相关推荐

  1. JavaScript基础知识系列:面向对象的编程

    JavaScript Basics is a series that explore some core concepts that every frontend software engineer ...

  2. JavaScript 基础知识 - DOM篇(二)

    7. 节点操作 7.1 节点的属性 节点分类: 标签节点 文本节点 属性节点 注释节点 节点常用的属性: nodeType:节点的类型 nodeName:节点名称 nodeValue:节点值 常见的节 ...

  3. JavaScript 基础知识 - 入门篇(二)

    11. 函数 11.1 函数的基础知识 为什么会有函数? 在写代码的时候,有一些常用的代码需要书写很多次,如果直接复制粘贴的话,会造成大量的代码冗余: 函数可以封装一段重复的javascript代码, ...

  4. JavaScript 基础知识 - BOM篇

    前言 本篇文章是JavaScript基础知识的BOM篇,如果前面的<JavaScript基础知识-DOM篇>看完了,现在就可以学习BOM了. 注意: 所有的案例都在这里链接: 提取密码密码 ...

  5. HTML5学习笔记 —— JavaScript基础知识

    HTML5学习笔记 -- JavaScript基础知识 标签: html5javascriptweb前端 2017-05-11 21:51 883人阅读 评论(0) 收藏 举报 分类: JavaScr ...

  6. 网页游戏开发基础——JavaScript基础知识

    对于初学编程的朋友来说,这篇文章有点长,而且会有点难懂.但是请不要放弃,我尽量以通俗的语言解释相关的编程概念,这里只讲解编写一个游戏需要的相关编程概念(如需要会在后面的文章中随时补充相关概念),对其余 ...

  7. 超详细的Java面试题总结(二)之Java基础知识篇

    系列文章: 超详细的Java面试题总结(一)之Java基本知识 超详细的Java面试题总结(二)之Java基础知识篇 超详细的Java面试题总结(三)之Java集合篇常见问题 超详细的Java面试题总 ...

  8. JavaScript基础知识与脚本语言总结

    1 Aptana插件安装 1.Aptana插件安装 <1>Aptana是一个非常强大,开源,JavaScript-focused的AJAX开发IDE. <2>它的特点包括: J ...

  9. 基金投资从入门到精通之一:基础知识篇

    第一篇 基础知识篇 第一节      认识基金 基金投资入门系列--基础知识 1.什么是证券投资基金? 通俗地说,证券投资基金是通过汇集众多投资者的资金,交给银行保管,由专业的基金管理公司负责投资于股 ...

最新文章

  1. Lesson 5.基本优化思想与最小二乘法
  2. ie的严苛,firefox的宽容
  3. window7连接其他计算机的打印机,win7系统电脑怎样连接其它电脑上在打印机?
  4. 【论文阅读】Deep Adversarial Subspace Clustering
  5. 五个问答,告诉你阿里云对象存储如何助力钉钉战胜业务洪峰
  6. 《Spring Recipes》第二章笔记:Creating Beans by Invokin...
  7. android studio运行模拟器报错请求超时_GDA关于android脱壳的问题说明
  8. matlab作业5答案,《matlab作业题答案》.doc
  9. COMPUTEX展 CPX论坛聚焦AI与物联网
  10. vue企业门户网站模板_门户网站建设费用需要多少钱?
  11. 网上收集总结一下mssql( 部分)
  12. 从C# 3.0说以人为本(二)—— LINQ语法结构
  13. mysql 5.6.15.0 源码_源码编译mysql-5.6.15
  14. 毕业设计 : 基于Spark的海量新闻文本聚类 - Spark 新闻分类 文本分类新闻聚类
  15. dell进入u盘启动模式_戴尔笔记本u盘启动按F12没有usb启动项 dellPC用f12没有u盘启动如何办...
  16. 史上最全maven教程
  17. 【753. 破解保险箱】
  18. Python 自动化办公
  19. ios高德地图提醒打开定位功能
  20. 毕业一年有感——人活着的意义是什么?

热门文章

  1. zabbix-agent 启动不起来
  2. 《ASP.NET MVC 4 实战》----导读
  3. Oracle CDC配置案例
  4. IT男人必学的20大泡妞妙招
  5. hive数据导入导出
  6. php 限制刷新,PHP禁止频繁刷新方法
  7. 计算机学硕哪些学校好考,什么学校研究生好考,计算机专业研究生哪个学校好考一点...
  8. JavaScript初学者编程题(17)
  9. mysql 复合索引 in,MySQL复合索引比主键索引还快,为什么?
  10. HDU6964 I love counting (字典树+莫队)