当前位置: 首页 > Web前端 > HTML5

数据类型与深拷贝

时间:2023-04-05 20:36:08 HTML5

前言为什么要在第一篇写这个?不要问我为什么,我只能说很简单。总不能一上来就介绍垃圾回收,图形渲染,各种风骚的操作吧。哈哈哈,话不多说,直接进入正题。数据类型JS分为两种数据类型,基本数据类型:Number,String,Boolean,Null,Undefined,Symbol(ES6)引用数据类型:Object(Date,Function,Array,RegExp)基本数据类型:vara=10;varb=a;b=20;console.log(a);//10值console.log(b);//20值贴一张图来解释这段代码在内存中的执行过程从上图很容易看出栈内存中存放的是基本数据类型,变量声明的本质是打开在栈中建立一个新的内存空间,变量赋值将相应的值填充到这个空间中。引用数据类型:varobj1={age:24,name:"Mynameisobj1"};varobj2=obj1;obj2.name="我叫obj2";控制台日志(obj1.name);//我叫obj2贴一张图说明这段代码在内存执行过程中的引用数据类型,存放在堆内存中,在栈中存放一个指向堆内存的地址,引用数据的赋值type其实就是引用地址的传递,而修改对象的属性就是在栈内存中获取指向堆内存的地址,然后在堆内存中寻址对象后修改属性。在这段代码中,虽然obj2赋值了name属性,但是发现obj1.name也输出了'mynameisobj2',这说明obj1和obj2共享同一个堆内存,所以我们要给obj2单独弄一个什么关于名字?别着急,下面会涉及到深拷贝和浅拷贝的知识点。首先要明确一点,讲基本数据类型的深拷贝和浅拷贝是没有意义的,所以下面的深拷贝和浅拷贝都是基于引用类型来讨论的。浅拷贝函数shallowCopy(obj){varnewObj=Array.isArray(obj)?[]:{};for(letiinobj){newObj[i]=obj[i];}returnnewObj;}varobj1={age:24,name:"Mynameisobj1"};varobj2=shallowCopy(obj1);obj2.name="Mynameisobj2";console.log(obj1.name);//我的名字是obj1console.log(obj2.name);//我的名字是obj2。这样ob2也有了自己的名字。每个人都有自己的名字,互不干涉。为什么这是可能的?结合上面提到的知识点,相信大家可以理解其中的原理。接下来看下面这段代码:varobj1={age:24,name:"我叫obj1",friend:{name:'我是obj1的朋友',age:18}};varobj2=shallowCopy(obj1);obj2.friend.name="我是obj2的朋友";console.log(obj1.friend.name);//我是obj2的朋友console.log(obj2.friend.name);//我是obj2的朋友,问题来了,如果你在obj2中修改了你朋友的名字,为什么会影响到我在obj1中的朋友呢?显然我们已经做了一个浅拷贝。这是因为浅拷贝只复制了对象的一级属性。如果对象有二级和三级数据,则不能复制后面的数据。理论上,它们是共享堆内存的,那么如何将它们复制到多层属性中呢?接下来说一下深拷贝。深度复制函数deepCopy(obj){constnewObj=objinstanceofArray?[]:{};for(letkeyinobj){if(obj.hasOwnProperty(key)){newObj[key]=typeofobj[key]==='object'?deepCopy(obj[key]):obj[key];}}returnnewObj;}varobj1={age:24,name:"Mynameisobj1",friend:{name:'Iamobj1friend',age:18}};varobj2=deepCopy(obj1);obj2.friend.name="我是obj2的朋友";console.log(obj1.friend.name);//我是obj1的朋友console.log(obj2.friend.name);//我是obj2的朋友这里我们使用递归开辟新的内存空间,复制每一层的属性,保证每一层的引用对象在堆内存中都是一个新的对象,实现了深拷贝目的。总结数据类型和浅拷贝是我们日常开发中最常见的知识点。通过这篇文章,我们了解了JS数据类型以及这两种数据类型在内存存储上的区别,并通过深拷贝和浅拷贝的方式解决了引用数据。类型堆内存共享的问题。更多知识交流,可以关注公众号:前端编程之路,一起学习。