javascript的一切实例都是对象,只是对象之间稍有不同,分为原始类型和合成类型。原始类型对象指的是字符串(String)、数值(Number)、布尔值(Boolean),合成类型对象指的是数组(Array)、对象(Object)、函数(Function)。
既然对象分为这两类,他们之间的最大差别是复制克隆的差别。普通对象存储的是对象的实际数据,而引用对象存储的是对象的引用地址,而把对象的实际内容单独存放,因为引用对象通常比较庞大,这是数据开销和内存开销优化的手段。通常初学者很难理解这部分内容,就像对象的原型一样,也是同一个概念。对象的原型也是引用对象,把原型的方法和属性放在单独内存当中,而对象的原型链则指向这个内存地址。尽管这部分内容比较拗口复杂,那其中的原理都是一致的,目的也一致。
引用
var myArrayRef = new Array(0,1,2); //创建数组对象
var mySeconArrayRef = myArrayRef; // 对象复制.
myArrayRef[0] = 100; // 修改元素值
alert(mySeconArrayRef[0]);
/**
* javascript语言中创建的对象myArrayRef值中其时保存的是对象的引用(也就是一个地址).
* 也就是 我用 new Array生成的保存在内存中,而new Array把它所在的地方告诉了myArrayRef,
* myArrayRef又把这地址告诉了mySeconArrayRef
* 他们两个都指向的是new Array生成对象的地址而不是把对象保存在myArrayRef中,
* 所以通过其中的一个去修改值时其时是修改他们同指象的那对象.
*/
赋值
var myVa = 'ABC'; //把ABC的值 赋予了myVa
var myVb = myVa; // myVa 赋值给 myVb
myVa = 'DEF'; //修改myVa
console.log(myVa ); //ABC
// 把值保存在了变量里, 而不是引用地址,所以他们两个是相对独立的整体.
如果真要复制对象互不影响,则要通过转换赋值或者遍历key:value来复制你对象中的方法和属性
jquery转换赋值
var data = {a:1,b:2,c:3,d:[0,1,2,3]};
var str = JSON.stringify(data);
var data1 = $.parseJSON(str); //$为jQuery对象需要引入jQuery包
data1["e"] = 4;
data1["d"][0] = 11;
console.log(data);
console.log(data1);
输出结果:
{a: 1, b: 2, c: 3, d: [0,1,2,3]}
{a: 1, b: 2, c: 3, d: [11,1,2,3], e: 4}
相互没有影响
浅拷贝
我们需要封装一个函数,来对对象进行拷贝,通过for in 循环获取基本类型,赋值每一个基本类型,才能真正意义上的复制一个对象
var obj = { a:10 };
function copyObj(obj){
var newobj = {};
for ( var key in obj) {
newobj[key ] = obj[key ];
}
return newobj;
}
var obj2 = copyObj(obj);
obj2.a = 20;
alert(obj.a); //10
深拷贝
浅拷贝存在隐患,如果obj中,a的值不是10,而是一个对象,这样就会导致在for in中,将a这个对象的引用赋值为新对象,导致存在对象引用的问题。
var obj = {a:{b:10}};
function copyObj(obj){
var newobj = {};
for ( var key in obj) {
newobj[key ] = obj[key ];
}
return newobj;
}
var obj2 = copyObj(obj);
obj2.a.b = 20;
alert(obj.a.b); //20
因此,由于这个copy对象只是对第一层进行拷贝,无法拷贝深层的对象,这个copy为浅拷贝,对象的子对象也是引用,所以遍历赋值的时候要判断,子元素是否是对象,如果子元素是对象,则继续对子元素进行遍历赋值,我们需要通过递归,来拷贝深层的对象。
var obj = {a:{b:10}};
function deepCopyObj(obj){
if(typeof obj != 'object'){
return obj;
}
var newobj = {};
for ( var attr in obj) {
newobj[attr] = deepCopyObj(obj[attr]);
}
return newobj;
}
var obj2 = deepCopyObj(obj);
obj2.a.b = 20;
alert(obj.a.b); //10
对象引用做为函数参数传递
对象引用做为函数参数传递时候,依然会相互影响,切记,如下示例:
var data = {a:1,b:2,c:3,d:{q:4,w:5,e:6}};
var data1 = data;
function con(data2){
data2["r"] = 5;
console.log(JSON.stringify(data2));
}
con(data1);
console.log(JSON.stringify(data));
输出结果:
{"a":1,"b":2,"c":3,"d":{"q":4,"w":5,"e":6},"r":5}
{"a":1,"b":2,"c":3,"d":{"q":4,"w":5,"e":6},"r":5}
对象引用赋值后,如果将对象置空,相互不受影响
var arr = {"a":"1","b":"2"};
var arr1 = arr;
arr = {};
arr["a"] = 2;
console.log(arr1);
console.log(arr);
输出结果:{"a":"1","b":"2"},{"a":2}
函数的克隆
var x=function(){alert(1);};
var y=x;
y=function(){alert(2);};
// function(){alert(1);};
alert(x);
// y=function(){alert(2);};
alert(y);
函数的克隆,使用“=”符号就可以了,并且在改变克隆后的对象,不会影响克隆之前的对象,因为克隆之后的对象会单独复制一次并存储实际数据的,是真实的克隆。
完整的对象克隆
function clone(obj) {
var o,i,j,k;
if(typeof(obj)!="object" || obj===null)return obj;
if(obj instanceof(Array)) {
o=[];
i=0;
j=obj.length;
for(;i<j;i++) {
if(typeof(obj[i])=="object" && obj[i]!=null) {
o[i]=arguments.callee(obj[i]);
} else {
o[i]=obj[i];
}
}
}else {
o={};
for(i in obj){
if(typeof(obj[i])=="object" && obj[i]!=null){
o[i]=arguments.callee(obj[i]);
}else{
o[i]=obj[i];
}
}
}
return o;
}