Part1 值类型与引用类型
值类型与引用类型的定义
值类型(基本类型)
定义:存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。
5种基本数据类型:string
、number
、boolean
、null
、undefined
。引用类型
定义:存放在堆内存中的对象,变量保存的实际是一个指针,当我们需要访问引用类型时,存放在栈内存中的指针会将我们指向堆内存的数据。每块空间大小不一样,根据情况进行特定的分配。
常见的引用类型有:Array
、Object
、Function
值类型与引用类型的存储(传值与传址)
值类型的赋值:把右边存储的信息(具体数据)复制一份给左边的变量。
特点:值类型赋值只是简单的数据复制,互相不影响,是独立的。
12345var a = 10;var b = a; //具体数据的复制,复制之后a,b相互独立互不影响b = 1;console.log(a); //10console.log(b); //1引用类型的赋值:把右边存储的信息(指向具体数据的地址)复制一份给左边的变量。
特点:共享同一份数据,修改其中一个对象属性的值也会影响另一个。
1234567var obj1 = {num : 10};var obj2 = obj1; //数据地址的复制,两个对象指向同一份数据,共享同一份数据。obj2.num = 1;console.log(obj1.num); //1 修改obj2的属性也会影响obj1console.log(obj2.num); //1
值类型与引用类型在函数中的应用
在函数中的参数有两种,一种是实参,就是实际的参数。还有一种是形参,形式参数,占位用的,函数调用之前是没有值的。
函数的调用:默认会把实参赋值给形参。
值类型作为函数的参数(值传递)
形参与实参相互独立,没有影响12345678var num = 10;function fn(n) {//默认会执行一步 n = num;n = 10;console.log(n); //10}fn(num); //函数的调用console.log(num); //20 值传递时,形参实参互不影响引用类型做为函数的参数(指针传递)
实参形参共享同一份数据,修改一个对象的值也会对另外一个对象产生影响123456789var obj = {num : 10}; //定义一个对象function fn(object) {//默认进行 object = obj; 此时进行了地址的传递object.num = 1; //修改了一个源数据,所有指向改数据的对象的属性都进行了更改object = {other : others}; //object新建一块内存空间,指针指向新建的空间console.log(object.num); //undefined 新建的空间内部已经没有num属性}fn(obj); //调用函数console.log(obj.num); //1 被object更改了属性
Part2 堆栈的概念
堆栈的定义
堆(heap)
动态分配内存,大小不定,不会自动释放存储空间,堆中存储复杂类型数据栈(stack)
自动分配内存空间,系统自动释放,栈中存储简单类型数据栈是一中特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。
后进先出(Last in First out),简称LIFO线性表
数据在堆栈中的表示
JavaScript在内存中是如何表示的呢?我们可以通过以下例子来了解值类型和引用类型在内存中是如何存储的。
|
|
以上代码可以描述为图示的关系:
Part3 深拷贝与浅拷贝
浅拷贝
在定义一个对象或数组的时候,变量在栈中只是存储了一个地址(指针),当我们复制该对象或数组的时候,复制的值也是该地址。在访问属性的时候,还是会通过复制的地址回溯到原来对象或数组指向的内存中。即两者共享了同一内存空间。修改一个对象的属性,另一个对象也会受到影响。
深拷贝
当我们不希望复制后的对象还与原对象共享同一数据,两者独立时,我们可以使用深拷贝来解决,通过递归的方法,把原对象中的属性方法都遍历给新的对象。这样,两个对象的属性会存储在堆中的不同内存空间。