JS中的堆栈
堆和栈都是运行时内存分配的一个数据区
堆(heap)
堆(heap)用于复杂数据类型(引用类型)分配空间,例如数组对象、object对象;
它是运行时动态分配内存的,因此存取速度较慢
栈(stack)
栈(stack)中主要存放一些基本类型的变量和对象的引用,(包含池,池存放常量),
其优势是存取速度比堆要快,并且栈内的数据可以共享,但缺点是存在栈中的数据大小
与生存期必须是确定的,缺乏灵活性
JavaScript的数据类型有哪些?
1.值类型(基本类型):string,number,boolean,undefined,null(这5种基本类型是按值访问的)es6新增了symbol
2.引用类型:Object(JS中除了基本类型以为都是对象,数组,函数,正则表达式)
基本数据类型存放在栈中
基本数据类型是指存放在栈中的简单数据段,数据大小确定,内存空间大小可以分配,它们是直接按值存放的,所以可以直接按值访问
let a = 1;
let b = a;
b = 2;
console.log(a,b) //1,2
引用数据类型
存放在堆内存中的对象,每个空间大小不一样,要根据情况进行特定的配置
引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。
通过这个引用地址可以快速查找到保存中堆内存中的对象
let obj1 = {
name:'lyl'
}
let obj2 = obj1;
obj2.name = "yr";
console.log(obj1.name); // yr
这说明obj1和obj2指向了用一个堆内存,obj1赋值给obj2,实际上这个堆内存对象在栈内存的引用地址复制了一份给了obj2,所以obj1和obj2指针都指向堆内存中同一个。
var a = [1,2,3,4];
var b = a;//传址 ,对象中传给变量的数据是引用类型的,会存储在堆中;
var c = a[0];
//传值,把对象中的属性/数组中的数组项赋值给变量,
这时变量C是基本数据类型,存储在栈内存中;改变栈中的数据不会影响堆中的数据
alert(b);//1,2,3,4
alert(c);//1
//改变数值
b[2] = 6;
c = 7;
alert(a[2]);//6
alert(a[0]);//1
从上面我们可以得知,当我改变b中的数据时,a中数据也发生了变化;但是当我改变c的数据值时,a却没有发生改变。
这就是传值与传址的区别。因为a是数组,属于引用类型,所以它赋予给b的时候
传的是栈中的地址(相当于新建了一个不同名“指针”),而不是堆内存中的对象。
而c仅仅是从a堆内存中获取的一个数据值,并保存在栈中。所以b修改的时候,
会根据地址回到a堆中修改,c则直接在栈中修改,并且不能指向a堆内存中。
浅拷贝
在定义一个对象或数组时,变量存放的只是一个地址,当使用对象拷贝时,如果属性是对象或者数组,我们传递的也知识一个地址,因此子对象在访问该属性时,会根据地址找到父对象指向的堆内存,父子对象是共享的。
var a={key1:"1"}
function Copy(p){
var c ={};
for (var i in p){
c[i]=p[i]
}
return c;
}
a.key2 = ["yr","lyl"]
var b = Copy(a);
b.key3 = "3"
alert(b.key1)//1
alert(b.key3)//3
alert(a.key3);//undefined
b.key2.push("xn")
alert(a.key2);//yr lyl xn
修改的属性变为对象或数组时,那么父子对象之间就发生关联
es6实现浅拷贝
var a = {name:"yr",eating:[
{
name:'螺蛳粉'
}, {
name:'酸辣粉'
}
]}
var b = Object.assign({},a);
//var b = {...a}
b.age = 18;
b.eating.push({
name:'过桥米线'
})
console.log(a.age,a.eating);//undefined 螺蛳粉 酸辣粉 过桥米线
以上Object.assign和... 进行拷贝时,对象中属性的值是数组或对象,都是拷贝地址,如果对象中所有属性对应的都是基本数据类型,就是拷贝值
深拷贝
不希望父子对象之间产生关联,那么这时候可以用到深拷贝,属性值类型是数组和或象时只会传址,就用递归来解决
function inCopy(obj1,obj2) {
var obj1 = obj1 || {};//容错处理
for (var k in obj2) {
if(obj2.hasOwnProperty(k)){ //只拷贝实例属性,不进行原型的拷贝(忽略继承的属性)
if(typeof obj2[k] === 'object') { //引用类型的数据单独处理
obj1[k] = Array.isArray(obj2[k])?[]:{};
inCopy(obj1[k],obj2[k]); //递归处理引用类型数据
}else{
obj1[k] = obj2[k]; //值类型的数据直接进行拷贝
}
}
}
}
let obj2 = {
name:'yr',
like:['海鲜','烧烤']
}
let obj1 = {age:18};
inCopy(obj1,obj2)
obj1.like.push('糖葫芦')
console.log(obj1,obj2)
整理了一些书籍分享给大家,可关注公众号菜单栏点击推荐书籍获取链接
JavaScript高级程序设计(红宝书) 你不知道的JavaScript(上卷) 你不知道的JavaScript(中卷) 你不知道的JavaScript(下卷).pdf
js权威指南.pdf 深入理解ES6.pdf es6标准入门(第三版).pdf HTML与CSS入门经典 Javascript高级程序设计
JavaScript设计模式 性能网站建设进阶指南 精通正则表达式 HTML5程序设计 CSS权威指南 JavaScript权威指南
JavaScript面向对象编程指南 HTTP权威指南.pdf 计算的本质:深入剖析程序和计算机.pdf