js中的深浅拷贝

·  阅读 233

学习深浅拷贝先学习数据类型

u=1709644436,2739756540&fm=26&gp=0.jpg

js中的数据类型

一般来说我们分为基本数据类型(原始类型)和引用类型(复杂类型)。

  • 原始类型:在存储时变量中存储的是值本身,包括string ,number,boolean,undefined,null
  • 复杂类型:在存储时变量中存储的仅仅是地址(引用),通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等;

总结(简单说):原始类型存值在栈中,引用类型存值在堆中,引用类型在栈中存的是地址。(堆栈不明白的去百度一下吧)

1.我们先来代码:

var a =123
var obj ={}

var person={
    name:'爱学习',
    hobby:['学习',['看电影','shopping'],'跑步']
}

var person1=person
person1.name='爱打球',
person.name='zjx'
person1.hobby[0]='挨打有i'
console.log(person);
console.log(person1);
//输出结果
{ name: 'zjx', hobby: [ '挨打有i', [ '看电影', 'shopping' ], '跑步' ] }
{ name: 'zjx', hobby: [ '挨打有i', [ '看电影', 'shopping' ], '跑步' ] }
复制代码

xdm!!看这段代码你们觉得是什么拷贝呢?其实这既不是深拷贝也不是浅拷贝,这只是简单的赋值。把一个对象赋值给了另一个对象,但是两个对象指向的都是同一个地址,所以对person或者person1进行操作。都是改变地址的数据。

赋值:当一个对象被赋给一个新的变量时,赋的其实是该对象在栈中的地址,而不是堆中的数据,也就是两个对象指的是同一个存储空间, 所以当无论哪个对象发生变化,都是栈中的地址指向的堆中的数据发生改变.

2.再来看看浅拷贝。(就是说对所需要的进行简单的拷贝:拷贝引用类型数据一旦改变,拷贝前和拷贝后的数据都会发生变化。而简单类型却不会。) 贴代码:

//- 浅拷贝
var person = {
    name: '爱学习',
    hobby: ['学习', ['看电影', 'shopping'], '跑步']
}


function shallowCopy(obj) {
    var target = {}
    for (var key in obj) {
        //只要是原型上有的属性都要被挂载到target对象上
        if (obj.hasOwnProperty(key)) {
            target[key] = obj[key]
        }
    }
    return target
}
var person1 = shallowCopy(person)
person1.name = '小刘'
person1.hobby[0] = '玩水' 
//如果对拷贝后的person1操作输出{ name: '小刘', hobby: [ '玩水', [ '看电影', 'shopping' ], '跑步' ] }
//person输出{ name: '爱学习', hobby: [ '玩水', [ '看电影', 'shopping' ], '跑步' ] }

person.hobby[0] = '好好'
//如果对拷贝后的person操作输出:{ name: '爱学习', hobby: [ '好好', [ '看电影', 'shopping' ], '跑步' ] }
//person输出{ name: '小刘', hobby: [ '好好', [ '看电影', 'shopping' ], '跑步' ] }
看原始类型浅拷贝后无论怎么变都不会互相影响。但复杂数据类型无论是改变前还是改变后再去改变值都会一起改变
// person.name='kk'
console.log(person);
console.log(person1);
复制代码

浅拷贝总结:浅拷贝后会重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后引用类型会共享堆中的内存,引用类型就会互相影响

最后看看深拷贝:(拷贝前后的数据都不会互相影响) 贴代码:(利用递归的方法实现的,有很多方法都可以实现,下篇文章我会总结一下实现的方法)

var person = {
    name: '爱学习',
    hobby: ['学习', ['看电影', 'shopping'], '跑步']
}

function deepCope(obj){
    // var cloneObj= {} //或者
    var cloneObj=new obj.constructor()
    if(obj === null) return obj
    if(obj instanceof Date)  return new Date()   //a.instanceof(b)  意思是b的prototype是否载a的原型链上
    if(obj instanceof RegExp)  return new RegExp()   //a.instanceof(b)  意思是b的prototype是否载a的原型链上
    if(typeof obj !=='object') return obj
    for (let key in obj){
        if(obj.hasOwnproperty(key)){
            cloneObj[key]= deepCope(obj[key])
        }
    }
    return cloneObj
}
var person1 = shallowCopy(person)
person1.name = '小刘'
person1.hobby[0] = '玩水'
console.log(person);
console.log(person1);

//{ name: '爱学习', hobby: [ '学习', [ '看电影', 'shopping' ], '跑步' ] }
{ name: '小刘', hobby: [ '玩水', [ '看电影', 'shopping' ], '跑步' ] }

//第二种方式
var person2 = Json.parse(Json.stringify(person))  //这种方式深拷贝函数不拷贝
复制代码

上面的递归就是只要对象里面有属性或者说对象里面的属性还有对象对象里面还有属性,就是用递归的方法把一个个引用类型抓换成原始类型。 解释一下这段话:说的很模糊:例如

var person = {
    name: '爱学习',
    love:{
    name:'hau',
    age:'14'
    }
}
复制代码

就是递归把对象里面的对象拿出来,变成了基本类型。也就是意味着变成了基本类型后,无论改变拷贝前的对象还是拷贝后的他们都不互不影响。

总结- 深拷贝:从堆内存中开辟一个新的区域存放对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不印象

浅显的拿一层属性来说

js的拷贝和原数据是否指向同一对象
赋值
浅拷贝
深拷贝
最外面的属性类型为简单类型最外面为复杂类型
改变会让原数据一起改变改变会让原数据一起改变
改变不会让原数据一起改变改变会让原数据一起改变
改变不会让原数据一起改变改变不会让原数据一起改变
分类:
前端
标签: