有網友提問,看不太懂jQuery.extend的用法,本想在留言裡回覆,但寫著寫著,發現要說到淺顯白話,還真得花些篇幅,索性另起一篇,解釋得更詳細點。

以jQuery.extend(objA, objB)為例,你可以想像成objA與objB各有一些屬性(方法也會比照處理,在此只提屬性),extend()會將objB有而objA沒有的屬性加到objA裡,如果objB裡的某個屬性,objA裡剛好也有同名的屬性,則會用objB的屬性值去覆寫objA原有的屬性。objA最後就是整合結果,或者也可以由var objC = jQuery.extend(objA, objB)取得整合結果(objA == objC)。

例如以下的程式碼,大家可以丟到Mini jQuery Lab跑一下,馬上就可以驗證jQuery.extend的效果:

var objA = { speed:"slow" };
var objB = { speed:"fast", power:"hard" };
var objC = jQuery.extend( objA, objB );
document.write("<dt>objA");
for (var p in objA) { document.write("<dd>" + p + "->" + objA[p]); }
document.write("<dt>objC");
for (var p in objC) { document.write("<dd>" + p + "->" + objC[p]); }

所得結果objA與objC的內容相同,都有兩個屬性speed:"fast"(被覆寫), power:"hard"(新加的)。

jQuery.extend可以支援多個物件屬性/方法的整併,並不限於兩個。例如: jQuery.extend(objA, objB, objC),objB, objC多出的屬性都會加到objA裡,如果有objA已有同名屬性,則會用objC/objB裡的屬性值覆寫之,若objB, objC都用同名屬性,則會排在後方的objC為準(後令壓前令)。

jQuery.extend的最常見的用途是用來處理Plugin或函數的傳入參數,比如函數會用到的參數有10個,但大部分情況呼叫時只需要指定其中一兩個,其餘的用預設值即可。於是我們可以在函數中宣告一個預設值物件objDefault,裡面已有10個屬性,呼叫函數時則傳入objOption,裡面只放入一兩個要變更的屬性值,經過var objSetting = jQuery.extend(objDefault, objOption)之後,我們得到10個"有指定用指定值,沒指定用預設值"的屬性供後續使用。舉個例子:

function addDiv(options) {
    var defaults = { 
        border: "solid 1px black",
        backgroundColor: "#cccccc",
        width: "200px", height: "50px",
    margin: "10px"
    };
    var settings = $.extend(defaults, options);
    $("<div></div>").css(settings).appendTo("body");
}
addDiv({ width: "400px" });
addDiv({ backgroundColor: "orange", height: "100px" });

希望這樣的說明夠清楚。


Comments

# by chicken

覺的比較有趣的,不是 jQuery.extend 的用法,而是它的用途... 一般的程式語言都沒這樣的東西,即使是 .NET 內的 Dictionary 也沒有對等的... 因為用途不一樣啊。extend 看起來像是 javascript 沒有正規的 "類別繼承" 的衍生作法, extend(objA, objB) 感覺就像 objA 去繼承 objB 一樣,只不過一般講的繼承是對 class, 這裡是對 object, 而且繼承的時間點從 coding time 延後到 run time ... 不過朝這角度想,extend 的用途就清楚多了...

# by Will 保哥

我 run 的結果跟你寫的不同耶,所得結果objA與objC的內容不一樣, objC 沒有 power 屬性: objA   speed->fast   power->hard objC   speed->fast

# by KINK

版大... 感謝您! 看來要多用幾次來熟悉這方便的語法了^^~

# by Jeffrey

to chicken, 這陣子Javascript寫多了,開始覺得可以不用宣告,就在Runtime"惡搞"起物件也有其獨到的方便之處。而C# 4.0裡的Dynamic Programming我個人覺得就有點向JS這種"不嚴謹"的精神傾斜... 程式語言的發展真是奇妙。 to 保哥,好像在Chrome裡<dd>因為沒有結尾</dd>所以最後一列不會馬上印出來,最後再加一個document.write("<hr />")應該可以改善。

# by metavige

javascript 本來就沒有類似 OOP 那種 extends 的觀念 他有 prototype 的方式可以做到類似繼承的東西 只是,因為 javascript 是弱型別,沒辦法像是 C# or Java 這樣 所以,只要名稱相同,就會被覆蓋掉 jQuery 只是提供了一個易懂的方式去讓 "繼承" 這件事情變得更貼近語意 如果寫 prototype 大概很少人會懂吧 因為這種作法,其實並不是現在才出現的 很早以前(我記得沒錯應該是七八年前了)就已經有這樣的作法了~

# by kink

Jeffrey大... 冒昧又來求問了:p關於以下的語法,小弟不理解其中的 var bb = this這段的涵義@@! 為什麼不能用$(this).dequeue();這樣呢? $.fn.wait = function(time, type) { time = time || 1000; type = type || "fx"; return this.queue(type, function() { var bb = this; //alert($(bb).attr("nodeName")); setTimeout(function() { $(bb).dequeue(); }, time); }); };

# by Jeffrey

to kink, PO了一篇文回答你的問題,Check it out. http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/03/11/js-this-and-closure.aspx

# by joeshow

不错。。谢谢

# by Raphael

見到此篇真是豁然開朗, 太感謝了.

# by A-chung

寫得真的不錯~簡單明瞭~感謝分享!!

# by Jill

非常感謝您~!

# by jessie

你好:我可以請教有關以下這個函數的用途嘛? $.fn.ntAccordion = function(options) { var _defaultSettings = { }; var _opts = $.extend(_defaultSettings, options); var _init = function(container){ var height=26*7; $(container).find('.menu.level01').next().each(function(){ height=$(this).height()>height?$(this).height():height; }).css({height:height}); $('.menu.level02[s=none]').hover( function(){ $(this).find('tr:first td:last').children().show(); }, function(){ $(this).find('tr:first td:last').children().hide(); } ).each(function(){ var url=Base64.decode($(this).attr('url')); $(this).unbind('click').click(function(){ location.href=url; }); }); }; var _handler = function() { var container=this; _init(container); $(container).find('.menu.level01').click(function(){ $(this).siblings('.menu.level02:visible').hide('fast'); $(this).next(':hidden').slideDown('fast'); }); }; return this.each(_handler); };

# by Jeffrey

to jessie,看起來是用來製作收合式選單的Plugin(滑鼠滑過時展開),但要配合適當的class設定才能順利運作。

# by anyyou

看完就解惑了~謝謝大大

# by Hardy

改成這樣子,就能馬上了解他們之間的曖昧關係了 var objA = { speed:"fast" }; var objB = { speed:"slow", power:"hard" }; document.write("<dt>objB"); for (var p in objB) { document.write("<dd>" + p + "->" + objB[p]); } var objC = jQuery.extend( objB, objA ); document.write("<dt>objC"); for (var p in objC) { document.write("<dd>" + p + "->" + objC[p]); }

Post a comment