JavaScript Object的extend是一個(gè)常用的功能
更新時(shí)間:2009年12月02日 00:42:08 作者:
對(duì)Object的extend是一個(gè)常用的功能。舉一個(gè)例子,由于javascript 沒(méi)有重載(overload),而且函數(shù)的參數(shù)類(lèi)型是沒(méi)有定義的,所以很多時(shí)候我們都傳入一個(gè)對(duì)象來(lái)作為參數(shù)已方便控制。
通常在函數(shù)里面給了參數(shù)對(duì)象的默認(rèn)值,這個(gè)時(shí)候就需要通過(guò)extend來(lái)把傳入的參數(shù)覆蓋進(jìn)默認(rèn)參數(shù),如:
代碼:
giant.ui.imageshow = function(options) {
this.opts = $.extend({}, giant.ui.imageshow.defaults, options);
}
giant.ui.imageshow.defaults = {
id:"imageshow",
isAuto:true,
speed:3000
};
Jquery 的框架中給了一個(gè)extend工具:
jQuery.extend(target,obj1,[objN])
用一個(gè)或多個(gè)其他對(duì)象來(lái)擴(kuò)展一個(gè)對(duì)象,返回被擴(kuò)展的對(duì)象。
用于簡(jiǎn)化繼承。
Extend one object with one or more others, returning the original, modified, object.
This is a great utility for simple inheritance.
返回值--Object
參數(shù)
target (Object) : 待修改對(duì)象。
object1 (Object) : 待合并到第一個(gè)對(duì)象的對(duì)象。
objectN (Object) : (可選) 待合并到第一個(gè)對(duì)象的對(duì)象。
但框架中內(nèi)置的這個(gè)extend有明顯的缺陷,那就是不能繼承對(duì)象中的對(duì)象。還是舉一個(gè)例子來(lái)說(shuō)明:
代碼:
var obj1 = {},
var obj2={name:"karry",email:"karry@a.com",tel:{homeTel:"158255",officeTel:"02112585"}}
obj1 = $.extend({},obj1 ,obj2 );
結(jié)果obj1 只有name 和email屬性,而有與tel本身就是一個(gè)對(duì)象,tel里面的homeTel和officeTel沒(méi)有繼承過(guò)去。
我的目標(biāo)就是實(shí)現(xiàn)這種對(duì)子對(duì)象的子屬性也一起復(fù)制(繼承)的功能,不管他嵌套有多深。
首先我們看看這個(gè)方法的參數(shù),有三個(gè)參數(shù),target 目標(biāo)對(duì)象,source 源對(duì)象,deep 是否復(fù)制(繼承)對(duì)象中的對(duì)象,如果deep為true則繼承所有,為false則和jquery的實(shí)現(xiàn)方式一樣,不會(huì)繼承子對(duì)象。
代碼:
Object.extend = function(target, /*optional*/source, /*optional*/deep) {}
我只把第一個(gè)參數(shù)target設(shè)為必選參數(shù),而source 和deep都設(shè)為可選參數(shù)。這樣就會(huì)遇到一個(gè)問(wèn)題,如果使用的時(shí)候只傳如兩個(gè)參數(shù),怎么確認(rèn)第二個(gè)參數(shù)是 對(duì)應(yīng)的source還是deep?所以我需要判斷傳入的第二個(gè)參數(shù)的類(lèi)型。
代碼:
target = target || {}; //target默認(rèn)為空
var sType = typeof source;
//如果第二個(gè)參數(shù)的類(lèi)型為未定義或者為布爾值
if( sType === 'undefined' || sType === 'boolean' ) {
deep = sType === 'boolean' ? source : false;
source = target; //把target賦值給source,
target = this; //這里的this指的是Object
}
有人可能對(duì)最后面的兩行代碼有疑問(wèn),我的處理方式是這樣的。如果target和source兩個(gè)參數(shù)都存在,且source不是布爾值,那么,就把source對(duì)象的內(nèi)容復(fù)制給target.否則,把target對(duì)象復(fù)制給Object對(duì)象。deep默認(rèn)為false.
為了安全起見(jiàn),我們還需要判斷一下,如果souce滿足了上面的條件,但它不是Object對(duì)象,或者它是一個(gè)Function對(duì)象(這涉及到一些其他的問(wèn)題),我們也沒(méi)辦法對(duì)其進(jìn)行復(fù)制的。這個(gè)時(shí)候我們把souce設(shè)為空的Object,也就是并不進(jìn)行復(fù)制操作。
代碼:
if( typeof source !== 'object' && Object.prototype.toString.call(source) !== '[object Function]' )
source = {};
注:Function對(duì)象在執(zhí)行typeof 操作時(shí) 也會(huì)返回“object”,但我們沒(méi)辦法對(duì)其進(jìn)行正確的復(fù)制(至少在我這個(gè)方法里面不行),所以我必須剔除出來(lái)。
下面就是循環(huán)進(jìn)行復(fù)制了。這里利用了遞歸。
代碼:
var i=1,option;
// 外層循環(huán)就是為了把依次修改options,先設(shè)為target,后設(shè)為source
while(i <= 2) {
options = i === 1 ? target : source;
if( options != null ) {
//內(nèi)層循環(huán)復(fù)制對(duì)應(yīng)的屬性
for( var name in options ) {
var src = target[name], copy = options[name];
if(target === copy)
continue;
//如果deep設(shè)為true,且該屬性是一個(gè)對(duì)象
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++;
}
這里利用了遞歸的方式,依次復(fù)制對(duì)象里面的對(duì)象。這個(gè)功能就做完了。全部代碼如下:
代碼:
/*
* @param {Object} target 目標(biāo)對(duì)象。
* @param {Object} source 源對(duì)象。
* @param {boolean} deep 是否復(fù)制(繼承)對(duì)象中的對(duì)象。
* @returns {Object} 返回繼承了source對(duì)象屬性的新對(duì)象。
*/
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);
代碼:
復(fù)制代碼 代碼如下:
giant.ui.imageshow = function(options) {
this.opts = $.extend({}, giant.ui.imageshow.defaults, options);
}
giant.ui.imageshow.defaults = {
id:"imageshow",
isAuto:true,
speed:3000
};
Jquery 的框架中給了一個(gè)extend工具:
jQuery.extend(target,obj1,[objN])
用一個(gè)或多個(gè)其他對(duì)象來(lái)擴(kuò)展一個(gè)對(duì)象,返回被擴(kuò)展的對(duì)象。
用于簡(jiǎn)化繼承。
Extend one object with one or more others, returning the original, modified, object.
This is a great utility for simple inheritance.
返回值--Object
參數(shù)
target (Object) : 待修改對(duì)象。
object1 (Object) : 待合并到第一個(gè)對(duì)象的對(duì)象。
objectN (Object) : (可選) 待合并到第一個(gè)對(duì)象的對(duì)象。
但框架中內(nèi)置的這個(gè)extend有明顯的缺陷,那就是不能繼承對(duì)象中的對(duì)象。還是舉一個(gè)例子來(lái)說(shuō)明:
代碼:
復(fù)制代碼 代碼如下:
var obj1 = {},
var obj2={name:"karry",email:"karry@a.com",tel:{homeTel:"158255",officeTel:"02112585"}}
obj1 = $.extend({},obj1 ,obj2 );
結(jié)果obj1 只有name 和email屬性,而有與tel本身就是一個(gè)對(duì)象,tel里面的homeTel和officeTel沒(méi)有繼承過(guò)去。
我的目標(biāo)就是實(shí)現(xiàn)這種對(duì)子對(duì)象的子屬性也一起復(fù)制(繼承)的功能,不管他嵌套有多深。
首先我們看看這個(gè)方法的參數(shù),有三個(gè)參數(shù),target 目標(biāo)對(duì)象,source 源對(duì)象,deep 是否復(fù)制(繼承)對(duì)象中的對(duì)象,如果deep為true則繼承所有,為false則和jquery的實(shí)現(xiàn)方式一樣,不會(huì)繼承子對(duì)象。
代碼:
復(fù)制代碼 代碼如下:
Object.extend = function(target, /*optional*/source, /*optional*/deep) {}
我只把第一個(gè)參數(shù)target設(shè)為必選參數(shù),而source 和deep都設(shè)為可選參數(shù)。這樣就會(huì)遇到一個(gè)問(wèn)題,如果使用的時(shí)候只傳如兩個(gè)參數(shù),怎么確認(rèn)第二個(gè)參數(shù)是 對(duì)應(yīng)的source還是deep?所以我需要判斷傳入的第二個(gè)參數(shù)的類(lèi)型。
代碼:
復(fù)制代碼 代碼如下:
target = target || {}; //target默認(rèn)為空
var sType = typeof source;
//如果第二個(gè)參數(shù)的類(lèi)型為未定義或者為布爾值
if( sType === 'undefined' || sType === 'boolean' ) {
deep = sType === 'boolean' ? source : false;
source = target; //把target賦值給source,
target = this; //這里的this指的是Object
}
有人可能對(duì)最后面的兩行代碼有疑問(wèn),我的處理方式是這樣的。如果target和source兩個(gè)參數(shù)都存在,且source不是布爾值,那么,就把source對(duì)象的內(nèi)容復(fù)制給target.否則,把target對(duì)象復(fù)制給Object對(duì)象。deep默認(rèn)為false.
為了安全起見(jiàn),我們還需要判斷一下,如果souce滿足了上面的條件,但它不是Object對(duì)象,或者它是一個(gè)Function對(duì)象(這涉及到一些其他的問(wèn)題),我們也沒(méi)辦法對(duì)其進(jìn)行復(fù)制的。這個(gè)時(shí)候我們把souce設(shè)為空的Object,也就是并不進(jìn)行復(fù)制操作。
代碼:
復(fù)制代碼 代碼如下:
if( typeof source !== 'object' && Object.prototype.toString.call(source) !== '[object Function]' )
source = {};
注:Function對(duì)象在執(zhí)行typeof 操作時(shí) 也會(huì)返回“object”,但我們沒(méi)辦法對(duì)其進(jìn)行正確的復(fù)制(至少在我這個(gè)方法里面不行),所以我必須剔除出來(lái)。
下面就是循環(huán)進(jìn)行復(fù)制了。這里利用了遞歸。
代碼:
復(fù)制代碼 代碼如下:
var i=1,option;
// 外層循環(huán)就是為了把依次修改options,先設(shè)為target,后設(shè)為source
while(i <= 2) {
options = i === 1 ? target : source;
if( options != null ) {
//內(nèi)層循環(huán)復(fù)制對(duì)應(yīng)的屬性
for( var name in options ) {
var src = target[name], copy = options[name];
if(target === copy)
continue;
//如果deep設(shè)為true,且該屬性是一個(gè)對(duì)象
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++;
}
這里利用了遞歸的方式,依次復(fù)制對(duì)象里面的對(duì)象。這個(gè)功能就做完了。全部代碼如下:
代碼:
復(fù)制代碼 代碼如下:
/*
* @param {Object} target 目標(biāo)對(duì)象。
* @param {Object} source 源對(duì)象。
* @param {boolean} deep 是否復(fù)制(繼承)對(duì)象中的對(duì)象。
* @returns {Object} 返回繼承了source對(duì)象屬性的新對(duì)象。
*/
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;
};
使用示例:
代碼:
復(fù)制代碼 代碼如下:
var source = {id:1, name:'Jack Source'}, target = {name:'Jack Target', gender:1,tel:{homeTel:"158255",officeTel:"02112585"}};
var newObj1 = Object.extend(target, source);
您可能感興趣的文章:
- js如何獲取object類(lèi)型里的鍵值
- JS 對(duì)象(Object)和字符串(String)互轉(zhuǎn)方法
- js如何打印object對(duì)象
- JavaScript 判斷判斷某個(gè)對(duì)象是Object還是一個(gè)Array
- 刪除Javascript Object中間的key
- 詳解Javascript中的Object對(duì)象
- Javascript中判斷變量是數(shù)組還是對(duì)象(array還是object)
- Javascript Object.extend
- 深入理解JavaScript中的對(duì)象復(fù)制(Object Clone)
- JS Object.preventExtensions(),Object.seal()與Object.freeze()用法實(shí)例分析
相關(guān)文章
JS調(diào)用頁(yè)面表格導(dǎo)出excel示例代碼
這篇文章主要介紹了JS調(diào)用頁(yè)面表格導(dǎo)出excel的具體實(shí)現(xiàn),需要的朋友可以參考下2014-03-03javascript閉包傳參和事件的循環(huán)綁定示例探討
按常理循環(huán)綁定事件,但是得到的結(jié)果卻不是想要的,下面有個(gè)不錯(cuò)的示例,可以為大家詳細(xì)分解下2014-04-04一文詳解preact的高性能狀態(tài)管理Signals
這篇文章主要介紹了一文詳解preact的高性能狀態(tài)管理Signals,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的朋友可以參考一下2022-09-09TypeScript常見(jiàn)類(lèi)型及應(yīng)用示例講解
這篇文章主要介紹了TypeScript常見(jiàn)類(lèi)型及應(yīng)用示例講解,本章我們會(huì)講解?JavaScript?中最常見(jiàn)的一些類(lèi)型,以及對(duì)應(yīng)的描述方式,有需要的朋友可以借鑒參考下2022-02-02javascript 支持鏈?zhǔn)秸{(diào)用的異步調(diào)用框架Async.Operation
javascript 支持鏈?zhǔn)秸{(diào)用的異步調(diào)用框架Async.Operation2009-08-08微信小程序自定義toast彈窗效果的實(shí)現(xiàn)代碼
微信小程序里面的自帶彈窗icon只有兩種,success和loading。這篇文章主要介紹了微信小程序之自定義toast彈窗效果的實(shí)現(xiàn)代碼 ,需要的朋友可以參考下2018-11-11