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

好的程序员web前端教程分享引用类型和基本类型

时间:2023-04-02 16:14:07 HTML

好的程序员web前端教程分享引用类型和基本类型,本文将从以下六个方面讲解引用类型和基本类型2.内存映射  3.引用类型和基本类型作为函数参数的区别  4。引用类型的优点:  5。引用类型的赋值(与基本类型比较)  6.浅拷贝和深拷贝  以下为详细介绍:  1。概念:  基本类型也叫简单类型,存储的数据是单一的,比如:学生的人数只是一个数字;引用类型也叫复杂类型,存储的数据比较复杂,比如:学生,包括学号、姓名、性别、年龄等诸多信息。从内存的角度看(不懂内存的可以参考相关资料):基本类型只占用一块内存;引用类型占用两个内存区域。即在定义基本类型的变量时,只在内存中申请一块空间,变量的值直接存放在这块空间中;在定义引用类型的变量时(很容易理解,我们看到new操作符,一般都是定义引用类型变量),在内存中申请两个空间,第一个空间存放第二个的地址空间,第二空间存储真实数据;第一个空间称为第二个空间的引用(Address),因此称为引用类型。  javaScript中的基本类型包括:Number(数字)、String(字符串)、Boolean(布尔)、Null、Undefined;  javascript的引用类型是:Object。而Array、Date属于Object类型。  2。内存映射:  以下代码(均定义了两个局部变量):  functiondemoFun(){  varnum=20;//定义一个基本类型的变量。  vararr=newArray(12,23,34);//定义一个引用类型的变量  }上面两行代码的内存映射:  可以看到,num变量只占用一块内存区域;arr变量占用两个内存区,arr变量在栈区申请一块内存区(对栈区不了解的不要想太多)来存储地址,存储的地址为堆区的地址。数据实际上是存放在堆区的,所以arr变量占用了两个内存区。从这个角度看,引用类型的变量似乎更占内存。哈哈,不用着急,后面你了解了引用类型的优点之后,你就会觉得这是个问题。  我们读取num变量的值的时候可以直接读取,但是当我们要读取arr中的值的时候,首先要找到arr中的地址,然后根据地址找到对应的数据。  引用型,类似于windows操作系统中的快捷方式。快捷方式是一个地址,真正的内容是快捷方式指向的路径的内容。例如:我们创建一个d:t.txt文件的快捷方式放在桌面上,那么桌面上的快捷方式就会占用桌面的空间,d:t.txt就会占用d盘的空间,所以它占用了两个方块空间。  基本类型相当于文件。  参考类型类似于我们填写入学登记表时填写家庭住址。这个家庭地址相当于第一空间,你真正的家(第二记忆空间)不在登记表上。如果学校要找你家,先在登记表上找到你家的地址,再根据地址找到你家。  3。引用类型的优点:  引用类型作为函数的参数有明显的优势。第一,形参传实参时,只需要传递地址,不需要移动大量数据(节省内存开销);第二,当形参对应的数据发生变化时,实参对应的数据也会发生变化(很多时候,我们希望如此)。  比如下面的代码:  首先定义函数(冒泡排序)  functionbubble(arr){  for(vari=0;i  for(varj=0;j  if(arr[j]>arr[j+1]){  vartemp=arr[j];  arr[j]=arr[j+1];  arr[j+1]=temp;  }  }  }  }  调用冒泡排序时,  vararr1=[250,2,290,35,12,99];  bubble(arr1);  查看上面代码执行时的内存变化:  图中,在执行①对应的代码时(vararr1=[250,2,290,35,12,99];),内存中会出现①对应的变化,即在堆栈并命名为arr1,在堆区申请内存空间放置250、2、290、35、12、99,并将堆区内存的地址赋值给arr1的内存;在执行②中对应的代码bubble(arr1)时,调用函数。这时候会定义形参arr(③在内存中对应变化),即在栈中申请一块内存区域,命名为arr,将arr1中保存的地址赋值给arr(赋值在内存中用②表示),所以,形参arr和实参arr1指向同一个内存区。数组中的值250、2、290、35、12、99在内存中只有一份。即不需要复制数组中每个元素的值,节省了内存。如果理解内存映射,那么当形参arr对应的数据顺序发生变化时,实参arr1对应的数据顺序也会发生变化。即,当形参数据改变时,实参数据也随之改变。所以冒泡函数不需要返回值,仍然可以达到排序的目的。大家可以运行我例子中的代码看看是否达到了排序效果。  补充,基本类型的内存变化作为函数参数:  内存映射:  4。引用类型变量的赋值:  引用类型变量赋值时,地址被赋值。即两个引用类型变量中存放的是同一个块地址,也就是说,两个引用类型变量都指向同一个内存区域。因此,这两个引用类型变量对应的数据是相同的。  又如:  varperson1={  姓名:"张三",  性别:"男",  年龄:12  };  varperson2=person1;  person2.name="张四";//这句话会改变person1和person2的名字。说明person1和person2的名字占用了相同的内存。  alert(person1.name+","+person1.sex+","+person1.age);  alert(person2.name+","+person2.sex+","+person2.age);  基本类型变量赋值时内存发生变化。  5.浅拷贝和深拷贝  先说对象的拷贝。上面说了,引用类型(对象)的赋值只是赋值的地址,那么当你要真正复制一个新的对象(也就是clone)的时候,怎么办呢。  varperson1={  name:"张三",  性别:"男",  年龄:12  };  varperson2={};  for(varkeyinperson1){  person2[key]=person1[key];  }  但是当对象的属性是引用类型时,就会出现浅拷贝和深拷贝的问题。使用自定义对象类型来说明问题。  例如:  varperson1={  姓名:"张三",  性别:"男",  年龄:12,  地址:{  国家:"陕西",  city:"渭南"  }  };  //对象??person1的地址是另外一个对象,也就是做一个person1的真实克隆,每一个address属性也被克隆。  varperson2={};  for(varkeyinperson1){  person2[key]=person1[key];  }  person2.name="张四";//不会改变person1的name属性。  person2.address.country="北京";//会改变person1的address.country  请注意,person1和person2的name属性有自己的空格,但是person1.address.country和person2.address.country是同一个空间。因此,当您更改person2.address.country的值时,person1.address.country的值也会更改。这意味着复制(克隆)没有到位。这种复制称为浅复制,进一步复制(克隆)person1.address.country和person1.address.name就是深复制。要实现深拷贝,需要判断每个属性的类型。如果是引用类型,会循环复制(需要递归)。