【JavaScript】对象引用、浅拷贝、深拷贝详解

前言:ECMAScript有五种简单数据类型(也称为基本数据类型),也有一复杂数据类型,那就是object了。数组可以是数组对象,函数可以是函数对象,普通对象类型也是,这些object都存在对象引用的问题。

一、对象的引用

var arr = ['nick','freddy','mike'];  
var newArr = arr;
newArr.push('james');

console.log(arr);     //输出原有的arr

arr = null;		//把原有的arr指向null空对象指针
console.log(newArr);  //输出newArr

输出结果:


会发现往newArr数组对象中push的“james”也出现在原有的arr中,然后我们将原有的arr数组对象指向null空对象指针,然后发现nreArr一样可以进行输出。其中发生了什么?

其实我们创建一个数组(对象)时,它单独开辟了一个新内存(空间),并不是属于任何人,

①如var arr = ['nick','freddy','mike'];中,数组['nick','freddy','mike']单独开辟了一个新内存(空间)。而var arr = ['nick','freddy','mike'],只是把变量arr的指针指向了数组['nick','freddy','mike'],并不是把['nick','freddy','mike']赋值给arr。他们只存在引用的关系。

②我们让var newArr = arr;只是给变量newArr也添加了一个指向['nick','freddy','mike']的指针。

我们让arr = null; 是把变量arr的指针改变了,让他不再指向['nick','freddy','mike'],而是指向null。

二、浅拷贝

①浅拷贝数组

var arr = ['nick','freddy','mike'];  

function copy(arr){
	var newArr = [];
	for(var i in arr){
		newArr[i] = arr[i];
	}
	return newArr;
}

var arr2 = copy(arr);
arr2.push('james');
console.log(arr2);
console.log(arr);

输出结果:

通过创建新的数组(开辟新的数组空间),然后用for in循环,给他传入arr中所有的值。

②浅拷贝对象

var userMsg = {  
    nick: {  
        name: 'nick',  
        age: 18,  
        sex: '男'      
    },  
    freddy: {  
        name: 'freddy',  
        age: 24,  
        sex: '男'  
    }     
};  

function copy(obj){
	var newObj = {};
	for(var i in obj){
		newObj[i] = obj[i];
	}
	return newObj;
}

var userMsg2 = copy(userMsg);
userMsg2.mike = {   //userMsg2下新添加一个mike对象
	name: 'mike',  
    age: 24,  
    sex: '男'
};
console.log(userMsg2);
console.log(userMsg);

userMsg2.nick.sex = '女';
console.log(userMsg2.nick.sex);
console.log(userMsg.nick.sex);

输出结果:


①浅拷贝后,给userMsg2下新添了一个mike对象,然后分别输出userMsg2userMsg,然后发现浅拷贝发挥了功效,userMsg2新添的mike对象不会影响userMsg。

②但是当我们修改userMsg2下的nick对象的sex值,然后分别输出userMsg2,userMsg下nick对象的sex值,发现两个的sex的值都被修改了。这就是浅拷贝的不足之处了,userMsg下的nick,freddy对象的虽然被拷贝过去了,当是他们的仍然使用同一个nick,freddy对象内存(空间)。

三、深拷贝

var userMsg = {  
    nick: {  
        name: 'nick',  
        age: 18,  
        sex: '男'      
    },  
    freddy: {  
        name: 'freddy',  
        age: 24,  
        sex: '男'  
    }     
};  

function deepCopy(obj){
	if(typeof obj != 'object'|| obj==null){   
		return obj;	 //如果传入obj不是object或者为null就退出递归,
	}
	var newObj = {};
	for(var i in obj){
		//arguments.callee 的作用是指向正在执行的函数的指针(也就是deepCopy函数本身)
		newObj[i] = arguments.callee(obj[i]);  //进行递归操作
	}
	return newObj;
}

var userMsg2 = deepCopy(userMsg);
userMsg2.mike = {   //userMsg2下新添加一个mike对象
	name: 'mike',  
    age: 24,  
    sex: '男'
};
console.log(userMsg2);
console.log(userMsg);

userMsg2.nick.sex = '女';
console.log(userMsg2.nick.sex);
console.log(userMsg.nick.sex);

输出结果:

这时,就把userMsg下的nick,freddy对象的也拷贝了一次,分别给它们创建了新的"空间"。这时就不存在对象引用带来的影响。

猜你喜欢

转载自blog.csdn.net/w390058785/article/details/80599025