值传递和引用传递和内存分析

目录

1.栈和堆

1.1栈结构及其相关存储属性

1.2堆结构及其相关属性

1.3图解栈和堆

2.拷贝

深拷贝


引言:我们在学习js过程中,也很想知道各种类型变量在内存中时如何存储的,今天我们讲学习这系列内容。

1.栈和堆

我们首先必须了解栈和堆两大概念,各种类型的变量就存储在这两者中

1.1栈结构及其相关存储属性

栈结构这里就不细讲了,详细大家之前学习中肯定了解栈结构的性质

在内存存储中,栈区中每一层叫做栈帧都占用栈本身有容量限制,超过限制为栈溢出

其中基本变量类型和数组地址值,对象的唯一访问地址值都存储在栈中

1.2堆结构及其相关属性

堆结构可以存储内存上连续的空间(数组),或者不连续的内存空间(对象)

1.3图解栈和堆

对于数组或者对象来说,堆内存中存储真实数据,然后地址值存储在栈中,需要访问他们时,只需要从栈中拿到地址值,然后拿着钥匙(地址值)去堆内存中拿数据

对于基本变量来说,就直接将真实数据存储到栈中

在实际开发中,这种存储方式也带来许多问题,下面来看一个案例:

var  a= [1,2,3,4]
var b=1
var xx1=b
var x=a
console.log(xx1,x);//1,[1,2,3,4]
//当我们修改x的第一个值,然后打印原数组
var  a= [1,2,3,4]
var b=1
var xx1=b
var x=a
console.log(xx1,x);//1,[1,2,3,4]
x[0]=9
console.log(a);//[9,2,3,4]

可以得到当操作xx1时,也会影响到,所以xx1和a在堆中指同一内存空间

但如果给xx1设置新的[1,2,3,4],及直接在xx1直接定义,两者将不会关联同一数组

将a=null时

只是将栈中的引用地址去掉,但是 堆内存中真实数据还会存在堆中,浏览器js引擎被垃圾回收地址收掉用来释放浏览器的运行内存

2.拷贝

什么是拷贝,我想从引用传递和拷贝的区别进行入手讲解:
先看下面代码

//引用传递
var arr=[1,2,3,4]
var arr1=arr
//拷贝
let arr2=[]
for(let i=0;i<arr.length;i++){
    arr2.push(i)
}
//改变arr2
arr2[0]=3
console.log(arr2,arr);//arr[0]还是为0

引用传递和拷贝的区别:

引用传递两个数组访问的是堆内存中同一内存空间,而拷贝是在堆内存中重新申请一段内存,比如在案例中arr2和arr在堆中是两端不同的内存空间

正式介绍一下拷贝的概念,比如说数组拷贝相当于在内存中开辟一个新的内存空间,并且将原数组的所有内容风别按照下标复制一封放到新的数组,这样内存中会出现一个一样的数组,但是存储在不同的位置他们相互之间没有关系

但是这种方式为浅拷贝

深拷贝

 我们来通过浅拷贝和深拷贝的区别来认识深拷贝

先来看一个浅拷贝:

var arr=[{name:"a",age:17},{name:'s',age:18}]
var arr1=[]
for(let i=0;i<arr.length;i++){
    arr1.push(i)
}
arr1[0].name='uuu'
console.log(arr,arr1);//arr的第一个对象中的name属性也为uuu
arr1.push(123)
log(arr,arr1)//只有arr1有123

观察结果来看,我们的拷贝还是浅拷贝,在内部赋值时还是会出现引用传递,也也就是出现影响原数组的问题,所以浅拷贝不能将对象的所有属性都进行复制,要想办法实现深拷贝

1.利用JSON.parse和JSON.stringify实现深拷贝

var arr=[{name:"a",age:17},{name:'s',age:18,},address:undefined]
var arr1=[]
for(let i=0;i<arr.length;i++){
    arr1.push(i)
}
arr1[0].name='uuu'
console.log(arr,arr1);//arr的第一个对象中的name属性也为uuu
//先将arr转为字符串
var str=JSON.stringify(arr)
//然后将字符串转为一个反序列化一个新数组
var arr3=JSON.parse(str)
//此时验证一下,当修改arr3第一个对象的name属性时,原arr中对应的属性值会不会受到影响
arr3[0].name='iii'
console.log(arr,arr3);//没影响,arr中name属性还是原来的值

这就是一个深拷贝,我们观察结果,arr中的name属性并没有受到影响,所以代表时成功的

但是这个方法也有缺点,当我们原数组对象中包含函数或者带有原型链的对象 时,会导致数据丢失,比如说我们在原数组上添加一个函数,但是通过一系列操作后,会发现str和arr3都没有这个函数,

缺点二:观察结果,address这个属性不能被复制,即不能有undefined

第二种深拷贝的方式

var myobj={
    name:'kerwin',
    arr:[1,2,3]
}
var myobj2={
    ...myobj
}
myobj2.name="xiaoming"
myobj2.arr.splice(1,1)
console.log(myobj);//通过控制台打印我们发现

通过控制台的打印,我们发现,此时myobj被影响到,此种拷贝方式其实只比拷贝多拷贝一层

在实际开发中我们都借助第三方库来实现(递归思想):比如说Immtable.js

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值