likes
comments
collection
share

重新认知一下作用域和作用域链:新手向

作者站长头像
站长
· 阅读数 36

浏览器怎么就认识我的写的东西

既然是新手向的东西,那么我们抛开 CPU、寄存器、内存、加载指令、存取指令这些概念。

主要是我的不懂

语言有高级语言和低级语言之分。这个是相对于我们人类而言的。高级语言JavaScript、C、C++、PhP等,容易记住和识别,和我们平时说话的逻辑相似,所以是个人都可以转行做程序员。低级语言010101的,没什么人能够记得住,但是电脑就可以秒懂。

咦?高级的东西不应该更加难懂么?这两个的划分是不是反过来了?

重新认知一下作用域和作用域链:新手向

对于浏览器而言,它也只认识低级语言。所以想让它看得明白我们写的JS。就需要的翻译器。这个翻译器可以是chrome的V8引擎,Webkit的JavaScriptCore。

重新认知一下作用域和作用域链:新手向

大家都知道JS是解释性语言。也就是说,你写的每一段代码没有任何改变的给到了浏览器。当浏览器想要运行的代码的前一刻,你们双方还是认识的。也就是课本上所说的:一边解释一边执行

而这个过程会有如下的阶段:

重新认知一下作用域和作用域链:新手向
  • 词法分析:将语法分析称一个最小单位,也叫token, 将这个token解析翻译成AST。检查是否有低级错误,比如多了一个<括号,少了一个分号等等。
  • 预编译:准备各种需要运行的环境。这也是我们要弄明白作用域的根本步骤。这个阶段它做了如下的工作:
    1. 创建AO(GO)对象
    2. 找形参和变量声明,将形参和变量名作为AO(GO)属性名,此时值为undefind
    3. 实参和形参合并
    4. 在函数体里面找函数声明,值赋予函数体。
  • 解释执行:又上到下一次执行。

所以说,函数的操作在预编译阶段就已经开始了。

内容来源《你不知道的JavaScript》

预编译和作用域

在简单了解了预编预干的事情之后,我们来看看它对于函数体做了什么。先来看看下面这段代码:

let 蚂蚱 = '马路边'

function 小区() {
    function 家() {
      console.log(蚂蚱)
    }
   家()
}
小区()

上面的代码毋庸置疑,打印的结果是马路边。假设蚂蚱是我儿子,在家找不到他的话,就去小区里面抓,小区还找不到,就出小区找。最终在小区外围的马路边找到了。并揍了他一顿。

我寻找的路径就是作用域链。家、小区就是一个个作用域。只是一个作用域有大有小。

我寻找的过程就是代码执行的过程,而确定小区是包裹着家这种常识的是预编译阶段干的事情。

不可能我家里面有一个小区吧?广东包租公?

重新认知一下作用域和作用域链:新手向

我们知道预编译是分为全局预编译和局部预编译的,每一个函数体在执行前一刻都经过局部预编译(立即执行函数?)。而全局预编预只执行一次,发生在发生在页面加载完成时

下面是上边代码片段的执行过程。

重新认知一下作用域和作用域链:新手向

当执行的console.log(蚂蚱)的时候,就会寻着作用域由下往上找,最终在GO上找到。如下图:

重新认知一下作用域和作用域链:新手向

进阶一下,看看下面这串代码片段:

let a = 10;
function foo() {
  consolo.log(a)
}

function sum() {
  let a = 20;
  foo()
}

sum()

只有理解了预编译阶段偷偷摸摸干了啥才知道这个打印的是什么?

函数作用域是在预编译阶段决定的,所以说不管你函数在什么位置调用,它的上级函数作用域都是不会变的。

所以说,打印的是10。而不是20。你学废了吗?

转载自:https://juejin.cn/post/7202987088152182841
评论
请登录