详解JavaScript的内存空间、赋值和深浅拷贝


Posted in Javascript onApril 17, 2019

JavaScript的内存空间

在JavaScript中,每一个数据都需要一个内存空间。内存空间分为两种,栈内存(stack)与堆内存(heap)

栈是系统自动分配的内存空间,由系统自动释放,堆则是动态分配的内存,大小不定不会自动释放。

基础数据类型

JavaScript中的基础数据类型,这些值都有固定的大小,保存在栈内存中,由系统自动分配存储空间在栈内存空间的值,我们可以直接进行操作,因此基础数据类型都是按照值访问

在栈内存中的数据发生复制的行为时,系统会自动为新变量开辟一个新的内存空间,当复制执行后,两个内存空间的值就互不影响,改变其中一个不会影响另一个

栈内存空间数据复制示例
var a = `I am variable a`;
var b = a; 
console.log(b); //`I am variable a`
b = `I am variable b`;
console.log(a); //`I am variable a`
console.log(b); //`I am variable b`

引用数据类型

引用类型的值是保存在堆内存中的对象,在JavaScript中我们不能直接操作对象的堆内存空间。因为引用类型的值都是按引用访问的,所以在操作对象时,实际上是操作对象的引用而不是实际的对象。引用可以理解为保存在栈内存中的一个地址,该地址指向堆内存中的一个实际对象

引用类型值的复制,系统会为新的变量自动分配一个新的栈内存空间这个栈内存空间保存着与被复制变量相同的指针,尽管他们在栈内存中的内存空间的位置互相独立但是在堆内存中访问到的对象实际上是同一个,因此,当我们改变其中一个对象的值时,实际上就是改变原来的对象

栈内存空间保存指针(地址),堆内存空间保存实际的对象,我们通过变量访问对象时,实际上访问的是对象的引用(地址)

内存中的栈区域存放变量(基本类型的变量包括变量声明和值)以及指向堆区域存储位置的指针(引用类型的变量包括变量声明和指向内容的指针)

var a = {
  name : `I am object a`,
  type : 'object'
}

var b = a;
console.log(b);
// {name: "I am object a", type: "object"}

b.name = `I am object b`;

console.log(a);
// {name: "I am object b", type: "object"}

console.log(b);

// {name: "I am object b", type: "object"}

基本类型总结

基本数据类型:

包括:null、undefined、number、string、boolean、symbol(es6)

存放位置:内存中的栈区域中

比较:值的比较,判断是否相等,如果值相等,就相等。一般使用===进行比较,因为==会进行类型的转换

拷贝:赋值(通过(=)赋值操作符 赋值),赋值完成后,两个变量之间就没有任何关系了,改变其中一个变量的值对另一个没有任何影响

引用类型总结

引用数据类型:

包括:数组、对象、函数

存放位置:内存的栈区域中存放变量和指针,堆区域存储实际的对象

比较:是引用的比较(就是地址的比较,变量在栈内存中对应的指针地址相等就指向同一个对象)判断是否为同一个对象,示例如下

变量a和变量b的引用不同,对象就不是同一个对象
var a = {name:'Jay'};
var b = {name:'Jay'};
a===b //false

我们对JavaScript中引用类型进行操作的时候,都是操作其对象的引用(保存在栈内存中的指针)

赋值、深拷贝和浅拷贝 (Assignment, deep copy and shallow copy)

赋值:两个变量的值(指针)都指向同一个对象,改变其中一个,另一个也会受到影响

所谓拷贝就是复制,通过复制原对象生成一个新的对象

浅拷贝:重新在堆内存中开辟一个空间,拷贝后新对象获得一个独立的基本数据类型数据,和原对象共用一个原对象内的引用类型数据,改变基本类型数据,两个对象互不影响,改变其中一个对象内的引用类型数据,另一个对象会受到影响

var obj = {
  name: 'Jay Chou',
  age: 32,
  song:{
    name:'发如雪',
    year:2007
  }
}
var obj1 = obj;
function shallowCopy(obj){
  var scObj = {};
  for(var prop in obj){
    if(obj.hasOwnProperty(prop)){
      scObj[prop] = obj[prop]
    }
  }
  return scObj;
}
var obj2 = shallowCopy(obj);
console.log(obj === obj1,'obj === obj1','赋值');
console.log(obj === obj2,'obj === obj2','浅拷贝');
// true "obj === obj1" "赋值"
// false "obj === obj2" "浅拷贝"
console.log(obj.song === obj2.song);
//true
obj2.song.name='双截棍';
obj2.name='Jay';
console.log(obj)
// {name: "Jay Chou", age: 32, song: {name:'双截棍',year:2007}}
console.log(obj1);
// {name: "Jay Chou", age: 32, song: {name:'双截棍',year:2007}}
console.log(obj2);
{name: "Jay", age: 32, song: {name:'双截棍',year:2007}}
console.log(obj===obj1)
//true
console.log(obj===obj2)
//false

深拷贝:不论是对象内的基本类型还是引用类型都被完全拷贝,拷贝后两个对象互不影响

一种比较简单实现方法是使用var dcObj = JSON.parse(JSON.stringify(obj))

var obj = {
  name: 'Jay Chou',
  age: 32,
  song:{
    name:'发如雪',
    year:2007
  }
}

var dcObj=JSON.parse(JSON.stringify(obj));

console.log(dcObj);
// {name: "Jay Chou", age: 32, song: {name:'发如雪',year:2007}}
console.log(dcObj.song === obj.song);
//false
dcObj.name='Jay';
dcObj.song.name='双截棍';
console.log(obj);
// {name: "Jay Chou", age: 32, song: {name:'发如雪',year:2007}}
console.log(dcObj);
//{name: "Jay", age: 32, song: {name:'双截棍',year:2007}}

比较:赋值、深拷贝、浅拷贝

赋值:新对象仍然指向原对象,改变新对象的基本类型和引用类型的值都会使原对象对应的值一同改变

浅拷贝:改变新对象基本类型的值不会使原对象对应的值一起改变,但是改变新对象引用类型的值会使原对象对应的值一同改变

深拷贝:改变新对象基本类型和引用类型的值,都不会影响原对象,两者互相独立,互不影响

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

Javascript 相关文章推荐
JavaScript 动态添加表格行 使用模板、标记
Oct 24 Javascript
超酷的网页音乐播放器DewPlayer使用方法
Dec 18 Javascript
js控制容器隐藏出现防止样式变化的两种方法
Apr 25 Javascript
深入理解JavaScript系列(43):设计模式之状态模式详解
Mar 04 Javascript
基于javascript实现图片左右切换效果
Jan 25 Javascript
JS实现左右无缝轮播图代码
May 01 Javascript
JavaScript检测原始值、引用值、属性
Jun 20 Javascript
js实现前端图片上传即时预览功能
Aug 02 Javascript
JS+CSS实现网页加载中的动画效果
Oct 27 Javascript
Vue使用NProgress进度条的方法
Sep 21 Javascript
vue+vant使用图片预览功能ImagePreview的问题解决
Apr 10 Javascript
Element实现动态表格的示例代码
Aug 02 Javascript
Vue源码探究之虚拟节点的实现
Apr 17 #Javascript
ES6知识点整理之数组解构和字符串解构的应用示例
Apr 17 #Javascript
ES6知识点整理之对象解构赋值应用示例
Apr 17 #Javascript
ES6知识点整理之函数对象参数默认值及其解构应用示例
Apr 17 #Javascript
仿vue-cli搭建属于自己的脚手架的方法步骤
Apr 17 #Javascript
一篇文章,教你学会Vue CLI 插件开发
Apr 17 #Javascript
ES6知识点整理之函数数组参数的默认值及其解构应用示例
Apr 17 #Javascript
You might like
PHP学习笔记之字符串编码的转换和判断
2014/05/22 PHP
php实现根据字符串生成对应数组的方法
2014/09/22 PHP
PHP时间相关常用函数用法示例
2020/06/03 PHP
js中cookie的使用详细分析
2008/05/28 Javascript
jQuery源码分析之Event事件分析
2010/06/07 Javascript
javascript Array.prototype.slice使用说明
2010/10/11 Javascript
JavaScript实现点击文字切换登录窗口的方法
2015/05/11 Javascript
JS实现新浪博客左侧的Blog管理菜单效果代码
2015/10/22 Javascript
基于jquery插件实现拖拽删除图片功能
2020/08/27 Javascript
js定义类的几种方法(推荐)
2016/06/08 Javascript
JS中parseInt()和map()用法分析
2016/12/16 Javascript
关于javascript事件响应的基础语法总结(必看篇)
2016/12/26 Javascript
jQuery中弹出iframe内嵌页面元素到父页面并全屏化的实例代码
2016/12/27 Javascript
如何写好你的JavaScript【推荐】
2017/03/02 Javascript
Bootstrap禁用响应式布局的实现方法
2017/03/09 Javascript
微信小程序 判断手机号的实现代码
2017/04/19 Javascript
Vue2.0 vue-source jsonp 跨域请求
2017/08/04 Javascript
JS中精巧的自动柯里化实现方法
2017/12/12 Javascript
js中let和var定义变量的区别
2018/02/08 Javascript
Vue两个版本的区别和使用方法(更深层次了解)
2020/02/16 Javascript
extjs4图表绘制之折线图实现方法分析
2020/03/06 Javascript
python 不关闭控制台的实现方法
2011/10/23 Python
python的mysqldb安装步骤详解
2017/08/14 Python
Python使用add_subplot与subplot画子图操作示例
2018/06/01 Python
python中使用ctypes调用so传参设置遇到的问题及解决方法
2019/06/19 Python
Python定时任务APScheduler的实例实例详解
2019/07/22 Python
Django结合ajax进行页面实时更新的例子
2019/08/12 Python
Python logging模块原理解析及应用
2020/08/13 Python
python help函数实例用法
2020/12/06 Python
html5 postMessage解决跨域、跨窗口消息传递方案
2016/12/20 HTML / CSS
Perfume’s Club法国站:购买香水和化妆品
2019/05/02 全球购物
门卫岗位职责
2013/11/15 职场文书
群众路线教育实践活动心得体会
2014/03/07 职场文书
活动策划求职信模板
2014/04/21 职场文书
公司授权委托书
2014/10/17 职场文书
保洁员岗位职责
2015/02/04 职场文书