由jQuery深拷贝引发的学习

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

原文地址:https://www.cnblogs.com/whosedream/p/2391467.html