jquery和zepto的擴展方法extend
總結下jQuery(3.1.1)和zepto(1.1.6)到底是如何來開放接口,使之可以進行擴展,兩者都會有類型判斷,本文使用簡單的類型判斷,暫不考慮兼容。
類型判斷
var class2type = {},toString = class2type.toString,$={}; //判斷類型 function type(obj) { return obj == null ? String(obj) : class2type[toString.call(obj)] || "object" } //對象 function isObject(obj) { return type(obj) == "object" } //字面量對象 function isPlainObject(obj) { return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype } function isArray(arr){ return Array.isArray(arr) || arr instanceof Array }
zepto.extend
zepto中的擴展,我們可以看到,首先是定義了一個extend函數,這個在內部使用的函數有三個參數target,source,deep。target是將被擴展的對象,source是擴展的對象,deep代表是否深度擴展。那么就直接看第三個參數了。
我們可以看到,在extend函數中,即使使用了深度擴展,也會通過遞歸函數來重新擴展,最后都會是targte[key]=source[key]
,而區別是:
//test1 var test1 = { name:"a", item:{ name:"b", nickname:"c" } }; //簡單擴展 extend(test1,{name:"a",item:{name:"b",item:{name:"c"}}}); console.log(test1);
可以看到,在沒有使用deep時,會直接擴展對象的第一層屬性,並直接覆蓋。但如果使用了deep:
//深度擴展 extend(test1,{name:"a",item:{name:"b",item:{name:"c"}}},true); console.log(test1);
現在擴展對象時就不會修改原對象中不對應的值。
然后是$.extend,這個是可以在外部使用的擴展函數,直接在$對象上定義的,zepto的插件擴展可以不需要通過$.extend擴展到zepto對象里,因為zepto的dom.__proto__ = $.fn,zepto.Z.prototype = $.fn
,且返回的是$。所以我們可以看見在zepto其他的模塊里,給zepto添加動態方法時,是這樣直接擴展的:
回到$.extend函數,這里在內部使用arguments,所以該函數是不限參數的,如果想深度擴展,只需要把首個參數設為true。首先是簡單擴展的:
var test2 = $.extend(test1,{name:"a",item:{name:"b",item:{name:"c"}}},{name:"d"}); console.log(test2);
深度擴展:
var test2 = $.extend(true,test1,{name:"a",item:{name:"b",item:{name:"c"}}},{name:"d",item:{name:"e"}}); console.log(test2);
jQuery.extend 和jQuery.fn.extend
看jQuery的擴展,得益jQuery返回的是一個真實的jQuery對象,其內部使用jQuery.fn來划分了作用域,所以擴展上,因為this的不同,如果擴展jQuery對象,extend是直接擴展在jQuery本身上的,而fn.extend是擴展在jQuery.prototype原型對象上。而實現函數其實是一樣的。
在jQuery中使用擴展時,如果除了第一個參數的boolean值之外,參數的長度等於內部定義的長度,都會擴展到jQuery自身,而zepto想要擴展到自身,可以將zepto對象設為第一個參數
jQuery在循環里加入了if ((options = arguments[i]) != null)
所以當給null或undefined賦值時,直接返回擴展對象,而且因為上面的arguments長度判斷,不會擴展到jQuery上去。而zepto則直接報錯target[key] = source[key]
。
zepto:
jQuery:
jQuery中的extend語法與上面的zepto相同,在zepto里,最后對如果沒有proto做了兼容:
在jQuery中$.extend()與$.fn.extend()是不同也相同的,在上面的源碼里我們也看到了,jQuery.extend = jQuery.fn.extend
,只是因為兩個函數的this值指向不同,所以能夠使用的場景也不同,可以大致分為動態和靜態。在使用jQuery的過程中,jQuery的最外層匿名函數里會執行,返回一個jQuery對象,並與$一起綁在window上,所以引入文件之后已經存在,而動態指的是jQuery.fn.init(selector,context);
所以需要先初始化再使用相應方法。
小結
這里將一些瑣碎的知識點歸納了一下,事實上,zepto的擴展與jQuery的擴展在使用的方法上看起來一樣,但jQuery更細。了解兩者的區別能夠在需要兼容zepto和jQuery時不會犯未知錯誤,也對擴展插件有更好的幫助。本文使用demo(有源碼注釋):jQuery與zepto的extend