详解JavaScript栈内存与堆内存

  

  

在编译阶段,除了声明变量和函数,查找环境中的标识符这两项工作之外,还会进行内存分配。不同类型的数据会分配到不同的内存空间:

  
      <李>栈内存:引擎执行代码时工作的内存空间,除了引擎,也用来保存基本值和引用类型值的地址。   <李>堆内存:用来保存一组无序且唯一的引用类型值,可以使用栈中的键名来取得。   
  

示意图:

  

详解JavaScript栈内存与堆内存

  

  

引擎不能直接操作堆内存中的数据,这就造成了对同一个变量赋不同类型的值,会出现完全不同的效果:为一个变量赋基本值时,实际上是创建一个新值,然后把该值赋给新变量,可以说这是一种真正意义上的“赋值”,为一个变量赋引用值时,实际上是为新变量添加一个指针,指向堆内存中的一个对象,属于一种“赋址”操作。

  

例子:      //基本值   var=1;   var b=一个;=2;   console.log(一个);//输出:2   console.log (b);//输出:1//引用值//变量c和d指向堆中的同一个数组   var c=(0, 1, 2);   var d=c;   c [0]=5;   console.log (c);//输出:(5、1、2)   console.log (d);//输出:(5、1、2)   之前      

详解JavaScript栈内存与堆内存

  

  

浅拷贝可以简单理解为,发生在栈中的拷贝行为,只能拷贝基本值和引用值的地址。

  

实现方式

  

ES6定义了Object.assign()方法来实现浅拷贝。

  

例子:         让一个={   名称:“汤姆”,   obj: {   年龄:19   }   }   让b=对象。分配({});   console.log (b);//输出:{名称:“汤姆”,obj:{年龄:20}}      a.name=鞍住?   a.obj。=20岁;      console.log(一个);//输出:{名称:“艾米”,obj:{年龄:20}}   console.log (b);//输出:{名称:“汤姆”,obj:{年龄:20}}   数组的切片()方法也属于浅拷贝   例子:   var=[0, [1]];   var b=a.slice (0);   [0]=8;   一个[1][0]=9;      console.log(一个);//输出:[8 [9]]   console.log (b);//输出:[0,[9]]   之前      

* concat()方法也属于浅拷贝,这里不再叙述。

  

  

深拷贝可以简单理解为,同时发生在栈中和堆中的拷贝行为,除了拷贝基本值和引用值的地址之外,地址指向的堆中的对象也会发生拷贝。

  

实现方式

  

将需要深拷贝的对象序列化为一个JSON字符串,然后根据这个字符串解析出一个结构和值完全一样的新对象,可以间接实现深拷贝。

  

例子:
  

        让一个={   名称:“汤姆”,   obj: {   年龄:19   }   }   var b=JSON.parse (JSON.stringify (a));   console.log (b);//输出:{名称:“汤姆”,obj:{年龄:19}}      a.name=鞍住?   a.obj。=20岁;      console.log(一个);//输出:{名称:“艾米”,obj:{年龄:20}}   console.log (b);//输出:{名称:“汤姆”,obj:{年龄:19}}      之前      

*这种方法需要保证对象是安全的,例如属性值不能是未定义的,象征,函数,日期和正则。

  

使用美元.extend()方法实现深拷贝

  

$ .extend()方法并非原生JavaScript提供的方法,属于jquery的方法。这个方法提供的实现深拷贝的基本思路是:如果是基本值或除了对象或数组之外的引用值,直接赋值,如果是对象或数组就需要进行递归,直到递归到基本值或除了对象或数组之外的引用值为止。

  

jquery中$ .extend()方法的代码片段:
  

     //如果副本内容是数组或对象则继续调用扩展函数   如果(深,,副本,,(jQuery.isPlainObject(副本)| |   (copyIsArray=jQuery.isArray(副本)))){   如果(copyIsArray) {   copyIsArray=false;   克?src,,jQuery.isArray (src) & # 63;src: [];      其他}{   克?src,,jQuery.isPlainObject (src) & # 63;src: {};   }   目标[名字]=jQuery。扩展(深,克隆、复制);//如果副本内容不是数组或对象则直接赋值   }else if(复制!==未定义){   目标[名字]=复制;   }      之前      

参考.extend美元()方法的思路,我们可以自己探索深拷贝的实现方式:

  

例子:      

详解JavaScript栈内存与堆内存