重新认知一下作用域和作用域链:新手向
浏览器怎么就认识我的写的东西
既然是新手向的东西,那么我们抛开 CPU、寄存器、内存、加载指令、存取指令这些概念。
主要是我的不懂
语言有高级语言和低级语言之分。这个是相对于我们人类而言的。高级语言JavaScript、C、C++、PhP
等,容易记住和识别,和我们平时说话的逻辑相似,所以是个人都可以转行做程序员。低级语言010101
的,没什么人能够记得住,但是电脑就可以秒懂。
咦?高级的东西不应该更加难懂么?这两个的划分是不是反过来了?

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

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

- 词法分析:将语法分析称一个最小单位,也叫token, 将这个token解析翻译成AST。检查是否有低级错误,比如多了一个
<
括号,少了一个分号等等。 - 预编译:准备各种需要运行的环境。这也是我们要弄明白作用域的根本步骤。这个阶段它做了如下的工作:
- 创建AO(GO)对象
- 找形参和变量声明,将形参和变量名作为AO(GO)属性名,此时值为undefind
- 实参和形参合并
- 在函数体里面找函数声明,值赋予函数体。
- 解释执行:又上到下一次执行。
所以说,函数的操作在预编译阶段就已经开始了。
内容来源《你不知道的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