天天看点

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

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

一、对象的引用

var arr = ['nick'];
var obj = {
    name: 'nick',
	hobit: ['eat']
}

var newArr = arr;
var newObj = obj;
newArr.push('freddy');  //给拷贝的数组插入队列('freddy')
newObj.name = 'freddy'; //修改拷贝的对象的name属性

console.log(arr);	//输出原数组
console.log(obj);	//输出原对象
console.log('-----分界线------');

arr = null;		//将原数组的引用指针指向null
obj = null;		//将原对象的引用指针指向null

console.log(newArr);    //输出拷贝的数组
console.log(newObj);    //输出拷贝的对象
           

运行结果:

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

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

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

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

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

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

二、浅拷贝

var arr = ['nick'];
var obj = {
    name: 'nick',
    hobit: ['eat']
}

var copy = function(obj){
    var newItem = null;
    Array.isArray(obj) ? newItem = [] : newItem = {};	
	
    for(var key in obj){
	newItem[key] = obj[key];
    }
    return newItem;
};

var newArr = copy(arr);    
newArr.push('freddy');    //给拷贝后的数组插入队列('freddy')
console.log(arr);        //输出被拷贝的数组
console.log(newArr);     //输出拷贝的数组

var newObj = copy(obj);
newObj.name = 'freddy';       //修改拷贝对象的名字
newObj.hobit.push('sleep');   //给拷贝对象下的hobit数组插入队列('sleep')
console.log(obj);             //输出被拷贝的对象
console.log(newObj);          //输出拷贝的对象
           

运行结果:

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

通过浅拷贝,我们会发现修改拷贝的数组和对象,不会再影响原数组和原对象了。但是我们往拷贝对象的hobit数组中插入队列'sleep'时,会发现原有对象中的hobit也一样有了'sleep'了,这就是浅拷贝的弊端了。

三、深拷贝

var obj = {
    name: 'nick',
    hobit: ['eat']
};

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

var newObj = deepCopy(obj);
newObj.name = 'freddy';
newObj.hobit.push('sleep');
console.log(obj);
console.log(newObj);
           

输出结果:

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

这时,原对象跟拷贝对象之前就不会互相影响,即不存在引用关系了。

继续阅读