当前位置:主页 > 查看内容

(大厂面试题)使用第一性原理推导---JS中代码是怎么运行的

发布时间:2021-07-25 00:00| 位朋友查看

简介:大厂面试题使用第一性原理推导—JS中代码是怎么运行的 前言 自从接触“第一性原理”这个词在网上被吹得神乎其神。可是它到底是什么我还没认真考究过。直到今天通过浏览各位大佬的博文对第一性原理有了点自己的理解。今天就和大家分享以下两点: 我对“第一性……

(大厂面试题)使用第一性原理推导—JS中代码是怎么运行的

前言

自从接触“第一性原理”,这个词在网上被吹得神乎其神。可是它到底是什么?我还没认真考究过。直到今天,通过浏览各位大佬的博文,对第一性原理有了点自己的理解。今天就和大家分享以下两点:

  1. 我对“第一性原理”的理解
  2. 从第一性原理的角度聊一聊JS中代码是怎么运行的

什么是第一性原理

当我看到下面马斯克这段话的完整译文,才终于把握到了“第一性原理”的实质,这令人膜拜的“第一性原理”,不就是“解耦合(decoupling)”吗?

捕获.PNG

  • 要搞清楚这个概念,我们不妨试想,我们作为开发人员,希望改进一款开源软件产品的功能,你会怎么做?

    你会打开一个新的空白源代码文件,从头开始,一行行的写代码吗?
    基本上不会。那你会怎么做呢?
    你会读现有软件的源代码,把新的功能实现补充或更新到对应的位置,提交合并请求
    在这个过程中,我们都是把前人做的东西作为基础层,而后再在这个层次上,去叠加新的内容。


  • 如果大家还没有理解,我们不妨再思考一个问题:为什么现在数据科学这么火热?Python、R和机器学习框架为何这么受到欢迎?甚至让很多非IT人士也在乐此不疲地渴望学习、应用它们?

    因为有许许多多的开发者,已经为你写好了实现数据科学工作的各项基本功能。相关的软件包已有成千上 万,而且每天还在不停快速涌现。你根本不需要了解哪些功能究竟是如何实现出来的,只要会搜软件、查文档,直接“拿来主义”调用就能实现酷炫繁复的功能,方便得令人发指。


  • 现在,大家再试想一下:如果之前的前提都不成立了呢?假设你目前的工作做所依赖的基础层级存在问题呢?

    这就比如“品牌假货”的存在,大家都痛恨假货,但是原本品牌的存在,就会减低大家识别商品质量的成本。如果一个案例中,两种事物同时出现,总会被我们脑补为必然的关联,于是就耦合在一起了。你不难感受到,耦合的结果是非常不利于创新的。而所谓的“第一性原理”,即是一种“解耦合”的思维方式

如何使用“第一性原理”思考-JS中代码是怎么运行的

  • 由第一性原理,可推出一下结论和问题
  1. 代码一定是逐行运行的
  2. 分为编译阶段执行阶段,先后顺序
  3. 编译阶段发生了什么?
  4. 执行阶段执行了什么?
  5. 代码运行时,变量是如何查找的?
showName()//函数的执行
var showName = function(){ // 抛去后面的函数赋值看,这其实就是一个变量声明加一个变量赋值
    console.log(2)
}
function showName(){ //函数的声明
    console.log(1)
}
showName()//函数的执行(调用)
  • 接下来通过以这段代码的运行过程为例,探讨所有的问题

  • 要探讨编译阶段和执行阶段都发生了什么,不妨将上述代码分为以下两个部分:

图.png

  • 由上图所示,我们可以看到这段代码真正的运行顺序:先进行函数和变量声明提升,在编译阶段进行变量和函数声明,创建scope对象,执行上下文{showName},为执行阶段准备好执行环境。在执行阶段执行函数调用、变量赋值操作。

  • 通过以上的推导,在JS中处于基础层级最重要的几个概念也就浮出来水面。下面带大家粗略的了解下这几个概念

声明提升

  • 什么是声明提升?

    • 是指在JS代码执行中,Javascript引擎(V8),把变量的声明部分和函数的声明部分提升到代码开头的行为,变量提升后,会给变量设置默认值undefined
  • 变量声明提升

    • 以下述代码为例:
    console.log(showName)// undefined
    var showName = 'Aaron_hj'
    console.log(showName)// Aaron_hj
    

    我们不难看出,在第一个打印showName处,变量showName还未声明,但此处不会报错,而是打印值undefined。这就是变量声明提升:变量在声明前已经可用。 实际上,代码运行顺序是:

    var showName; //变量声明提升
    console.log(showName);// undefined
    showName = 'Aaron_hj'// 赋值
    console.log(showName) //Aaron_hj
    

    注意:声明提前是在JavaScript引擎的预编译时进行,是在代码开始运行之前。并且,只有声明提升,赋值仍在原处

  • 函数声明提升

    • 以下述代码为例:
    showName()// 函数的执行(调用)
    function showName(){ // 函数的声明
    console.log(1)
    

    我们不难看出,在调用showName()处,函数showName()还未声明,但该代码片仍能正常运行。这就是函数声明提升:函数声明语句可以被提升到外部脚本或者外部函数作用域的顶部。 实际上,代码运行顺序是:

    function showName(){ // 函数的声明
    console.log(1)}
    showName()// 函数的执行(调用)
    

    注意:虽然函数声明和变量声明都会被提升,但是函数会首先被提升,然后才是变量。

作用域

  • 变量作用域

    • 变量作用域指变量可以起作用的范围
    • 变量又可分为全局变量,局部变量
      1. 全局变量在全局都有作用
      2. 局部变量只在函数作用域内起作用
      3. 所有不使用var定义的变量都视为全局变量
        注意:在函数体内,同名的局部变量或者参数的优先级会高于全局变量。也就是说,如果函数内存在和全局变量同名的局部变量或者参数,那么全局变量将会被局部变量覆盖。
  • 函数作用域

    • 函数作用域是指在函数内声明的所有变量在函数体内始终有定义。再结合声明提升的概念,可理解为Javascript函数中的var声明的变量都被提前到函数体的顶部。(注意:只有声明会提升到函数体的顶部,变量赋值操作仍留在原来的位置)

执行上下文

  • 执行上下文是一个Javascript中最基础,但同时也是最重要的概念。每当控制器转到执行阶段代码时,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域,每个函数执行时,都会给对应的函数创建这样一个执行环境。 因此在一个Javascript程序中,必定会产生多个执行上下文。Javascipt引擎会以栈的方式来处理他们,称之为函数调用栈。栈底永远时全局上下文,而栈顶则是正在执行的上下文。为了更加清晰地理解这个过程,根据下面的示例代码,结合图示给大家展示。
var name = 'Aaron_hj';
function showName(){
var anotherName = 'Aaron';
function swapName(){
    var tmpName = anotherName;
    anothorName = name
    name = tmpName;
}
swapName();
}
showName();

无标题.png

第一步:全局上下文入栈
第二步:showName的执行上下文入栈
第三步:swapName的执行上下文入栈
第四步:swapName的执行上下文出栈
第五步:showName的执行上下文出栈
全局上下文在浏览器窗口关闭后出栈

注意:函数中,运行到return会直接终止函数可执行代码的执行,因此会直接将当前上下文弹出栈

  • 总结
    • 详细了解了这个过程之后,我们就可以对执行上下文总结一些结论了。
      1. 单线程
      2. 同步执行,只有栈顶的上下文处于执行中,其他上下文需要等待
      3. 全局上下文只有唯一的一个,它在浏览器关闭时出栈
      4. 函数的执行上下文的个数没有限制
      5. 每次某个函数被调用,就会有个新的执行上下文为其创建,即使是调用的自身函数,也是如此。
        注:本博文旨在和大家分享博主自己的理解,欢迎大家来评论区一起讨论学习~)
;原文链接:https://blog.csdn.net/hsingle/article/details/115774236
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:Vue专题(一)聊一聊双向绑定 下一篇:没有了

推荐图文


随机推荐