通常在函數裡面給了參數對象的預設值,這個時候就需要通過extend來把傳入的參數覆蓋進預設參數,如:
代碼:
複製代碼 代碼如下:giant.ui.imageshow = function(options) {
this.opts = $.extend({}, giant.ui.imageshow.defaults, options);
}
giant.ui.imageshow.defaults = {
id:"imageshow",
isAuto:true,
speed:3000
};
Jquery 的架構中給了一個extend工具:
jQuery.extend(target,obj1,[objN])
用一個或多個其他對象來擴充一個對象,返回被擴充的對象。
用於簡化繼承。
Extend one object with one or more others, returning the original, modified, object.
This is a great utility for simple inheritance.
傳回值--Object
參數
target (Object) : 待修改對象。
object1 (Object) : 待合并到第一個對象的對象。
objectN (Object) : (可選) 待合并到第一個對象的對象。
但架構中內建的這個extend有明顯的缺陷,那就是不能繼承對象中的對象。還是舉一個例子來說明:
代碼: 複製代碼 代碼如下:var obj1 = {},
var obj2={name:"karry",email:"karry@a.com",tel:{homeTel:"158255",officeTel:"02112585"}}
obj1 = $.extend({},obj1 ,obj2 );
結果obj1 只有name 和email屬性,而有與tel本身就是一個對象,tel裡面的homeTel和officeTel沒有繼承過去。
我的目標就是實現這種對子物件的子屬性也一起複製(繼承)的功能,不管他嵌套有多深。
首先我們看看這個方法的參數,有三個參數,target 目標對象,source 來源物件,deep 是否複製(繼承)對象中的對象,如果deep為true則繼承所有,為false則和jquery的實現方式一樣,不會繼承子物件。
代碼: 複製代碼 代碼如下:Object.extend = function(target, /*optional*/source, /*optional*/deep) {}
我只把第一個參數target設為必選參數,而source 和deep都設為選擇性參數。這樣就會遇到一個問題,如果使用的時候只傳如兩個參數,怎麼確認第二個參數是 對應的source還是deep?所以我需要判斷傳入的第二個參數的類型。
代碼: 複製代碼 代碼如下:target = target || {}; //target預設為空白
var sType = typeof source;
//如果第二個參數的類型為未定義或者為布爾值
if( sType === 'undefined' || sType === 'boolean' ) {
deep = sType === 'boolean' ? source : false;
source = target; //把target賦值給source,
target = this; //這裡的this指的是Object
}
有人可能對最後面的兩行代碼有疑問,我的處理方式是這樣的。如果target和source兩個參數都存在,且source不是布爾值,那麼,就把source對象的內容複寫給target.否則,把target對象複製給Object對象。deep預設為false.
為了安全起見,我們還需要判斷一下,如果souce滿足了上面的條件,但它不是Object對象,或者它是一個Function對象(這涉及到一些其他的問題),我們也沒辦法對其進行複製的。這個時候我們把souce設為空白的Object,也就是並不進行複製操作。
代碼: 複製代碼 代碼如下:if( typeof source !== 'object' && Object.prototype.toString.call(source) !== '[object Function]' )
source = {};
註:Function對象在執行typeof 操作時 也會返回“object”,但我們沒辦法對其進行正確的複製(至少在我這個方法裡面不行),所以我必須剔除出來。
下面就是迴圈進行複製了。這裡利用了遞迴。
代碼: 複製代碼 代碼如下:var i=1,option;
// 外層迴圈就是為了把依次修改options,先設為target,後設為source
while(i <= 2) {
options = i === 1 ? target : source;
if( options != null ) {
//內層迴圈複製對應的屬性
for( var name in options ) {
var src = target[name], copy = options[name];
if(target === copy)
continue;
//如果deep設為true,且該屬性是一個對象
if(deep && copy && typeof copy === 'object' && !copy.nodeType)
//遞迴
target[name] = this.extend(src ||(copy.length != null ? [] : {}), copy, deep);
else if(copy !== undefined)
target[name] = copy;
}
}
i++;
}
這裡利用了遞迴的方式,依次複製對象裡面的對象。這個功能就做完了。全部代碼如下:
代碼: 複製代碼 代碼如下:/*
* @param {Object} target 目標對象。
* @param {Object} source 來源物件。
* @param {boolean} deep 是否複製(繼承)對象中的對象。
* @returns {Object} 返回繼承了source對象屬性的新對象。
*/
Object.extend = function(target, /*optional*/source, /*optional*/deep) {
target = target || {};
var sType = typeof source, i = 1, options;
if( sType === 'undefined' || sType === 'boolean' ) {
deep = sType === 'boolean' ? source : false;
source = target;
target = this;
}
if( typeof source !== 'object' && Object.prototype.toString.call(source) !== '[object Function]' )
source = {};
while(i <= 2) {
options = i === 1 ? target : source;
if( options != null ) {
for( var name in options ) {
var src = target[name], copy = options[name];
if(target === copy)
continue;
if(deep && copy && typeof copy === 'object' && !copy.nodeType)
target[name] = this.extend(src ||
(copy.length != null ? [] : {}), copy, deep);
else if(copy !== undefined)
target[name] = copy;
}
}
i++;
}
return target;
};
使用樣本:
代碼: 複製代碼 代碼如下:var source = {id:1, name:'Jack Source'}, target = {name:'Jack Target', gender:1,tel:{homeTel:"158255",officeTel:"02112585"}};
var newObj1 = Object.extend(target, source);