加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

JavaScript是如何工作的:JavaScript的共享传递和按值传递

发布时间:2019-04-19 07:40:47 所属栏目:建站 来源:前端小智
导读:关于JavaScript如何将值传递给函数,在互联网上有很多误解和争论。大致认为,参数为原始数据类时使用按值传递,参数为数组、对象和函数等数据类型使用引用传递。 按值传递 和 引用传递参数 主要区别简单可以说: 按值传递:在函数里面改变传递的值不会影响

JavaScript 在执行期间为程序分配了三部分内存:代码区,调用堆栈和堆。 这些组合在一起称为程序的地址空间。

JavaScript是如何工作的:JavaScript的共享传递和按值传递

代码区:这是存储要执行的JS代码的区域。

调用堆::这个区域跟踪当前正在执行的函数,执行计算并存储局部变量。变量以后进先出法存储在堆栈中。最后一个进来的是第一个出去的,数值数据类型存储在这里。

例如:

  1. var corn = 95  
  2. let lion = 100 

在这里,变量 corn 和 lion 值在执行期间存储在堆栈中。

堆:是分配 JavaScript 引用数据类型(如对象)的地方。 与堆栈不同,内存分配是随机放置的,没有 LIFO策略。 为了防止堆中的内存漏洞,JS引擎有防止它们发生的内存管理器。

  1. class Animal {}  
  2. // 在内存地址 0x001232 上存储 new Animal() 实例  
  3. // tiger 的堆栈值为 0x001232  
  4. const tiger = new Animal()  
  5. // 在内存地址 0x000001 上存储 new Objec实例  
  6. // `lion` 的堆栈值为 0x000001  
  7. let lion = {  
  8. strength: "Very Strong"  
  9. }    
JavaScript是如何工作的:JavaScript的共享传递和按值传递   

Here,lion 和 tiger 是引用类型,它们的值存储在堆中,并被推入堆栈。它们在堆栈中的值是堆中位置的内存地址。

激活记录(Activation Record),参数传递

我们已经看到了 JS 程序的内存模型,现在,让我们看看在 JavaScript 中调用函数时会发生什么。

  1. // 例子一  
  2. function sum(num1,num2) {  
  3. var result = num1 + num2  
  4. return result  
  5. }  
  6. var a = 90  
  7. var b = 100  
  8. sum(a, b)  

每当在 JS 中调用一个函数时,执行该函数所需的所有信息都放在堆栈上。这个信息就是所谓的激活记录(Activation Record)。

这个 Activation Record,我直译为激活记录,找了好多资料,没有看到中文一个比较好的翻译,如果朋友们知道,欢迎留言。

激活记录上的信息包括以下内容:

  • SP 堆栈指针:调用方法之前堆栈指针的当前位置。
  • RA 返回地址:这是函数执行完成后继续执行的地址。
  • RV 返回值:这是可选的,函数可以返回值,也可以不返回值。
  • 参数:将函数所需的参数推入堆栈。
  • 局部变量:函数使用的变量被推送到堆栈。

我们必须知道这一点,我们在js文件中编写的代码在执行之前由 JS 引擎(例如 V8,Rhino,SpiderMonke y等)编译为机器语言。

所以以下的代码:

  1. let shark = "Sea Animal" 

会被编译成如下机器码:

  1. 01000100101010  
  2. 01010101010101  

上面的代码是我们的js代码等价。 机器码和 JS 之间有一种语言,它是汇编语言。 JS 引擎中的代码生成器在最终生成机器码之前,首先是将 js 代码编译为汇编代码。

为了了解实际发生了什么,以及在函数调用期间如何将激活记录推入堆栈,我们必须了解程序是如何用汇编表示的。

为了跟踪函数调用期间参数是如何在 JS 中传递的,我们将例子一的代码使用汇编语言表示并跟踪其执行流程。

先介绍几个概念:

ESP:(Extended Stack Pointer)为扩展栈指针寄存器,是指针寄存器的一种,用于存放函数栈顶指针。与之对应的是 EBP(Extended Base Pointer),扩展基址指针寄存器,也被称为帧指针寄存器,用于存放函数栈底指针。

EBP:扩展基址指针寄存器(extended base pointer) 其内存放一个指针,该指针指向系统栈最上面一个栈帧的底部。

EBP 只是存取某时刻的 ESP,这个时刻就是进入一个函数内后,cpu 会将ESP的值赋给 EBP,此时就可以通过 EBP 对栈进行操作,比如获取函数参数,局部变量等,实际上使用 ESP 也可以。

  1. // 例子一  
  2. function sum(num1,num2) {  
  3. var result = num1 + num2  
  4. return result  
  5. }  
  6. var a = 90  
  7. var b = 100  
  8. var s = sum(a, b)  

我们看到 sum 函数有两个参数 num1 和 num2。函数被调用,传入值分别为 90 和 100 的 a 和 b。

记住:值数据类型包含值,而引用数据类型包含内存地址。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读