鏈式模式:經過在對象方法中將當前對象返回,實現對同一個對象多個方法的鏈式調用。從而簡化對該對象的多個方法的屢次調用,對該對象的屢次引用。javascript
jquery是基於原型繼承,每一個原型下的方法都返回當前對象this,讓當前對象一直在原型的最高層,這樣就能夠實現鏈式調用。咱們來試着建立一個模仿的鏈式調用的方法.css
var jquery = function(seletor, context) { this.init(seletor, context) } jquery.fn = jquery.prototype = { //簡化寫法,再寫query.prototype就能省點力氣直接寫jquery.fn constructor: jquery, length: 0, init: function(seletor, context) { //定義上下文簡化版(*^__^*) if (context instanceof jquery) { //判斷上下文是不是jquery的實例 context = context[0] } else { context = context || document; //指定選擇範圍 //判斷上下文是否爲字符串 context = typeof context == 'string' ? querySelector(context) || context } this.context = context; //保存上下文 if (~seletor.indexOf('#')) { //判斷補碼是否爲0,是則類,反之id選擇 this.length = 1; this[0] = context.querySelector(seletor); } else { //類選擇 var i = 0, selectArr = context.querySelectorAll(seletor), len = selectArr.length; for (; i < len; i++) { this[i] = selectArr[i] } this.length = len } return this; }, size: function() { return this.length } }
咱們在頁面上建立元素java
<div id="aa"></div> <div class="cc">1</div> <div class="cc">2</div>
var $cc = new jquery('#cc'); console.log($cc) //=>jquery {0: div.cc, 1: div.cc, length: 2} console.log($cc.size()) //=>2
可是咱們發現跟真正的jquery有很大差異, 真正的jquery沒有顯示的new一個構造函數。咱們試着修改上面的函數jquery
var jquery = function(seletor, context) { return new jquery.fn.init(seletor, context) } //而後執行 var $cc = jquery('#cc'); console.log($cc) //=>jquery {0: div.cc, 1: div.cc, length: 2} console.log($cc.size()) //=>$cc.size is not a function
爲何會報錯呢?由於這裏new jquery.prototype.init,由於這裏返回的this指向的是init.prototype,而不是jquery.prototype,init的prototype上並無size這個方法。可是想想,若是new jquery.prototype.init,返回的this指向jquery.prototype,那麼不就能調用jquery.prototype的size方法嗎?真正的jquery源碼中是這樣的解決這個問題.ajax
jquery.fn.init.prototype = jquery.fn
加上這句話再次運行就不會報錯啦。
真正的jquery有許多方法,有直接對jquery對象上掛載方法如:$.ajax,也有對選擇器擴展的一些方法,如$(seletor).attr(),$(seletor).css...等等,也有許多jquery上的插件定義的方法。那麼咱們如何來拓展呢?在真正的jquery中,若是寫過jquery插件或者瞭解過源碼,那麼你會知道,是經過extend這個方法來拓展jquery一些方法。咱們來動手試試吧!設計模式
jquery.extend = jquery.fn.extend = function() { var i = 1, len = arguments.length, target = arguments[0], //拷貝的目標對象 deep, //是否深拷貝標誌 j; /*只有一個參數*/ if (i == len) { //如$.extend({a:1}) 運行後獲得$.a =1 target = this i-- } if (typeof arguments[0] == 'boolean') { //若是深拷貝,如$.extend(true,{},{a:1,b:{c:2}},{d:3}) deep = true i == 2 target = arguments[1] || {} } for (; i < len; i++) { for (j in arguments[i]) { var copy = arguments[i][j], //拷貝對象的值 src = target[i]; //拷貝到目標對象的值 var type = {}.toString.call(copy) //深拷貝 if (deep && (type == '[object Object]' || type == '[object Array]')) { if (!Array.isArray(src)) { src = src || {} } else { src = src || [] } target[j] = $.extend(deep, src, copy) //遞歸循環 } else if (copy != undefined) { target[j] = copy } } } return target }
讓咱們來動手試一試!運行效果jquery插件
/*單個對象*/ var a = { a: 1 } jquery.extend(a) console.log(jquery.a) var b = { b: 2, c: { d: 3 }, } /*多個對象*/ var c = jquery.extend(a, b) console.log(c) c.c.d = 4 console.log(b.c.d) var e = { b: 2, c: { d: 3 }, } /*深拷貝*/ var f = jquery.extend(true, a, e) f.c.d = 4 console.log(e.c.d)
運行成功後咱們來爲咱們的jquery添加上方法,click,和attr函數
jquery.fn.extend({ on: (function(doc) { if (doc.addEventListener) { return function(type, fn) { var i = this.length - 1 for (; i >= 0; i--) { this[i].addEventListener(type, fn, false) } return this } } else if (doc.attachEvent) { return function(type, fn) { var i = this.length - 1; for (; i >= 0; i--) { this[i].attachEvent('on' + type, fn); } return this } } else { return function(type, fn) { var i = this.length - 1; for (; i >= 0; i--) { this[i]['on' + type] = fn } return this } } })(document), attr: function() { var arg = arguments, len = arg.length; if (len < 1) return false if (len == 1) { return this[0].getAttribute(arg[0]) } else if (len == 2) { for (var i in arg[0]) { for (var j = this.length - 1; j >= 0; j--) { this[j].setAttribute(arg[0], arg[1]) } } return this } } }) jquery('.cc').on('click', function() { console.log(this) }) jquery('.cc').attr('class','aa') console.log(jquery('.cc').attr('class'))
以上就是javascript設計模式的鏈式模式的學習喔。以上皆爲demo版jquery代碼~學習