jquery和zepto的擴(kuò)展方法extend
總結(jié)下jQuery(3.1.1)和zepto(1.1.6)到底是如何來(lái)開(kāi)放接口,使之可以進(jìn)行擴(kuò)展,兩者都會(huì)有類(lèi)型判斷,本文使用簡(jiǎn)單的類(lèi)型判斷,暫不考慮兼容。
類(lèi)型判斷
var class2type = {},toString = class2type.toString,$={};//判斷類(lèi)型function type(obj) { return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"}//對(duì)象function isObject(obj) { return type(obj) == "object"}//字面量對(duì)象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中的擴(kuò)展,我們可以看到,首先是定義了一個(gè)extend函數(shù),這個(gè)在內(nèi)部使用的函數(shù)有三個(gè)參數(shù)target,source,deep。target是將被擴(kuò)展的對(duì)象,source是擴(kuò)展的對(duì)象,deep代表是否深度擴(kuò)展。那么就直接看第三個(gè)參數(shù)了。
我們可以看到,在extend函數(shù)中,即使使用了深度擴(kuò)展,也會(huì)通過(guò)遞歸函數(shù)來(lái)重新擴(kuò)展,最后都會(huì)是targte[key]=source[key]
,而區(qū)別是:
//test1var test1 = { name:"a", item:{ name:"b", nickname:"c" } };//簡(jiǎn)單擴(kuò)展extend(test1,{name:"a",item:{name:"b",item:{name:"c"}}}); console.log(test1);
可以看到,在沒(méi)有使用deep時(shí),會(huì)直接擴(kuò)展對(duì)象的第一層屬性,并直接覆蓋。但如果使用了deep:
//深度擴(kuò)展extend(test1,{name:"a",item:{name:"b",item:{name:"c"}}},true); console.log(test1);
現(xiàn)在擴(kuò)展對(duì)象時(shí)就不會(huì)修改原對(duì)象中不對(duì)應(yīng)的值。
然后是$.extend,這個(gè)是可以在外部使用的擴(kuò)展函數(shù),直接在$對(duì)象上定義的,zepto的插件擴(kuò)展可以不需要通過(guò)$.extend擴(kuò)展到zepto對(duì)象里,因?yàn)閦epto的dom.__proto__ = $.fn,zepto.Z.prototype = $.fn
,且返回的是$。所以我們可以看見(jiàn)在zepto其他的模塊里,給zepto添加動(dòng)態(tài)方法時(shí),是這樣直接擴(kuò)展的:
回到$.extend函數(shù),這里在內(nèi)部使用arguments,所以該函數(shù)是不限參數(shù)的,如果想深度擴(kuò)展,只需要把首個(gè)參數(shù)設(shè)為true。首先是簡(jiǎn)單擴(kuò)展的:
var test2 = $.extend(test1,{name:"a",item:{name:"b",item:{name:"c"}}},{name:"d"}); console.log(test2);
深度擴(kuò)展:
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的擴(kuò)展,得益jQuery返回的是一個(gè)真實(shí)的jQuery對(duì)象,其內(nèi)部使用jQuery.fn來(lái)劃分了作用域,所以擴(kuò)展上,因?yàn)閠his的不同,如果擴(kuò)展jQuery對(duì)象,extend是直接擴(kuò)展在jQuery本身上的,而fn.extend是擴(kuò)展在jQuery.prototype原型對(duì)象上。而實(shí)現(xiàn)函數(shù)其實(shí)是一樣的。
在jQuery中使用擴(kuò)展時(shí),如果除了第一個(gè)參數(shù)的boolean值之外,參數(shù)的長(zhǎng)度等于內(nèi)部定義的長(zhǎng)度,都會(huì)擴(kuò)展到j(luò)Query自身,而zepto想要擴(kuò)展到自身,可以將zepto對(duì)象設(shè)為第一個(gè)參數(shù)
jQuery在循環(huán)里加入了if ((options = arguments[i]) != null)
所以當(dāng)給null或undefined賦值時(shí),直接返回?cái)U(kuò)展對(duì)象,而且因?yàn)樯厦娴腶rguments長(zhǎng)度判斷,不會(huì)擴(kuò)展到j(luò)Query上去。而zepto則直接報(bào)錯(cuò)target[key] = source[key]
。
zepto:
jQuery:
jQuery中的extend語(yǔ)法與上面的zepto相同,在zepto里,最后對(duì)如果沒(méi)有proto做了兼容:
在jQuery中$.extend()與$.fn.extend()是不同也相同的,在上面的源碼里我們也看到了,jQuery.extend = jQuery.fn.extend
,只是因?yàn)閮蓚€(gè)函數(shù)的this值指向不同,所以能夠使用的場(chǎng)景也不同,可以大致分為動(dòng)態(tài)和靜態(tài)。在使用jQuery的過(guò)程中,jQuery的最外層匿名函數(shù)里會(huì)執(zhí)行,返回一個(gè)jQuery對(duì)象,并與$一起綁在window上,所以引入文件之后已經(jīng)存在,而動(dòng)態(tài)指的是jQuery.fn.init(selector,context);
所以需要先初始化再使用相應(yīng)方法。
小結(jié)
這里將一些瑣碎的知識(shí)點(diǎn)歸納了一下,事實(shí)上,zepto的擴(kuò)展與jQuery的擴(kuò)展在使用的方法上看起來(lái)一樣,但jQuery更細(xì)。了解兩者的區(qū)別能夠在需要兼容zepto和jQuery時(shí)不會(huì)犯未知錯(cuò)誤,也對(duì)擴(kuò)展插件有更好的幫助。本文使用demo(有源碼注釋):jQuery與zepto的extend