亲宝软件园·资讯

展开

JS深拷贝与浅拷贝

YinJie… 人气:0

一、JS中数据的存储形式-堆栈

我们先简单理解一下堆栈分别是啥:

什么是栈:计算机为原始类型开辟的一块内存空间 string number ...

什么是堆:计算机为引用类型开辟的一块内存空间 object

我们分别分析下面两段代码:

var a = 'jack'
var b = a
b = 'andy'
console.log(a,b);//jack andy
var c = {key : 1}
var d = c
d.key = 2
console.log(c,d);//{ key: 2 } { key: 2 }

看完之后我们可能有这么一个疑问,第一段代码很好理解,但是第二段代码里改变的明明是d中的key,为啥c里的key也改变了呢?

这里就是因为堆跟栈的原理,我们在定义原始类型数据的时候都会开辟一个栈的空间,当声明一个基本变量时,它就会被存储到栈内存中,而当其发生复制时,会把对应内存中的数据复制一份到新内存中,所以这两个变量之间没有什么联系。如果我们对引用类型进行复制,我们只是将地址复制了一遍,原变量和复制的新变量都是指向同一个地址,这就说明对新变量进行修改时就会影响到原变量的值。

二、深浅拷贝的三种方式

深拷贝与浅拷贝,简单点来说:

就是假设B赋值了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝。如果B没变,那就是深拷贝。

遍历赋值

下面我们看一段代码:

var obj = {
  a:'hello',
  b:{
    a:'world',
    b:111
  },
  c:[11,'jack','abdy']
}
function clone(obj) {
  var objnew = {}
  for(var i in obj) {
    objnew[i] = obj[i]
  }
  return objnew
}
var objcopy = clone(obj)
console.log(obj);
console.log(objcopy);

在这里我们定义了一个对象 obj,为了实现能够复制出另一个对象,我们再定义一个clone方法。然后调用这个方法,输出原来的对象和复制后的对象,看看是否相同:

在控制台下输出的两个结果没有任何差异,那他们两个是否真的完全一样呢?

他们两个是有不同的,因为这里的拷贝属于浅拷贝,我们根据浅拷贝的定义,如果在上例中,我们改变了objcopy,那么obj也发生了变化的话那他就是一个浅拷贝。

我们下面来验证一下,改变一下objcopy.b.a的值,看看 obj 里会不会发生相应的变化:

将objcopy.b.a赋值为字符串hhhh后,obj.b.a也变为了hhhh,这就说明我们最开始的拷贝属于浅拷贝。因为obj.b他是一个引用类型,所以objcopy.b和obj.b指向的都是同一个地址,这样不管objcopy.b.a改成什么,obj.b.a都会变成什么。

Object.create()

这种方法只需要行代码:

var objcopy = Object.create(obj)

obj在复制的时候,它会被当前对象复制到原型__proto__上,并不是复制到当前的对象上。我们再次改变一下objcopy.b.a的值,看看 obj 里会不会发生相应的变化:

所以他也是浅拷贝

遍历赋值实现深拷贝

这是深拷贝的克隆函数:

function deepclone(startobj,endobj) {
  var obj = endobj || {}
  for(var i in startobj)
  {
    if(typeof startobj[i] === 'object') {
      obj[i] = startobj[i].constructor === Array ? [] : {}
      deepclone(startobj[i],obj[i])
    }else {
      obj[i] = startobj[i]
    }
  }
  return obj
}

值得注意的一点是,在递归调用的时候,需要把当前处理的 obj[i] 给传回去,否则的话 每次递归obj都会被赋值为空对象,就会对已经克隆好的数据产生影响。

我们来验证一下是否是深拷贝:

var objcopy = deepclone(obj)
objcopy.b.a = 'hhhh'
console.log(obj);
console.log(objcopy);

运行结果:

这就说明我们的深拷贝已经实现了。

通过JSON.parse()和JSON.stringify()实现深拷贝

这是我们在工作中最常见的一种方式

var objcopy = JSON.parse(JSON.stringify(obj))

我们对初始化的对象先通过JSON.stringify转换为字符串,再通过JSON.parse转回对象类型。

这样为什么能实现深拷贝的效果呢?因为我们通过 JSON.stringify 转成 string 类型后,他就存储在栈里,这样就不会出现地址值上的误会了,再通过JSON.parse就可以再转换为object类型。

加载全部内容

相关教程
猜你喜欢
用户评论