先前对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块一个的工程师,一条狗咬死一片的那种。。。”