js值类型引用类型和深浅拷贝

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

js值类型引用类型和深浅拷贝

引用数据类型

存放在堆内存中的对象,每个空间大小不一样,要根据情况进行特定的配置

引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。
通过这个引用地址可以快速查找到保存中堆内存中的对象
  let obj1 = {
      name:'lyl'
   }
  let obj2 = obj1;
  obj2.name = "yr";
  console.log(obj1.name); // yr

这说明obj1和obj2指向了用一个堆内存,obj1赋值给obj2,实际上这个堆内存对象在栈内存的引用地址复制了一份给了obj2,所以obj1和obj2指针都指向堆内存中同一个。

js值类型引用类型和深浅拷贝

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堆内存中。

js值类型引用类型和深浅拷贝

浅拷贝

在定义一个对象或数组时,变量存放的只是一个地址,当使用对象拷贝时,如果属性是对象或者数组,我们传递的也知识一个地址,因此子对象在访问该属性时,会根据地址找到父对象指向的堆内存,父子对象是共享的。

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

修改的属性变为对象或数组时,那么父子对象之间就发生关联

js值类型引用类型和深浅拷贝

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)

js值类型引用类型和深浅拷贝

js值类型引用类型和深浅拷贝

 

js值类型引用类型和深浅拷贝

整理了一些书籍分享给大家,可关注公众号菜单栏点击推荐书籍获取链接

JavaScript高级程序设计(红宝书)     你不知道的JavaScript(上卷)  你不知道的JavaScript(中卷)  你不知道的JavaScript(下卷).pdf

js权威指南.pdf    深入理解ES6.pdf    es6标准入门(第三版).pdf    HTML与CSS入门经典   Javascript高级程序设计

JavaScript设计模式    性能网站建设进阶指南   精通正则表达式   HTML5程序设计  CSS权威指南  JavaScript权威指南

JavaScript面向对象编程指南   HTTP权威指南.pdf   计算的本质:深入剖析程序和计算机.pdf

上一篇:Python——面向对象


下一篇:LeetCode刷题笔记第148题:排序链表