作为程序员,你一定要知道函数底层运行机制!!!

大家好,我是一个函数,一个又累,又苦,又被广大开发者使用的反派角色。

自从世界各大语言诞生的时候,我也随之诞生。虽然经常出现在人们的眼前,但是我的出生环境和身世却很少被人所知。今天不得不借助鹿哥的平台,进行一次自白。

这么多年过去了,总是被别人当做“工具人”,却总是不能够被人理解,我真的很伤心。多亏遇到了鹿哥,给了我这一次自白的机会。

在各个语言中,虽然我的存在的形态不同,但是我还是我,一个不一样的烟火,只要被人敲一下代码,我的兄弟姐妹们就被创建出来。而且我们每个函数天生的命运已经被决定这一生要去做一件事,我们不得不听天由命。

function fn(){
// 要执行的任务
......
}
function fn(a, b){
  let result = null;
  result = a + b;
  return result;
}

其实,我们也像人类一样,需要生存的环境,空气、食物和水,但是我们很少被人所周知。下面我就亲自介绍一下我们所生存环境——栈。

我生活的栈内存中,有属于自己的两间大房子,一间房子当做仓库,存放一些变量和变量对应的值。

另一间房子就是我的工作室,执行我天生体内就有的任务代码。我的每个兄弟姐妹都和我一样,都有独立的环境和两间大房子,只不过我们的命运不同。
在这里插入图片描述
在这里插入图片描述
每当我的上级 Boss(主线程)告诉我要开始工作了,我就开始在工作室从头到尾顺序执行体内所要处理的任务。

因为栈内存空间太小,只能存储一些变量的和值,我体内的任务代码占据空间太大,栈内存里放不下。所以当我出生的时候,我体内的代码会以一堆破字符串的形式存放在堆内存中(其他大仓库),我在栈内存中只存这个堆仓库的地址就行了,这样需要占据的栈空间就小很多了。

在这里插入图片描述
每当我的 Boss(主线程)告诉我,开始工作了,我就开始在我的存储变量的栈仓库和存储代码字符串的堆仓库中,取出所需要执行的值和字符串。先对取出的字符串转化为可执行代码,开始在一个全新私有栈内存环境下执行。将执行完的结果会返回给外界变量兄弟接收。

为了能让大家更好的记住我的运行机制,不得不麻烦一下鹿哥把这个函数从定义到执行完毕给梳理一下。

大家好,我是鹿哥。一个迷人帅气、代码风骚、文章通俗的硬核男人。以上是函数的自白,它讲完了,该换鹿哥 BB 几句了。

我们启动运行程序,程序代码自上而下顺序执行,当遇到下面代码时,会发生什么呢?

function fn(a, b){
  let result = null;
  result = a + b;
  return result;
}
var a = fn(10, 10)
console.log(a)

首先,遇到定义的函数 fn 时,会开辟一个栈内存空间,上边函数自己说了,栈内存空间会分为两部分,一部分是存储变量和对应的值。另一部分会分配给主线程用来执行代码。

在这里插入图片描述
由于函数是引用类型,会开辟一个堆内存空间,函数体内的所有执行代码字符串全部存放在堆中,当函数执行的时候才能叫做代码,这个时候只是存储在堆内的一堆破字符串而已。

在这里插入图片描述
程序继续自上而下执行,会将 a 变量存储在栈内存中,但是它对应的值就是函数执行后的返回值。

var a = fn(10, 10)

函数开始执行,每一次函数执行的目的就是把函数体内的代码(先从堆内存中取出那一堆破字符串,然后转化为代码)执行。而且是在一个全新私有的栈内存内执行。

函数体内的代码开始自上而下顺序执行,这个全新的私有作用域栈和之前我们说到的栈内存是一样的,也是由两部分组成。

首先将代码中的变量推入到栈中,然后根据代码的运算取出相对应的变量进行求值,最后 retrun,将计算的值返回给变量 a,此时 a 在栈内存中有了对应的值。

在这里插入图片描述

PS:如果函数体内有 return 则直接返回 return 的值,如果没有,则返回的是 undefined。

以上就是整个函数从定义到执行最后结束的底层过程,但是我们还没有更深入,我们上边说到了栈中执行的两部分专业名词叫做 VO 阶段和 AO 阶段,再深入就会涉及到 JS 的编译过程,又可以作为一大部分去讲解。

通过上边函数底层的运行机制,我们有很多疑问得到解惑,比如为什么函数内声明的变量,函数外部不可访问?

因为函数执行,又重新创建了一个全新私有作用域,外界是不能直接访问该私有作用域栈内存中的值的,只有通过 return 的方式把值返回出去或者通过某种方式暴露出去。

函数定义的时候,函数体不执行的原因?

定义函数时,让对应的变量指向该堆内存的地址。我们只不过是在堆内存存了一堆破字符串而已,而不是代码,无法执行。只有当调用函数的时候,从堆内存中取出字符串转化为可执行的代码,函数体才可以执行。

通过这篇函数底层的运行机制,我们之前存在的一些对函数的疑问都一目了然。虽然像这种函数的底层运行机制看起来不难,但是我们自学中很难去梳理把握全面。

一些大厂的面试题,虽然看起来表面感觉很复杂,如果通过鹿哥上述对代码的整个底层运作拆解,再复杂的题目对你来说也会游刃有余。

不信来个阿里的面试题,欢迎在留言区写出你的答案和分析的过程。

 let a = {
    n:1
 }
 let b = a;
 
 a.x = a = {
    n:2
 }
 console.log(a.x)
console.log(b)

❤️ 不要忘记留下你学习的脚印 [点赞 + 收藏 + 评论]

1、老铁们,我是小鹿,欢迎关注我的原创微信公众号 「 小鹿动画学编程」,专注于数据结构和算法,网络原理,计算机基础、Web 大前端等,欢迎来鹿哥公众号搞事情。一天一篇动画家属技术搞定你。。

2、给俺点个赞呗,可以让更多的人看到这篇文章,顺便激励下我,就这么脸皮厚!

发布了68 篇原创文章 · 获赞 8550 · 访问量 63万+

猜你喜欢

转载自blog.csdn.net/qq_36903042/article/details/105267927