详解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 相关文章推荐
jquery操作下拉列表、文本框、复选框、单选框集合(收藏)
Jan 08 Javascript
js密码强度校验
Nov 10 Javascript
二维码图片生成器QRCode.js简单介绍
Aug 18 Javascript
JavaScript中创建原子的方法总结
Aug 26 Javascript
Vue Cli3 创建项目的方法步骤
Oct 15 Javascript
Vue一次性简洁明了引入所有公共组件的方法
Nov 28 Javascript
PM2自动部署代码步骤流程总结
Dec 10 Javascript
简单的React SSR服务器渲染实现
Dec 11 Javascript
jQuery表单选择器用法详解
Aug 22 jQuery
js实现坦克移动小游戏
Oct 28 Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
Jul 21 Javascript
react+antd 递归实现树状目录操作
Nov 02 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
PHP比你想象的好得多
2014/11/27 PHP
php自定义hash函数实例
2015/05/05 PHP
怎样搭建PHP开发环境
2015/07/28 PHP
PHP常用技巧汇总
2016/03/04 PHP
Zend Framework入门应用实例详解
2016/12/11 PHP
C#中TrimStart,TrimEnd,Trim在javascript上的实现
2011/01/17 Javascript
Javascript获取数组中的最大值和最小值的方法汇总
2016/01/01 Javascript
jquery form表单获取内容以及绑定数据
2016/02/24 Javascript
Jquery 自定义事件实现发布/订阅的简单实例
2016/06/12 Javascript
Angular动态添加、删除输入框并计算值实例代码
2017/03/29 Javascript
代码详解Vuejs响应式原理
2017/12/20 Javascript
Vue引入jquery实现平滑滚动到指定位置
2018/05/09 jQuery
vue如何引入sass全局变量
2018/06/28 Javascript
解决vue axios的封装 请求状态的错误提示问题
2018/09/25 Javascript
JavaScript闭包与作用域链实例分析
2019/01/21 Javascript
Vue项目配置跨域访问和代理proxy设置方式
2020/09/08 Javascript
[47:45]Liquid vs OG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python 示例分享---逻辑推理编程解决八皇后
2014/07/20 Python
Python标准异常和异常处理详解
2015/02/02 Python
使用Python的urllib2模块处理url和图片的技巧两则
2016/02/18 Python
python爬虫入门教程--利用requests构建知乎API(三)
2017/05/25 Python
python获取多线程及子线程的返回值
2017/11/15 Python
python远程邮件控制电脑升级版
2019/05/23 Python
python3 实现函数写文件路径的正确方法
2019/11/27 Python
Python3 中作为一等对象的函数解析
2019/12/11 Python
如何基于Python + requests实现发送HTTP请求
2020/01/13 Python
谈谈python垃圾回收机制
2020/09/27 Python
Python 实现键盘鼠标按键模拟
2020/11/18 Python
Python利用imshow制作自定义渐变填充柱状图(colorbar)
2020/12/10 Python
巴西网上药房:onofre
2016/11/21 全球购物
澳大利亚当地社区首选的光学商店:1001 Optical
2019/08/24 全球购物
我与祖国共奋进演讲稿
2014/09/13 职场文书
一年级数学下册复习计划
2015/01/17 职场文书
2016抗战胜利71周年红领巾广播稿
2015/12/18 职场文书
《田忌赛马》教学反思
2016/02/19 职场文书
mysql查询的控制语句图文详解
2021/04/11 MySQL