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

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

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

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

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

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

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

另一间房子就是我的工作室,执行我天生体内就有的任务代码。我的每个兄弟姐妹都和我一样,都有独立的环境和两间大房子,只不过我们的命运不同。

每当我的上级 Boss(主线程)告诉我要开始工作了,我就开始在工作室从头到尾顺序执行体内所要处理的任务。

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

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

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

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

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

1function fn(a, b){2  let result = null;3  result = a + b;4  return result;5}6var a = fn(10, 10)7console.log(a)

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

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

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

1var a = fn(10, 10)

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

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

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

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

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

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

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

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

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

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

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

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

 1let a = { 2   n:1 3} 4let b = a; 5 6a.x = a = { 7   n:2 8} 9console.log(a.x)10console.log(b)

提示:对象和函数都是引用类型,都存放在堆中的。

最后

这么硬核的文章,加上骚气的鹿哥讲解,不要放弃手中点赞的权利,相信我,你是最“胖”的!

©著作权归作者所有:来自51CTO博客作者mb5fe1601ede528的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. GitHub的注册,代码仓库的创建,用小乌龟上传代码(个人认为比较适合新
  2. 再来 6 个例子教你重构 Python 代码
  3. 【代码实战】华为应用市场专家在线直播AppGallery Connect 服务
  4. GitHub 热门:别再用 print 输出来调试代码了
  5. Hard 级别难度?桶排序几行代码搞定!
  6. 推荐一个项目:数据结构和算法必知必会的 50 个代码实现
  7. 十大经典排序算法动画与解析,看我就够了!(配代码完全版)
  8. 使用Eclipse实现自定义Jmeter函数助手
  9. 深度好文 |Matplotlib 可视化最有价值的 50 个图表(附完整 Python

随机推荐

  1. Android2.1系统在TOP6410上完美运行
  2. android WebView全屏观看视频 全屏观看直
  3. Android-经常涉及到的权限
  4. [android盈利模式探索]心得分享--Android
  5. Android的IPC机制Binder的详解(转发)
  6. Android(安卓)小項目之---Toast對象詳細
  7. FFmpeg的Android平台移植—编译篇
  8. activity设置背景色为透明
  9. Android 通过WebView来播放flash在线视频
  10. Android Studio中设置ButterKnife、andro