本文主要对 Arindam Paul - JavaScript VM internals, EventLoop, Async and ScopeChains视频做个总结。虽然英语水平很差,几乎听不懂这位大佬在说什么。但是我会猜啊?。接下来就把我所猜到的内容分享给大家。
Question:What make programming interesting? Answer:主要有以下2点。 1)Programming is more like art than science。Programming 并不像普遍的科学那样:有着固定的步骤,一成不变。不同Programmer在programming时,会因为对事物认知方式的不同而采用不同的编写方式和编写策略(即使面对的是 同样的task)。 2)Programming就像下象棋一样:虽然了解规则并花不了多少时间,但是 如果想下的相对高明点就需要花费极其多的时间去琢磨 每步的细节,用意,以及对整场游戏的后续影响。从这点上来看:programming更像是艺术一样,需要雕琢。 嗯,好有道理的样子?,上次骗我去柬埔寨讨老婆,现在又想骗我给你打一辈子工,哼?。
Agenda:
1)JavaScript Interpretation and Memory Model
2) Compilation and Variable Hoisting
3) Function Execution
4) Scope Chains and Closure
5) Javascript Runtime and Event Loop
6) Async Example
7) Single threaded parallel execution
对于以上这些内容,仅猜到了2,4两点(虽然听不懂大佬讲些什么,但就是觉得讲得牛掰?)。接下来正式展开 所猜到的内容。
Compilation and Variable Hoisting
Function Execution
这意味着:
编译时 对所有代码进行逐行检测 。检测到所有的var(var当然也包括函数的定义,但是不包括赋值表达式右侧的函数定义),并分配存储空间。
执行时 遇到未var声明的变量时 沿着scope chain向上查找该变量的定义。如果在scope chain上找到该变量,不再分配存储空间。如果找到global scope时 仍然没有该变量 就在global scope为该变量分配存储空间。
注意是先编译后执行,编译时为所有的变量的定义 分配好存储空间(函数的定义也视作var声明),要区分compilation phase和execution phase。并且编译也不是一次性完成的,每当遇到要执行的函数时,会对要执行的函数进行编译。因此编译和执行时交叉进行的。
下面来看具体的例子,代码如图1所示。
1.png
编译顺序1,2,3,4,18,19,20。Compilation of the main block done(此时不会进入函数f内进行编译)。只有var a,f分配了存储空间。如图2。
2.png
执行顺序1,2,3,4,18,19,20。执行到line 2时,沿scope chain查找,未找到b的var声明,就在global scope中为b分配存储空间。接着执行f(1),为函数f创建local heap memory
。
执行f(1)时,再compile函数f(函数f的形参变量z 视作是var声明了的。同样地,在compile函数f时,不会进入函数g内进行编译)。需要注意的是:line17在函数f的编译阶段被分配存储空间(这也就是variable hoisting
)。结果如3。
3.png
执行函数f阶段,line5 line6在当前函数f的scope中找不到变量b,c,会沿scope chain向上查找。在global scope找到了变量b。在global scope 没找到变量c(于是在global scope创建变量c)。在函数f的执行阶段 执行到line8时,会在当前函数f的scope中找到var e(并给var e赋值)。执行到line16时,会compile函数g,为函数g分配heap memory。结果如图4。
4.png
类似地,在函数g的编译阶段结束后,结果如图5。 Note:变量的查找是沿scope chain查找的。这也是图5中 绿字的原因。
5.png
执行完line20后,结果如图6。
6.png
接下来看个类似但更深入的例子,如图7。
7.png
跳过不重要的步骤,只关心我们感兴趣的地方。执行完line21后,结果如图8。
8.png
去掉garbage collected的,如图9。
9.png
函数f的scope没有被garbage collected的原因是:myG指向Lamda “g”,并可能通过myG调用g。而执行g时,是需要scope chain作为环境的。所以在scope chain上的函数f的scope是不该也不能被garbage collected。(Scope chain is nothing but Copy of [[scope]] from the definition to the invocation。如图10)到现在为止,闭包closure大概就不难懂了。
10.png
Closure的表现形式如图11。
11.png
什么是closure?如图12。
12.png
需要注意的是:Closure is used and copied as the "outer environment reference" when the funtion is run.
(每当函数被调用执行时,函数所在的scope chain就会再次被复制。这么翻译可能不太恰当。)
implicit closure, explicit closure示例 如图13,14。
13.png
14.png
原创作品,转载请注明出处