详解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 相关文章推荐
js parentElement和offsetParent之间的区别
Mar 23 Javascript
jQuery EasyUI API 中文文档 - DataGrid数据表格
Nov 17 Javascript
js实现连续英文字符自动换行兼容ie6 ie7和firefox
Sep 06 Javascript
js实现星星打分效果的方法
Jul 05 Javascript
JS实现的仿淘宝交易倒计时效果
Nov 27 Javascript
jQuery EasyUI 入门必看
Jun 03 Javascript
JS实现仿百度文库评分功能
Jan 12 Javascript
BootStrap实现带关闭按钮功能
Feb 15 Javascript
ES6新特性之类(Class)和继承(Extends)相关概念与用法分析
May 24 Javascript
vue 本地环境跨域请求proxyTable的方法
Sep 19 Javascript
浅谈JavaScript中你可能不知道URL构造函数的属性
Jul 13 Javascript
JS实现简易图片自动轮播
Oct 16 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利用func_get_args和func_num_args函数实现函数重载实例
2014/11/12 PHP
PHP可变函数学习小结
2015/11/29 PHP
Zend Framework教程之MVC框架的Controller用法分析
2016/03/07 PHP
PHP const定义常量及global定义全局常量实例解析
2020/05/28 PHP
PHP文件打开关闭及读写操作示例解析
2020/08/06 PHP
PHP替换Word中变量并导出PDF图片的实现方法
2020/11/26 PHP
JavaScript入门教程(2) JS基础知识
2009/01/31 Javascript
jquery插件制作简单示例说明
2012/02/03 Javascript
ExtJS4 Grid改变单元格背景颜色及Column render学习
2013/02/06 Javascript
自己编写的类似JS的trim方法
2013/10/09 Javascript
JavaScript数据类型学习笔记
2016/01/25 Javascript
ArtEditor富文本编辑器增加表单提交功能
2016/04/18 Javascript
jquery使用on绑定a标签无效 只能用live解决
2016/06/02 Javascript
遍历json 对象的属性并且动态添加属性的实现
2016/12/02 Javascript
深入理解JavaScript中的for循环
2017/02/07 Javascript
微信小程序 定位到当前城市实现实例代码
2017/02/23 Javascript
小程序云开发部署攻略(图文教程)
2018/10/30 Javascript
laydate如何根据开始时间或者结束时间限制范围
2018/11/15 Javascript
Vue $emit()不能触发父组件方法的原因及解决
2020/07/28 Javascript
python实现数独算法实例
2015/06/09 Python
深入浅析Python中join 和 split详解(推荐)
2016/06/30 Python
python smtplib模块实现发送邮件带附件sendmail
2018/05/22 Python
对dataframe进行列相加,行相加的实例
2018/06/08 Python
Python面向对象基础入门之设置对象属性
2018/12/11 Python
tensorflow求导和梯度计算实例
2020/01/23 Python
Python requests模块安装及使用教程图解
2020/06/30 Python
基于Python爬取搜狐证券股票过程解析
2020/11/18 Python
英国奢侈品牌时尚购物平台:Farfetch(支持中文)
2020/02/18 全球购物
招聘单位介绍信
2014/01/14 职场文书
雪山饭庄的创业计划书范文
2014/01/18 职场文书
乡镇八一建军节活动方案
2014/08/24 职场文书
环境工程专业毕业生求职信
2014/09/30 职场文书
清明节寄语2015
2015/03/23 职场文书
产品调价通知函
2015/04/20 职场文书
师德师风主题教育活动总结
2015/05/07 职场文书
【DOTA2】总决赛血虐~ XTREME GAMING vs MAGMA - OGA DOTA PIT 2022 CN
2022/04/02 DOTA