abstract-of-JavaScript-???

一天不装逼,就难受。本来还想装一下,但是打开 ecma-262 自己就绝望了;没有猴年马月不可能看一遍。只好自己举栗子来说明一下JavaScript中的原型,作用域……

栗子(一)

example 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var ILoveU = 'are you kidding?';

function helloWorld(argc, argv){
"use strict";

var BBC = "2B";

function worldCup2018 () {
var no10 = "Messi";
debugger; //停在这里,我们随便看看;你用其他方法调试也可以。
return BBC;
}

worldCup2018();

return null;//不小心把这句删除了,后面截图注意这里,无大碍。
}

helloWorld(1, "holy shit!");

这里不会用什么奇技淫巧,注重基本概念的理解。我不会定义一个这个的函数 function shit(shit){var shit; return shit;}。这ecma-262发展太快了。不断有新的特性加入,还有概念上的改名。先有个简单的理解,以后再慢慢细化。

我们让栗子(一)跑起来,用Chrome 【版本 67.0.3396.99(正式版本) (64 位)】吧,我觉得灰常好用(我搞不懂,IE11在win7上跑,反正很难用,我也不想截图了)。

先粗略的过一遍,直观的感受一下。

  1. 我们第一个要看的就是 Call Stack

在 Call Stack 中,最底下的(anonymous)就是大伙说的 global Execution Context,我们的源代码就在这里面运行。其中定义一个变量,一个函数,然后到了 19行,调用了helloWorld,就产生了新的 helloWord-EC;里面定义了一个”2B”变量,一个函数,再到14行调用了worldCup2018,产生了worldCup2018-EC。

这种Stack数据结构哪里都有它的身影,什么push,pop……

瞅了一眼ecma-262,哎,真是复杂……你只要记住,调用函数就会产生一个新的数据结构EC就得了(至于第一个global-EC怎么产生的?还有没有其他方法产生?我们后面会有所涉及)。

爱因斯坦:「如果你无法向6岁小孩解释它,那代表你自己也不明白。」
对这句话,我是深表怀疑。老爱真的说过?鸡汤喝多了,不好。该下功夫的地方还是自己出力,我还想一个月让小孩长到20岁那么大呢。谈不上什么对错,看山是山,看山不是山,看山还是山,不多说了。

  1. 假设,我们让代码停在第一行(怎么停?踩刹车啊!自己去改改)。我有句话不知当讲不当讲?这个点,其实挺重要的。此时已经进入了global-EC。但是在进入之前,V8(或者其他引擎)会创建好 global object(到底怎么弄的?我也不知道,或许我说的就是错的,但是 global object 得有)。这是什么东东?
    简单说,global object上面挂了很多东西,比如 Infinity,NaN,parseInt,Number,Object,Map,Promise……。记住,是在执行代码之前创建的global object。管你有没有代码,都有这东西。浏览器执行你的代码,产生global-EC,上面说了这是一个重要的数据结构,要存很多值。情况没有我们想的那么简单,但是复杂的情况我们不考虑,呵呵(不管你我理解对错,你我的代码都能运行,或许还很完美。你没养过猪,但是会吃红烧肉啊!)。

3. fuck ecma-262。我们还是来说global-EC,我们只看Realm部分。
> Before it is evaluated, all ECMAScript code must be associated with a realm. Conceptually, a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code that is loaded within the scope of that global environment, and other associated state and resources.
把 global object挂上去, global Environment Record也挂上去。
我他妈还以为自己在实现ecma-262呢!

  1. 看着我们的代码,我们还是来说global-EC,(我不知道EC这个数据结构各个部分该叫什么名字,网上有叫VariableObject/ActiveObject,ScopeChain,thisValue的)。我也不打算起什么名字了。放个图,看吧。

此时Scope里面就一个Global,Global上挂了global object,还有各种乱七八糟的属性;注意ILoveU: undefined 和 helloWorld: f helloWorld(argc, argv)。此时我们的代码还在第一行。这也就是进入EC的时候,初始化阶段;然后才是执行代码。(明白这两个阶段,你就能明白什么时候一个名字绑定了你所期望的值。)

  • 初始化阶段,把var,FD都存入当前环境,也就是Scope的Global中。var的变量ILoveU,名字存进去,值是undefined。FD helloWorld名字也存进去,值就是一个函数对象。(FD、FE、NFE、FS自便查找)(注意:Scope,GLobal是当前我用的调试器中的。不必在意这些名字。只需记住有个数据结构存储环境即可。就是你一眼看过全局代码,有些名字需要存起来。)this被设置为 Global,此时就是window。

Scope,这个词,我不知道为什么很多地方都叫作用域。我还是觉得环境更准确。任何程序的运行,都必须有外界提供一个初始环境。硬件给操作系统提供,操作系统给各种游戏、浏览器提供,浏览器给JS代码提供。不管是外环境还是内环境,都是事物发展所必须的。你说个人名“王麻子”,你的小伙伴就知道你在说“隔壁老王”,而不是说公元前666年的老王;小伙伴们都默认了一个小环境;如果没有环境,什么都说不清。当然,如果你隔壁两边都住的“王麻子”,就需要提供更多的信息,才能区分你说的左隔壁还是右隔壁老王。

还有一点很重要,我们点击看到helloWorld,能看到[[Scopes]]。这个是干啥用的?先不管干啥用的,它的值,记录了定义时环境。helloWord哪里定义的,global-EC中啊,所以它的[[Scopes]]值就是global-EC的Scope,这里是含有一个元素的数组的形式,也就是[Global]。

  • 执行阶段,好的,那我就一步一步执行即可。第一行代码,执行完毕。ILoveU: "are you kidding?";然后就到了17行 helloWorld(1, "holy shit!"); ,那么我们继续执行。欧,我们进入helloWord-EC了。

我们不扯乱七八糟的名称了。直接撸代码。

  1. 那我们就来看看helloWord-EC。
  • 初始化阶段,这个是函数调用产生的EC,比global-EC多了参数,但还是要构建环境。在局部环境Local里存argc: 1, argv: "holy shit!", BBC: undefined, worldCup2018: f worldCup2018(), this: undefined,实际应该还有arguments对象,不过Chrome浏览器显示的数据应该都是优化过的。(后面会稍稍提及。)helloWord产生了Local,再加helloWord的[[Scopes]]共同构成了此时的Scope。注意,我用了"use strict";,就是不想过多涉及this,我觉得 this is not important, at least for now, it’s irrelevant. 如果没有strict,this会被设置为window。 worldCup2018的[[Scopes]]就是helloWord-EC的Scope,也就是[Closure (helloWorld), Global]。

  • 执行阶段,走一步瞧瞧,BBC: "2B",我们又来到了14行worldCup2018();,没啥可说的,继续走起。

  1. 那我们就来看看worldCup2018-EC。
  • 初始化阶段,初始化局部环境Local,外加它自己(worldCup2018)的[[Scopes]],构成此时的Scope。你或许很纳闷,Closure (helloWorld)里面只有一个BBC: "2B",其实这里应该是最少显示了,显示多余的没卵用。worldCup2018有一句return BBC,仅仅用到了Closure (helloWorld)中的BBC,如果用到了 helloWorld的argc,这里也会显示;如果连BBC也没有用到,Chrome这里就不会有Closure (helloWorld),直接优化掉了。因为此时,Closure (helloWorld)对worldCup2018来说就是多余的,但是挂在那里也是可以的。(比如你在worldCup2018里面再定义一个函数并且此函数用到了BBC,再调用一下此函数,那么Closure (helloWorld)对worldCup2018就不能优化掉。)

  • 执行阶段,没什么可说的。

我们该回去了。没必要再定义66层函数了。三层,我都感觉多了。我脑子不够用。

注意看 Call Stack。

Look,我们退出了worldCup2018-EC。时间不早了,继续走。

退出了helloWord-EC。

退出了global-EC(global-EC应该是程序关闭了才退出。调试器在这里插了一脚,这里应该与调试有关)。

回家吃饭吧。
本来打算几句话讲讲prototype,scope。到现在却感觉Call Stack,尤其EC都说的很乱。改天补充吧。