详解JavaScript栈内存与堆内存


Posted in Javascript onApril 04, 2019

内存分配

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

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

示意图:

详解JavaScript栈内存与堆内存

赋值与赋址

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

例子:

//基本值
var a = 1;
var b = a;
a = 2;
console.log(a); //输出: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() 方法来实现浅拷贝。

例子:

let a = {
  name: "Tom",
  obj: {
    age: 19
  }
}
let b = Object.assign({}, a);
console.log(b); //输出:{name: "Tom",obj: {age: 20}}

a.name = "Amy";
a.obj.age = 20;

console.log(a); //输出:{name: "Amy",obj: {age: 20}}
console.log(b); //输出:{name: "Tom",obj: {age: 20}}
数组的 slice() 方法也属于浅拷贝
例子:
var a = [0, [1]];
var b = a.slice(0);
a[0] = 8;
a[1][0] = 9;

console.log(a); //输出:[8, [9]]
console.log(b); //输出:[0, [9]]

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

深拷贝

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

实现方式

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

例子:

let a = {
  name: "Tom",
  obj: {
    age: 19
  }
}
var b = JSON.parse(JSON.stringify(a));
console.log(b); //输出:{name: "Tom",obj: {age: 19}}

a.name = "Amy";
a.obj.age = 20;

console.log(a); //输出:{name: "Amy",obj: {age: 20}}
console.log(b); //输出:{name: "Tom",obj: {age: 19}}

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

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

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

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

//如果 copy 内容是数组或对象则继续调用 extend 函数
if (deep && copy && (jQuery.isPlainObject(copy) || 
(copyIsArray = jQuery.isArray(copy)))) {
  if (copyIsArray) {
    copyIsArray = false;
    clone = src && jQuery.isArray(src) ? src : [];

  } else {
    clone = src && jQuery.isPlainObject(src) ? src : {};
  }
  target[name] = jQuery.extend(deep, clone, copy);

//如果 copy 内容不是数组或对象则直接赋值
} else if (copy !== undefined) {
  target[name] = copy;
}

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

例子:

//深拷贝函数
function extend(source) {
  var target = Array.isArray(source) ? [] : {};
  for (var key in source) {
    var isObject = Object.prototype.toString.call(source[key]) === "[object Object]";
    if (isObject || Array.isArray(source[key])) {
      //如果是对象或数组,继续调用 extend 函数
      target[key] = extend(source[key]);
    } else {
      //递归到基本值或除了对象或数组之外的引用值,直接赋值
      target[key] = source[key];
    }
  }
  return target;
}

//测试代码
var a = {
  a1: undefined,
  a2: null,
  a3: 123,
  a4: false,
  a5: "Tom",
  a6: Symbol.for("6"),
  obj: {
    s: "book",
    n: 10
  },
  arr: [1, 2, 3, [4]],
  fn: function() {
    console.log(999);
  },
  now: new Date(),
}

var b = extend(a);

a.a5 = "Amy";
console.log(a.a5); //输出:Amy
console.log(b.a5); //输出:Tom

a.obj.s = "pen";
console.log(a.obj.s); //输出:pen
console.log(b.obj.s); //输出:book

a.arr[3][0] = 9999;
console.log(a.arr[3][0]); //输出:9999
console.log(b.arr[3][0]); //输出:4

运行时流程图

结合本课的的内容,JavaScript 的运行时流程图如下:

详解JavaScript栈内存与堆内存

*这张图会根据内容的增加不断进行补充。

以上所述是小编给大家介绍的JavaScript栈内存与堆内存详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JavaScript 数组的 uniq 方法
Jan 23 Javascript
js post方式传递提交的实现代码
May 31 Javascript
JavaScript声明变量名的语法规则
Jul 10 Javascript
jquery实现顶部向右伸缩的导航区域代码
Sep 02 Javascript
JS实现弹出居中的模式窗口示例
Jun 20 Javascript
浅析JavaScript中作用域和作用域链
Dec 06 Javascript
JS中利用swiper实现3d翻转幻灯片实例代码
Aug 25 Javascript
[js高手之路]原型式继承与寄生式继承详解
Aug 28 Javascript
通过js动态创建标签,并设置属性方法
Feb 24 Javascript
Javascript幻灯片播放功能实现过程解析
May 07 Javascript
Vue-cli 移动端布局和动画使用详解
Aug 10 Javascript
vue+iview实现文件上传
Nov 17 Vue.js
jQuery中实现text()的方法
Apr 04 #jQuery
基于 jQuery 实现键盘事件监听控件
Apr 04 #jQuery
详解微信图片防盗链“此图片来自微信公众平台 未经允许不得引用”的解决方案
Apr 04 #Javascript
基于Vue+elementUI实现动态表单的校验功能(根据条件动态切换校验格式)
Apr 04 #Javascript
vue学习笔记五:在vue项目里面使用引入公共方法详解
Apr 04 #Javascript
JavaScript多种页面刷新方法小结
Apr 04 #Javascript
详解easyui 切换主题皮肤
Apr 04 #Javascript
You might like
使用 eAccelerator加速PHP代码的目的
2007/03/16 PHP
使用PHP导出Word文档的原理和实例
2013/10/21 PHP
使用PHPExcel操作Excel用法实例分析
2015/03/26 PHP
php验证码的制作思路和实现方法
2015/11/12 PHP
用js判断页面刷新或关闭的方法(onbeforeunload与onunload事件)
2012/06/22 Javascript
禁止iframe脚本弹出的窗口覆盖了父窗口的方法
2014/09/06 Javascript
javascript中clone对象详解
2014/12/03 Javascript
BootStrap下拉菜单和滚动监听插件实现代码
2016/09/26 Javascript
jQuery动态生成表格及右键菜单功能示例
2017/01/13 Javascript
js 动态生成html 触发事件传参字符转义的实例
2017/02/14 Javascript
详解angularJs指令的3种绑定策略
2017/04/13 Javascript
基于bootstrap实现多个下拉框同时搜索功能
2017/07/19 Javascript
Vue实现点击后文字变色切换方法
2018/02/11 Javascript
基于Webpack4和React hooks搭建项目的方法
2019/02/05 Javascript
Python BeautifulSoup中文乱码问题的2种解决方法
2014/04/22 Python
Python multiprocessing.Manager介绍和实例(进程间共享数据)
2014/11/21 Python
Python中文竖排显示的方法
2015/07/28 Python
使用Python编写爬虫的基本模块及框架使用指南
2016/01/20 Python
Python timeit模块的使用实践
2020/01/13 Python
Tensorflow 实现释放内存
2020/02/03 Python
tensorflow实现训练变量checkpoint的保存与读取
2020/02/10 Python
Pytorch学习之torch用法----比较操作(Comparison Ops)
2020/06/28 Python
无惧面试,带你搞懂python 装饰器
2020/08/17 Python
关于pycharm 切换 python3.9 报错 ‘HTMLParser‘ object has no attribute ‘unescape‘ 的问题
2020/11/24 Python
手把手教你用Django执行原生SQL的方法
2021/02/18 Python
VSCode中autopep8无法运行问题解决方案(提示Error: Command failed,usage)
2021/03/02 Python
Timberland俄罗斯官方网上商店:全球领先的户外品牌
2020/03/15 全球购物
给排水专业应届生求职信
2013/10/12 职场文书
计算机专业推荐信范文
2013/11/27 职场文书
大学毕业生个人自荐信范文
2014/01/08 职场文书
档案检查欢迎词
2014/01/13 职场文书
九年级化学教学反思
2014/01/28 职场文书
2015年新学期寄语
2015/02/26 职场文书
Keras多线程机制与flask多线程冲突的解决方案
2021/05/28 Python
关于python爬虫应用urllib库作用分析
2021/09/04 Python
vue实现移动端div拖动效果
2022/03/03 Vue.js