详解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 相关文章推荐
经验几则 推荐
Sep 05 Javascript
完美解决AJAX跨域问题
Nov 01 Javascript
javascript读取Xml文件做一个二级联动菜单示例
Mar 17 Javascript
javascript制作的滑动图片菜单
May 15 Javascript
JS基于MSClass和setInterval实现ajax定时采集信息并滚动显示的方法
Apr 18 Javascript
JQuery学习总结【二】
Dec 01 Javascript
react native与webview通信的示例代码
Sep 25 Javascript
Vue异步加载about组件
Oct 31 Javascript
vue2.x+webpack快速搭建前端项目框架详解
Nov 30 Javascript
npm 下载指定版本的组件方法
May 17 Javascript
SSM+layUI 根据登录信息显示不同的页面方法
Sep 20 Javascript
layui监听下拉选框选中值变化的方法(包含监听普通下拉选框)
Sep 24 Javascript
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
跟我学Laravel之视图 & Response
2014/10/15 PHP
PHP附件下载中文名称乱码的解决方法
2015/12/17 PHP
php防止表单重复提交实例讲解
2019/02/11 PHP
javascript在一段文字中的光标处插入其他文字
2007/08/26 Javascript
Div自动滚动到末尾的代码
2008/10/26 Javascript
Javascript学习笔记1 数据类型
2010/01/11 Javascript
JQuery 选择和过滤方法代码总结
2010/11/19 Javascript
JQuery中DOM事件冒泡实例分析
2015/06/13 Javascript
jQuery判断多个input file 都不能为空的例子
2015/06/23 Javascript
CSS javascript 结合实现悬浮固定菜单效果
2015/08/23 Javascript
深入浅析JavaScript中数据共享和数据传递
2016/04/25 Javascript
深入浅析JavaScript函数前面的加号和叹号
2016/07/09 Javascript
jQuery实现单击按钮遮罩弹出对话框效果(2)
2017/02/20 Javascript
jquery+css3实现熊猫tv导航代码分享
2018/02/12 jQuery
vue组件传递对象中实现单向绑定的示例
2018/02/28 Javascript
Vue + Element UI图片上传控件使用详解
2019/08/20 Javascript
layui表单验证select下拉框实现验证的方法
2019/09/05 Javascript
JavaScript实现图片上传并预览并提交ajax
2019/09/30 Javascript
JavaScript实现多个物体同时运动
2020/03/12 Javascript
vue css 引入asstes中的图片无法显示的四种解决方法
2020/03/16 Javascript
[01:31:22]Ti4 循环赛第四日附加赛LGD vs Mouz
2014/07/13 DOTA
Python内置函数dir详解
2015/04/14 Python
python+requests+unittest API接口测试实例(详解)
2017/06/10 Python
python 连接各类主流数据库的实例代码
2018/01/30 Python
Python二叉树的遍历操作示例【前序遍历,中序遍历,后序遍历,层序遍历】
2018/12/24 Python
python项目对接钉钉SDK的实现
2019/07/15 Python
Pycharm安装并配置jupyter notebook的实现
2020/05/18 Python
Django实现任意文件上传(最简单的方法)
2020/06/03 Python
python 还原梯度下降算法实现一维线性回归
2020/10/22 Python
详解H5本地储存Web Storage
2017/07/03 HTML / CSS
eBay澳大利亚站:eBay.com.au
2018/02/02 全球购物
CheapTickets泰国:廉价航班,查看促销价格并预订机票
2019/12/28 全球购物
实习报告评语
2014/04/26 职场文书
超市理货员岗位职责
2014/07/04 职场文书
评估“风险”创业计划的几大要点
2019/08/12 职场文书
Python实现日志实时监测的示例详解
2022/04/06 Python