最近做项目时候,需要用到对象的深拷贝,图省事就直接上了JSON.parse(JSON.string(obj)),简单粗暴!!挺好用,但悲剧发生了,我的对象中有一个函数,然后这个方法就挂掉了,没法拷贝函数,只好就换了jq的$.extend()方法进行深拷贝。关于深拷贝、浅拷贝的问题,碰见过好多次,懒癌晚期的我每次都是临时抱佛脚,现查现用,终于今天再也忍不了了,系统整理下,做个记录
首先我们先了解一些javascript的基本知识
基本类型的值一共有6种:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、Symbol(es6中新增)
阴影类型值指那些可能由多个值构成的对象 只有一种:object
在将一个值付给变量时,解析器必须确定这个值是基本类型值还是引用类型值。基本数据类型是按照值访问的,因此可以操作保存在变量中的实际值。而引用类型的值是保存在内存中的独享。JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象是,实际上是在操作对象的引用而不是实际的对象
栈:自动分配内存空间,系统自动释放,里面存放的是基本类型的值和引用类型的地址
堆:动态分配内存,大小不定,也不会自动释放。里面存放引用类型的值
值传递:基本类型采用的是值传递。
var a=1; var c=1; var b=a; b++; console.log(a)//1 console.log(b)//2 a===c //true址传递:引用类型是地址传递,存放在栈内存的地址赋值给接受的变量。
var a=[1,2,3]; var c=[1,2,3,0]; var b=a; b.push(0); console.log(a)//[1,2,3,0] console.log(b)//[1,2,3,0] a===b//true a===c//false 内存地址不同由于a和b都是引用类型,采用的是址传递,即a将地址传递给b,那么a和b必然指向同一个地址(引用类型的地址存放在栈内存中),而这个地址都指向了堆内存中引用类型的值。当b改变了这个值的同时,因为a的地址也指向了这个值,故a的值也跟着变化。
1、jq的$.extend(true,obj1,obj2)第一个参数设置为true即可完成深度复制
2、JSON.parse(JSON.string(obj)) 此种方法复制对象 中 不能含有函数(貌似还有其他问题),
4、es6中的Object.assign({},obj) 此种方法只适用于根属性值都为基本类型的对象,局限性也很大(和Array.from()类似)
3、js递归实现
function deepCopy(p,c){ var i; c = c||{}; for(i in p){ if(p.hasOwnProperty(i)){ if(typeof(p[i])==="object"){ c[i] = Array.isArray(p[i])?[]:{}; deepCopy(p[i],c[i]); }else{ c[i] = p[i]; } } } return c; }
