晨叔周刊,每周一话题,技术天天涨。

本周的话题是JS的内存问题(加入本周话题,请点击传送门)。

图 话题入口

今天的技术晨报,就来谈谈JS中变量的,值传递和引用传递的问题。现在,对于很多的JSer来讲,基本不关心堆和栈的问题,代码照样666。

但是,现在的前端,不再是传统的JQ时代,而是MVVM,组件化,工程化。前端的承载着复杂业务逻辑。为此,内存问题,成为JSer必须要考虑的问题。 本文从堆栈讲起,让大家理解JS中变量的内存使用以及变动情况 。

一、初步了解堆栈 

先初步了解JS中的堆和栈,首先,内存空间分为 堆和栈两个区域,js 代码运行时,js解析器会先判断变量类型,根据变量类型,将变量放到不同的内存空间中(堆和栈)。

 图 1

基本的数据类型(String,Number,Boolean,Null,Undefined)都会分配栈区。而Object (对象)类型的变量都放到堆区。

如下代码示例

 var a = 12;
var b = false;
var c = "string" var chenshu = {name:"晨叔周刊",desc:"每周一话题,技术天天涨" }

对应的内存分配图如下图2

图 2 

栈区的特点:空间小,数据类型简单,读写速度快,一般由JS引擎自动释放

堆区的特点:空间大,数据类型复杂,读写速度稍逊,当对象不在被引用时,才会被周期性的回收。

了解了内存的栈区和堆区后, 接下来,来看看变量如何在栈区和堆区“愉快的玩耍”。

二、变量传递 

进入今天的重点,先看看下面的代码。

var a = 12;
var b= a;
b = 13;

上面代码的运行结果,a 变量的值没变,因为 第二行“b = a” ,把a的值赋值个b时, 执行的是“复制”的操作,a 和 b 没有关系。(so easy ,不在多BB),再往下看

1 var chenshu =  {name:"晨叔周刊",desc:"每周一话题,技术天天涨" };
2 var xiaoming = chenshu;
chenshu 不是基础类型变量, 而是一个对象。

第二行中,“xiaoming = chenshu”,进行也是“复制的操作”, 为什么? 且看下图分解。

根据代码,首先, 申明了变量“chenshu” ,如下图3。

图 3 

接下来, “xiaoming = chenshu”(复制操作),内存空间图如下图4

 图4

在上图4 中,xiaoming 变量的存储空间(栈区)复制了 chenshu变量的值,但是这个变量的值,并不是一个基础的数据类型,而是一个堆区的内存地址(指针)。所以操作“xiaoming”变量和操作“chenshu”变量效果都一样。

划重点:在JS的变量传递中,本质上都可以看成是值传递,只是这个值可能是基础数据类型,也可能是一个指针,如果是指针,我们通常就说为引用传递。 JS中比较特殊,不能直接操作对象的内存空间,必须通过指针(所谓的引用)来访问。

所以,即使是所以复杂数据类型(对象)的赋值操作,本质上也是值传递。在往下看看一个例子。

三、函数的形参、实参的值传递 


看如下代码。

function setName(user)
{
user.name = "new name";// 重新设置name 这个属性
} var chenshu = { name:"晨叔" }; setName(chenshu); console.log(chenshu.name);

讲解:

函数 setName 有一个 形参 “user”,没毛病。

将“chenshu”对象传给 “setName ” 函数,chenshu 为实参,也没毛病。

重点:传参的过程中,js引擎将实参chenshu的值(值是对象{name:"晨叔"}的指针)“复制”给形参。即,形参user 和 chenshu变量指向同一个堆内存对象。 没毛病。 但问题来了,实参和形参在是一个变量?还是两个变量? 很多开发者的误区:认为 在 setName 函数中改变了形参user的属性,实参 chenshu的属性也发生变动,就认为同一个变量,但真实的情况是:实际上实参和形参 是两个变量,只是实参和形参指向同一个堆区的变量而已,见如下图5

 图5 

形参user只是存了对象 { name:"晨叔" }的地址,但在栈区中,user是单独存在的,而且函数运行完,user 立即被释放了,为了更加直观的说明这个问题。我们再来分析一段代码。

  function setName(user)
{
user.name = "new name";// 重新设置name 这个属性
user = { name:"西门吹雪" };
} var chenshu = { name:"晨叔" };
setName(chenshu); console.log(chenshu.name);//输出 new name

上面这段代码就能很能说明问题,在“setName”函数中,形参user首先修改实参chenshu对象的name属性之后, 又重新指向了一个新对象“{ name:"西门吹雪" }”, 但因为 形参user和实参chenshu是两个对象,形参user指向新对象后,对实参chenshu并没有影响,因为实参和形参进行的是值传递(复制),实参和形参是两个独立在栈区的变量。

本文的分享就到这里,我们来做一下总结。

  1. 我们初步理解了js中的堆区和栈区。
  2. 理解了变量传递的方式——值传递,所谓的引用传递,本质上也是值传递,只是传递的这个值是一个指针, 值传递带来的效果就是在内存栈区创建了一个新的空间。
  3. 通过函数的实参和形参传递的分析,我们进一步的理解js的值传递。

本文的内容只是初步的探索JS的内存问题,更深的干货,更精彩的内容,请加入本期的分享话题,点击传送门

请关注“晨叔周刊”微信公众号, 即可每周与晨叔深入研究一个话题,每周一发布本周话题,周二,周六 早上九点更新周刊内容。晨叔口号: 晨叔周刊,每周一话题,技术天天涨。

 

晨叔技术晨报: 你真的搞懂JS中的“值传递”和“引用传递”吗?的更多相关文章

  1. 帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

    作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...

  2. 让你彻底搞懂JS中复杂运算符==

    让你彻底搞懂JS中复杂运算符== 大家知道,==是JavaScript中比较复杂的一个运算符.它的运算规则奇怪,容易让人犯错,从而成为JavaScript中“最糟糕的特性”之一. 在仔细阅读了ECMA ...

  3. 彻底搞懂 JS 中 this 机制

    彻底搞懂 JS 中 this 机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog 目录 this 是什么 this 的四种绑定规 ...

  4. 一文搞懂 js 中的各种 for 循环的不同之处

    一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...

  5. 搞懂js中小数运算精度问题原因及解决办法

    js小数运算会出现精度问题 js number类型 JS 数字类型只有number类型,number类型相当于其他强类型语言中的double类型(双精度浮点型),不区分浮点型和整数型. number类 ...

  6. 一文搞懂js中的typeof用法

    基础 typeof 运算符是 javascript 的基础知识点,尽管它存在一定的局限性(见下文),但在前端js的实际编码过程中,仍然是使用比较多的类型判断方式. 因此,掌握该运算符的特点,对于写出好 ...

  7. 来一轮带注释的demo,彻底搞懂javascript中的replace函数

    javascript这门语言一直就像一位带着面纱的美女,总是看不清,摸不透,一直专注服务器端,也从来没有特别重视过,直到最近几年,javascript越来越重要,越来越通用.最近和前端走的比较近,借此 ...

  8. 轻松搞懂Java中的自旋锁

    前言 在之前的文章<一文彻底搞懂面试中常问的各种“锁”>中介绍了Java中的各种“锁”,可能对于不是很了解这些概念的同学来说会觉得有点绕,所以我决定拆分出来,逐步详细的介绍一下这些锁的来龙 ...

  9. 通过一张简单的图,让你彻底地搞懂JS的==运算

    大家知道,JavaScript中的==是一种比较复杂运算,它的运算规则很奇怪,很容易让人犯错,从而成为JavaScript中“最糟糕的特性”之一. 在仔细阅读ECMAScript规范的基础上,我画了一 ...

随机推荐

  1. 读取Flex AIR应用程序设置

    说明: 本人之前做过一年的Flex AIR移动跨平台开发,在之前学习过程中,一直是将笔记记在了Evernote上,有的笔记是自己写的,也有的笔记是在网上看到,顺手记下了的. 所以在这里声明下,如果在网 ...

  2. HDU 1326

    题意:给出一堆高度不一的砖头,现在使他们高度一样,问最少的移动次数,(每减少1就是移动一次) 思路:求出平均高度,然后模拟最后平均高度的数组,也就是说,每个数组对应每一个平均高度,也就是说比平均高度大 ...

  3. 【t085】Sramoc问题

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] Sramoc(K,M)表示用数字0,1,2,...,K-1组成的自然数中能被M整除的最小数.给定K,M ...

  4. es6—变量的解构赋值

    数组的解构赋值 ]]]]]]] = []}} = {}} = {}})]: first]: last} = arr} = {}) {}))}))}) {}))}))].]]]])})] }}} = { ...

  5. 12174 - Shuffle——[滑动窗口]

    You are listening to your music collection using the shuffle function to keep the music surprising. ...

  6. P1009 字符三角形

    题目描述 输入一个字符c,按照阳历输出的格式输出由该字符组成的一个字符三角形. 输入格式 输入包含一个字符c. 输出格式 输出由该字符c组成的字符三角形. 样例输入 A 样例输出 A AAA AAAA ...

  7. tf.reduce_sum()

    #axis 表示在哪个维度进行sum操作,不写代表所有维 #keep_dims 是否保留原始数据维度 reduce_sum( input_tensor, axis=None, keep_dims=Fa ...

  8. RabbitMQ-Exchange交换器

    交换器分类 RabbitMQ的Exchange(交换器)分为四类: direct(默认) headers fanout topic 其中headers交换器允许你匹配AMQP消息的header而非路由 ...

  9. jQuery 工具类函数-字符串操作函数

    调用名为$.trim的工具函数,能删除字符串中左右两边的空格符,但该函数不能删除字符串中间的空格,调用格式为: $.trim (str); 参数str表示需要删除左右两边空格符的字符串. <bo ...

  10. vue-learning:4-template-v-if-and-v-show

    控制元素可见性的指令 v-if 和 v-show v-if v-else v-else-if :多重判断 template :分组渲染包裹元素 key:管理可复用元素 v-show v-if与v-sh ...