jQuery自定義了jQuery.extend()和jQuery.fn.extend()方法.其中jQuery.extend()方法能夠創建全局函數或者選擇器,而jQuery.fn.extend()方法能夠創建jQuery對象方法.
這兩個方法用的是相同的代碼,一個用於給jQuery對象或者普通對象合並屬性和方法一個是針對jQuery對象的實例,對於基本用法舉幾個例子:
html代碼如下:
代碼如下:
下面寫js裡面的用法:
合並兩個普通對象
代碼如下:
//給兩個普通對象合並屬性
var obj1={name:'Tom',age:22};
var obj2={name:'Jack',height:180};
console.log($.extend(obj1,obj2)); //Object {name: "Jack", age: 22, height: 180}
給jQuery對象添加屬性或者方法
代碼如下:
$.extend({hehe:function(){alert('hehe');}});
$.hehe(); //alert('hehe')
這個用法很重要,是jQuery內部添加實例屬性和方法以及原型屬性和方法的實現方法也是編寫jQuery插件的方法,下面是jQuery1.7.1中使用extend方法擴展自己的方法和屬性
代碼如下:
jQuery.extend({
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
.....
在這個例子中只傳入了一個對象參數,那麼默認就把this當做待合並修改的對象
給jQuery對象實例添加屬性或者方法
代碼如下:
//針對jQuery實例擴展合並
console.log($('img').extend({'title':'img'}));//[img, img#img.img, prevObject: jQuery.fn.jQuery.init[1], context: document, selector: "img", title: "img", constructor: function…]
只合並不修改待合並對象
代碼如下:
var obj1={name:'Tom',age:22};
var obj2={name:'Jack',height:180};
console.log($.extend(obj1,obj2)); //Object {name: "Jack", age: 22, height: 180}
console.log(obj1); //Object {name: "Jack", age: 22, height: 180}
默認情況下,待合並對象跟返回結果一樣是被修改了的,如果僅僅想得到一個合並後的對象又不想破壞任何一個原來的對象可以使用此方法
代碼如下:
var obj1={name:'Tom',age:22};
var obj2={name:'Jack',height:180};
var empty={};
console.log($.extend(empty,obj1,obj2)); //Object {name: "Jack", age: 22, height: 180}
console.log(obj1); //Object {name: "Tom", age: 22}
使用則遞歸合並或者叫深度拷貝
代碼如下:
var obj1={name:'Tom',love:{drink:'milk',eat:'bread'}};
var obj2={name:'Jack',love:{drink:'water',sport:'football'}};
console.log(($.extend(false,obj1,obj2)).love); //Object {drink: "water", sport: "football"}
console.log(($.extend(true,obj1,obj2)).love); //Object {drink: "water", eat: "bread", sport: "football"}
詳細的使用方法可以看參考手冊http://www.w3cschool.cc/manual/jquery/
下面來分析下1.7.1源碼中是怎麼實現的:
代碼如下:
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
...
}
首先是定義了一組變量,因為參數個數不確定所以就直接調用arguments對象訪問傳遞的參數
變量 options:指向某個源對象。
‰ ‰ 變量 name:表示某個源對象的某個屬性名。
‰ ‰ 變量 src:表示目標對象的某個屬性的原始值。
‰ ‰ 變量 copy:表示某個源對象的某個屬性的值。
‰ ‰ 變量 copyIsArray:指示變量 copy 是否是數組。
‰ ‰ 變量 clone:表示深度復制時原始值的修正值。
‰ ‰ 變量 target:指向目標對象。
‰ ‰ 變量 i:表示源對象的起始下標。
‰ ‰ 變量 length:表示參數的個數,用於修正變量 target。
‰ ‰ 變量 deep:指示是否執行深度復制,默認為 false。
為了更好地了解代碼實現這裡以上面舉的一個例子作為演示觀察源代碼執行情況
代碼如下:
var obj1={name:'Tom',love:{drink:'milk',eat:'bread'}};
var obj2={name:'Jack',love:{drink:'water',sport:'football'}};
$.extend(true,obj1,obj2)
源碼分析
代碼如下:
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
判斷是不是深度復制,如果第一個參數是布爾值那麼就把第一個參數的值給deep,然後把第二個參數作為目標對象,如果第二個參數不存在就賦值為一個空對象,把源對象的下標改為2,在這個例子裡面 是走這裡的因為第一個參數是ture然後把deep變成了true ,target被修正成了第二個參數也即是obj1,源對象的起始下標為2就是從第三個開始作為源對象也就是本例中的obj2
代碼如下:
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
這裡對target又進一步進行了處理對於非對象和函數的數據類型而言增加自定義屬性是無效的比如字符串自能調用自帶的方法和屬性
代碼如下:
// extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
}
如果length屬性等於i的值那就表示沒有目標對象存在,正常情況下length應該是大於i的值的 ,那麼這個時候就把this作為目標對象把i值減一實現length值大於i值(比i大1)
這個就是jQuery給自己擴展屬性的方法的實現原理,只要不傳入目標對象就可以啦
兩種可能的情況:$.extend(obj) 或者 $.extend(false/true,obj);
代碼如下:
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
這個部分就是此方法的核心了,從arguements對象的第i個下標值開始循環操作首先過濾掉源對象是null或者是undefined的情況可以看到其實
源對象不一定真的就是對像,也可以是其他類型的值比如字符串比如這樣寫:
代碼如下:
console.log($.extend({'nam