先前對javascript的繼承學的很模糊,由此我就百度各種文章,然文章千奇百怪,雖不乏精妙之言,卻獨無對吾之口味,由此從jquery
中的extend方法開始學起,首先上源碼copy自jQuery1.7版本
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
}
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;
}
}
}
}
// Return the modified object
return target;
};
籠統看一遍,很難產生什么直觀的感覺,先看該方法的定義
合並兩個或更多的對象匯集成到第一個對象中
jQuery.extend([deep,]Target[,object1,][objectN]);
可以去看一下該函數的說明,有以下幾種用法
jQuery.extend(object); jQuery.extend(object1,object2,objectN); jQuery.extend(bool,object1); jQuery.extend(bool,object1,object2,objectN);
我們從上面的方法來分析jQuery是怎么處理的,首先是jQuery.extend(object)。一個參數的時候,目標對象將會被jquery本身代替
//對象1
var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};
$.extend(obj1);
document.write($.name);
//result:
//hello
對象的屬性已經被附加到jQuery中了,看看其實現
//關鍵之處,參數的長度如果和預設的長度相等的話,那么目標對象將會被改變為自身
if ( length === i ) {
target = this;
--i;
}
然后就是對象的拷貝
//這里的拷貝只是簡單的拷貝,通常說的淺拷貝,與深拷貝的不同繼續看下面
else if ( copy !== undefined ) {
target[ name ] = copy;
}
那么深拷貝與淺拷貝有什么不同呢?看例子
淺拷貝
//對象1
var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};
$.extend(obj1);
obj1.name="hello is changed!";
obj1.fruits[0]="1 is changed";
obj1.bb.name="gg is changed";
document.write($.name+"<br>"+$.fruits[0]+"<br>"+$.bb.name);
//results:
//hello
//1 is changed
//gg is changed
//結果表明obj1的array與object類型的數據被改變后會影響到目標對象,而值類型
//確不會,現在是不是有點意思了,深拷貝就是要排除這個影響,讓他們互不侵犯
深拷貝
//對象1
var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};
$.extend(true,obj1); //調用時候變成了2個參數,第一個布爾值就是深拷貝標識
obj1.name="I changed!";
obj1.fruits[0]="1 is changed";
obj1.bb.name="gg is changed";
document.write($.name+"<br>"+$.fruits[0]+"<br>"+$.bb.name);
//results:
//hello
//1
//gg
//現在源對象的改變再也不會影響到目標對象了,下面看看jquery是怎么實現的
關鍵點把對象或數組的拷貝轉化為值的拷貝
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
//對象是否是數組,是的話記錄對象本身,否則創建一個新的空數組
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
//對象是否為object,是的話記錄對象本身,否則創建一個新的空對象
}
//關鍵之處,對array或object進行迭代,把他們的值進行拷貝
target[ name ] = jQuery.extend( deep, clone, copy );
現在再看jQuery.extend(object1,object2,objectN);、jQuery.extend(bool,object1,object2,objectN);這兩種用法就很容易理解是怎么實現的了。
//對象1
var obj1={name:"hello",sex:"man",fruits:["1","2"],bb:{name:"gg"}};
//對象2
var obj2={name:"world",sex:"woman",fruits:["3","4"],bb:{name:"mm"}};
//對象3
var obj3={name:"!",sex:"undefind",fruits:["5","6"],bb:{name:"gm"}};
$.extend(obj1,obj2,obj3);
obj3.bb.name="gm is changed"; //如果是obj2.bb.name="aa";是不會影響obj1的,因為參數是依次遍歷的哦,前面的會被后面的覆蓋
for(var i in obj1){
if(jQuery.type(obj1[i])=="array"||jQuery.type(obj1[i])=="object")
{
for(var i2 in obj1[i]){document.write("<br>"+obj1[i][i2]);}
}else{
document.write("<br>"+obj1[i]);
}
}
//results:
//!
//undefind
//5
//6
//gm is changed 這里是淺拷貝的緣故哦
$.extend(true,obj1,obj2,obj3); 深拷貝
//results:
//!
//undefined
//5
//6
//gm
以上就是jquery用來實現“繼承”的方法,和傳統的OO繼承比較,不同的是,“子類”的屬性、方法會被“父類”的屬性、方法給覆蓋,這讓我有點費解,也許
是被先入為主的思想所左右了,也奇怪jquery的開發人員怎么不搞的傳統點,也許他們覺得這樣也就夠了,也許我沒理解透徹。
扯着扯着,又得寫下,傳統的OO繼承在JS中的實現
看個例子
//將Object.prototype上的toString方法重寫,以便測試
Object.prototype.toString=function(){document.write("I am object");};
//父類
function ParentFunction(){
this.toString=function (){document.write("I am parent");}
}
ParentFunction.prototype.toString=function(){document.write("I am parent prototype");};
//子類
function SubFunction(){
this.toString=function(){document.write("I am sub");}
}
//SubFunction繼承了ParentFunction,通過將原型new一個ParentFunction對象來建立關系
SubFunction.prototype=new ParentFunction();
//由於上面的prototype被重寫了,而我們又必須讓原型鏈完整,構造函數屬性指向SubFunction
SubFunction.prototype.constructor=SubFunction;
//可以再在prototype上添加方法
//SubFunction.prototype.toString=function(){document.write("I am sub prototype");};
var test=new SubFunction();
test.toString(); //result: I am sub
結果貌似不怎么明顯表達意思,那么把SubFunction里的方法去掉
//result: I am parent
有點意思了,方法調用的是父類的本地代碼里的方法,再將ParentFunction里的方法去掉
//result: I am parent prototype
調用的是父類prototype上的方法,繼續把ParentFunction.prototype.toString去掉如何?
//result: I am object
調用了Object對象上的方法,別奇怪,那是因為Object是所有對象的父類。
上個圖,也許能理解的清楚點
學習做此小記,最后歡快一下。
“辛苦十幾年,你也不過是紅警里500塊一個的工程師,一條狗咬死一片的那種。。。”