详解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 KeyDown、KeyPress和KeyUp事件的区别与联系
Dec 03 Javascript
让你的CSS像Jquery一样做筛选的实现方法
Jul 10 Javascript
jQuery中each()方法用法实例
Dec 27 Javascript
js生成随机数的过程解析
Nov 24 Javascript
Jquery使用小技巧汇总
Dec 29 Javascript
PassWord输入框代码分享
Jun 07 Javascript
jQuery EasyUI提交表单验证
Jul 19 Javascript
Angular懒加载机制刷新后无法回退的快速解决方法
Aug 30 Javascript
Bootstrap Search Suggest使用例子
Dec 21 Javascript
easyui combogrid实现本地模糊搜索过滤多列
May 13 Javascript
JS获取url参数,JS发送json格式的POST请求方法
Mar 29 Javascript
基于vue-ssr的静态网站生成器VuePress 初体验
Apr 17 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
MySQL相关说明
2007/01/15 PHP
php的debug相关函数用法示例
2016/07/11 PHP
PHP版微信小店接口开发实例
2016/11/12 PHP
php出租房数据管理及搜索页面
2017/05/23 PHP
用js遍历 table的脚本
2008/07/23 Javascript
细说浏览器特性检测(2)-通用事件检测
2010/11/05 Javascript
jquery()函数的三种语法介绍
2013/10/09 Javascript
在JS中操作时间之getUTCMilliseconds()方法的使用
2015/06/10 Javascript
Angular懒加载机制刷新后无法回退的快速解决方法
2016/08/30 Javascript
分类解析jQuery选择器
2016/11/23 Javascript
bootstrapValidator bootstrap-select验证不可用的解决办法
2017/01/11 Javascript
浅析jsopn跨域请求原理及cors(跨域资源共享)的完美解决方法
2017/02/06 Javascript
jQuery实现的简单对话框拖动功能示例
2018/06/05 jQuery
vue里input根据value改变背景色的实例
2018/09/29 Javascript
BootStrap表单验证中的非Submit类型按钮点击时触发验证的坑
2019/09/05 Javascript
[01:07:22]2014 DOTA2华西杯精英邀请赛 5 24 DK VS VG加赛
2014/05/26 DOTA
[58:59]完美世界DOTA2联赛PWL S3 access vs CPG 第一场 12.13
2020/12/16 DOTA
一篇不错的Python入门教程
2007/02/08 Python
在Heroku云平台上部署Python的Django框架的教程
2015/04/20 Python
python从入门到精通(DAY 3)
2015/12/20 Python
Python实现的简单排列组合算法示例
2018/07/04 Python
python 判断矩阵中每行非零个数的方法
2019/01/26 Python
python_array[0][0]与array[0,0]的区别详解
2020/02/18 Python
Python tkinter之ComboBox(下拉框)的使用简介
2021/02/05 Python
HTML5 canvas 基本语法
2009/08/26 HTML / CSS
美国家居装饰和豪华家具购物网站:One Kings Lane
2018/12/24 全球购物
加拿大领先的时尚和体育零售商:Sporting Life
2019/12/15 全球购物
大学生创业计划书的用途
2014/01/08 职场文书
学生会竞选演讲稿
2014/04/24 职场文书
大学生入党推荐书范文
2014/05/17 职场文书
2014年企业团支部工作总结
2014/12/10 职场文书
表扬信范文
2019/04/22 职场文书
详解Html5项目适配系统深色模式方案总结
2021/04/14 HTML / CSS
用CSS3画一个爱心
2021/04/27 HTML / CSS
基于flask实现五子棋小游戏
2021/05/25 Python
浅谈Go语言多态的实现与interface使用
2021/06/16 Golang