JavaScript-DOM节点操作深拷贝浅拷贝递归

本文介绍了JavaScript中的基本数据类型和引用数据类型的区别,重点讲解了深拷贝和浅拷贝的概念,特别是通过递归函数实现深拷贝的方法。讨论了如何通过constructor属性和typeof运算符判断数据类型,并提供了深拷贝的封装示例代码,强调了深拷贝在处理对象层级属性时的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本数据类型和引用数据类型

基本数据类型:number,String,Boolean,null,undefined
引用数据类型:object,array,function

基本数据类型和引用数据类型的区别

1:值是否可变
.基本类型的值是不可变得:
.引用类型的值是可变的

2:数据的比较
.基本类型的比较是值的比较—只有在它们的值相等的时候它们才相等
如果他们的类型不相等;在进行比较的过程中;== 就进项了数据类型的转化。转化为相等的类型;在进行值的比较;也就是为什么==只比较值;不比较类型的原因;===比较类型和值、
引用类型的比较是引用的比较。比较是在堆中的数据,也就是说;即使是两个一样的对象。返回也是false ;是因为在堆中地址不同。

3:在内存中储蓄不同
基本类型的变量是存放在栈区的(栈区指内存里的栈内存),栈区包括了 变量的标识符和变量的值。
引用类型的值是同时保存在栈内存和堆内存中的对象

4:赋值时候区别
在从一个变量向另一个变量赋值基本类型时,会在该变量上创建一个新值,然后再把该值复制到为新变量分配的位置上:
这两个变量可以参加任何操作而相互不受影响。

a中保存的值为 10 ,当使用 a 来初始化 b 时,b 中保存的值也为10,但b中的10与a中的是完全独立的,该值只是a中的值的一个副本,此后
在这里插入图片描述

对象的引用

当从一个变量向另一个变量赋值引用类型的值时,同样也会将存储在变量中的对象的值复制一份放到为新变量分配的空间中。前面讲引用类型的时候提到,保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。那么赋值操作后,

两个变量都保存了同一个对象地址,则这两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响:

例:

<script>
      //基本类型
      var a = 'zhang';
      var arr = [1,2,3,4];
      arr.push(3)
      //数据比较
      var bool= true;
      console.log(a == bool);
      //赋值
      /*var a = 1;
      var b = a;
      b = 10;*/
      var a = {};//a保存了一个空对象的实例
      var b = a;//a和b都指向了这个空对象
      a.name = '张';
      console.log(b.name);
      b.age = 22;
      console.log(a);
      console.log(a==b);//true
      
    </script>

他们的关系图:
在这里插入图片描述
总结:引用类型的赋值其实是对象保存在栈区地址指针的赋值,因此两个变量指向同一个对象,任何的操作都会相互影响。

数据类型的判断总结

typeof 判断一个变量的数据类型,返回一个字符串
typeof一般用来判断值类型(数字型字面量,字符串的字面量,布尔字面量)
注意:使用typeof判断数据类型时,发现对象,数组, null无法区分准确的类型
instanceof 关键字判断数据类型时,可以区分对象,数组, null的类型。
instanceof一般用来判断引用类型(new Number(), new String(), {},new Object(), new Array(), [], function等。
instance实例, 直译:判断arr变量是否是Array对象的实例。如果是返回true,否则返回false。

实例注意:
console.log([] instanceof Object); // true原因:继承关系Array继承Object
console.log(false instanceof Boolean); // false原因:字面量的布尔值是值类型。
console.log(new Boolean() instanceof Boolean); // true原因:对象是引用类型。

constructor 属性返回对创建此对象的数组函数的引用。
constructor判断对象的类型,会比typeof更精确,constructor能获取一些复杂对象的类型,typeof做不到。
constructor.name 返回该数据的数据类型的字符串名字

例:

<script>
      var a = 34;
      var b = 'zhang';
      var c = true;
      var arr = [];
      var obj = {};
      //以下输出结果均为false
      /*console.log(a == b);
      console.log(a == c);
      console.log(a == arr);
      console.log(a == obj);*/
      
      //以下输出数据的类型
      /*console.log(typeof a);
      console.log(typeof b);
      console.log(typeof c);
      console.log(typeof arr,'数组'); 
      console.log(typeof obj,'对象');
      console.log(typeof null);*/
      
      //instanceof 返回 true,因为数组继承了Object
      console.log([] instanceof Object);
      //false,子变量的布尔值是数值类型
      console.log(false instanceof Boolean);
      //true,对象是引用类型的。
      console.log(new Boolean() instanceof Boolean);
      //均返回true:因为e既是一个数组也是Object类型的。
      var e = [1,2,3,4];
      console.log(e instanceof Array);
      console.log(e instanceof Object);
      
      //constructor 返回一个方法;
      console.log([].constructor.name,'比价方式');//Array
      console.log({}.constructor.name);//Object
    </script>

外延知识 数据在内存中是怎么存在的

存放引用类型数据的值。为在栈内存中属性中;提供一个堆内存的地址

1:基本数据类型;在栈中 var a = 1
在这里插入图片描述
当你b=a复制时,栈内存会新开辟一个内存,例如这样:
在这里插入图片描述
因此当改变a的值时候;b 的值就不会被改变。遍实现了深拷贝。
总结基本数据类型的拷贝;可以实现深拷贝

2:引用数据类型的:名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,
例如a 的数据为引用类型的
在这里插入图片描述
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。所以当a改变时候;堆内存中也发生了改变
在这里插入图片描述
堆内存中也开辟一个新的内存专门为b存放值,就可以实现深拷贝了
在这里插入图片描述
注意:深拷贝,是拷贝对象各个层级的属性
函数封装;见课件代码

总结:数据类型可以直接实现深拷贝;浅拷贝会出现在对象和数组中。引用的数据类型实现深拷贝我们可以通过封装方法的方式

什么是深拷贝和浅拷贝

深拷贝:

指的是抄袭者,当抄袭者的数据改变时不会改变被抄袭者中的内容同时当被抄袭者中数据发生改变时也不会影响抄袭者的数据,此时说明抄袭者可以自食其力。这是由于数据在中内存中存储形式造成的。栈和堆的形式储存。

浅拷贝:

拷贝后,抄袭者和被抄袭者互相影响。当被拷贝者数据发生改变,拷贝者数据也会发生改变。
例:

<script>
      //拷贝:赋值数据值
      /*深拷贝*/
      var a = 20;
      var b = a;
      console.log(a,b);
      b = 30;
      a = 40;
      console.log(a,b);
      
      /*浅拷贝 */
      var obj = {};
      var c = obj;//拷贝的obj在堆中的指针,而不是真正的值。
      console.log(obj,c);
      obj.name = 'zzz';
      console.log(obj,c);
      c.age = 18;
      console.log(obj,c);
    </script>

递归函数

阶乘的规律;n = n*(n-1)的阶乘
递归:反复循环执行一个函数;最后实出入一个结果,可以为return ;就是反复执行一个函数。知道输出一个结果
弊端:函数调用;得等函数返回一个结果;才自行完毕
优点:就是代码简单了

写递归需要注意:
1:找到实现改结果的规律
2找到停止递归的出口;不然会出现是循环现象
例:

<script>
      /*递归
       * n! = n(n-1)!
       * 递归函数:是函数中的循环,通过反复调用自身的方法,来返回一个
       * 优点:代码简单,更符合人的思想,不符合运算逻辑
       * 缺点:运算量大,最先执行的程序,左右输出结果。
       */
      /*var n = 5;
      var a = 1;
      for (var i = 1; i <n; i++){
        var a = a*i;
        console.log(a);
      }*/
      //实现阶乘
      /*function argu(n) {
        if(n < 0 ){
          return -1;
        }else if (n == 0 || n ==1){
          return 1;
        }else{
          return (n*argu(n-1));
        }
      }
      console.log(argu(6));*/
      //实现阶加
      function argu(n) {
        if(n < 0 ){
          return -1;
        }else if (n == 0 || n ==1){
          return 1;
        }else{
          return (n+argu(n-1));
        }
      }
      console.log(argu(5));
    </script>

递归实现复杂深拷贝封装方法

例:

<script>
      /*方法作用:实现多层复杂的数据类型的深拷贝
       */
      var data = [
        {
          'list':[
            {
              name:'yq',
              age:18
            },
            {
              name:'ad',
              age:3
            },
            {
              name:'zz',
              age:28
            }
          ]
        },
        {
          
        }
      ]
      //封装递归深拷贝方法
      function deepCopt(data){
        if (data.constructor.name === 'Array') {//为数组
          var arrCopy = [];
          for (var i = 0, len=data.length;i<len;i++) {
            
            if (data[i] instanceof Object) {
              arrCopy.push(data[i]);
            } else{//基本类型
              arrCopy.push(data[i]);
            }
          }
          return arrCopy;
        } else{//为对象
          var objCopy = {};
          for(x in data){
            if(data[x] instanceof Object){
              objCopy[x] = deepCopt(data[x]);
            }else{//基本类型
              objCopy[x] = data[x];
            }
          }
          return objCopy;
        }
      }
      var res = deepCopt(data);
          console.log(res);
          console.log([] instanceof Object)
          console.log({} instanceof Object)
          console.log(null instanceof Object)
          console.log('sss' instanceof Object)
          console.log(true instanceof Object)
          console.log(123 instanceof Object)
    </script>

引用类型的深拷贝

例:

<script>
      var a = [1,2,3,4,5];
      var b = [];
      for(var i = 0; i <a.length;i++) {
        b.push(a[i]);
      }
      console.log(a);
      console.log(b);
      //验证重新赋值后原数组发生的变化。
      a[0] = 999;
      console.log(a);
      console.log(b);
      
      var obj ={
        name:'zhang'
      }
      //在堆内存中已经为obj2开辟了一个新通道,因而给在栈中的变量标识为obj2提供了新的堆地址,这个地址与栈中的obj地址不是同一个
      var obj2 = {};
      for(x in obj){
        obj2[x] = obj[x];
      }
      obj.age = 3;
      console.log(obj);
      console.log(obj2);
    </script>

递归的深拷贝

外接知识点:

JS 数据类型的判断 typeOf 和 constractor
constructor判断对象的类型,会比typeof更精确,constructor能获取一些复杂对象的类型,typeof做不到。

深拷贝的方法封装和思路

注意:深拷贝,是拷贝对象各个层级的属性
第一步;先实现;单层次拷贝数组; 以及单层拷贝对象
第二步;在实现;单程拷贝数组或者对象
第三步:实现多成拷贝数组或者对象

1:确定被拷贝的的数据类型;引用类型对象或者数组,不同的数据进行不同的处理。
通过判断被拷贝的数据类型类型;不同的类型;执行不同的程序

2:如果是数组;拷贝数据;遍历呗拷贝数据,注意:数组返回结果可能是值;可能还是对象或者数据;
如果获取的数据还是对象或则数据;那么需要通过递归方式来进一步处理 对象同理,如果直接是值那就直接拷贝就可以了。

深拷贝封装方法例:
<script>
      /*深拷贝数组封装方法
       */
      function deepArr(arr){
        var arrCopy = [];
        for (var i = 0, len=arr.length;i<len;i++) {
          arrCopy.push(arr[i]);
        }
        return arrCopy;
      }
      
      /*深拷贝对象封装方法
       */
      function deepObject(obj){
        var objCopy = {};
        for(x in obj){
          objCopy[x] = arr2[x];
        }
        return objCopy;
      }
      /*深拷贝引用类型数据封装
       */
      function deepData(data){
        //判断传入的数据是否是数组
        if (data.constructor.name === 'Array') {
          var arrCopy = [];
          for (var i = 0, len=data.length;i<len;i++) {
            arrCopy.push(arr[i]);
          }
          return arrCopy;
        } else{//如果数据是对象
          var objCopy = {};
          for(x in obj){
            objCopy[x] = obj[x];
          }
          return objCopy;
        }
      }
      var obj={
        name:'zhang',
        age:22,
        dec:"hahahahha"
      }
      var res = deepData(obj);
      console.log(res);
      var arr = [1,2,3,4,5];
      var resArr = deepData(arr);
      console.log(resArr);
    </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值