我相信我们的OP已经尝到了网络学习的权衡。虽然可以访问大量信息,但缺少指导。不幸的是,我们不知道您知道多少,并且我们假设许多事情,并且这些是您所知道的一些先验知识,最终导致对可怕的“提升”是什么有所了解。这就是典型的磁铁如何工作,因此,我将提供一些关键词,应该作为JavaScript理解的指南。
创建阶段
+ 激活(也称代码执行)阶段
= 执行上下文
好的,但这些都是什么?
作用域链
+ 创建参数、函数、变量
+ 'this'关键字的值
= 创建阶段
为函数分配值和引用,然后执行代码
= 激活(也称代码执行)阶段
创建阶段
- 设置作用域链
- 创建包含变量的对象
- 创建参数对象
- 搜索函数声明,对于每个函数声明,在上述对象中创建具有该名称的属性,如果函数名存在,则引用指针值将被覆盖
- 搜索变量声明,对于每个变量声明,在上述对象中创建具有该名称的属性,并将其值设置为
undefined
。如果名称已经存在,则不执行任何操作。
this
关键字的值被解析。
执行阶段,也称为运行代码阶段
- 执行函数
()
并将值分配给this = value is assigned
。
代码1按照上述算法逐行开始执行。
阶段1:创建阶段
globalExeContext = {
objForVariables = {
b: `points to function`,
a: `undefined`
},
this:
}
创建阶段已完成。我们按照上面定义的指令逐行进行了操作。现在我们进入执行阶段,其中包括赋值=
和执行()
。再次从第一行开始执行。
第二阶段:执行阶段
globalExeContext = {
objForVariables = {
b: `points to function`,
a: 1
},
this:
}
然后在第8行,我们发现了函数执行,这意味着在全局执行上下文的顶部创建新的执行上下文,这意味着我们针对该函数再次遵循上述算法。
阶段1:创建阶段
bExeContext = {
scope: {globalExeContext}
objForVariables = {
args:{},
},
this:
}
现在,我们已经进入执行阶段,在这个阶段我们会使用()
和=
。在第一行中告诉我们a = 10
,这意味着我们需要找到a
并将值赋给它。但是我们在bExeContext
对象中没有a
怎么办?现在我们进入scope
并尝试在其中找到它。果然,在我们的全局空间中有a
,现在我们将10分配给它。我们已经覆盖了它。它将永远不会再是同样的,我将带回globalExeContext来向您展示。
阶段2:执行阶段
globalExeContext = {
objForVariables = {
b: `points to function`,
a: 10
},
this:
}
现在问题已经解决,我们回到执行我们
b
函数中的下一行,即
console.log(a);
。我们需要解决
a
是什么,再次搜索
b
没有找到,但我们在globalExeStack中有它。你记得,它是
10
。所以我们记录
10
。我们已经到达函数的末尾,它从堆栈中弹出。它不再存在。
现在我们恢复执行全局代码的最后一行:
console.log(a);
,很容易,在globalExeStack中有
a
。它是
10
。
代码2第1阶段:创建阶段。
globalExeContext = {
objForVariables = {
b: `points to function`,
a: `undefined`
},
this:
}
第二阶段:执行阶段=
和()
第一行与原文相同
globalExeContext = {
objForVariables = {
b: `points to function`,
a: 1
},
this:
}
第8行指示执行b
函数。
阶段1:创建阶段
bExeContext = {
scope: {globalExeContext}
objForVariables = {
args:{},
a: `points to function`
},
this:
}
阶段2:执行阶段
第1行指示查找a
并将10
赋值给它。这次我们很幸运,因为a
可以在我们的bExeContext中找到。
bExeContext = {
scope: {globalExeContext}
objForVariables = {
args:{},
a: 10
},
this:
}
这意味着我们不必去全局空间找a
。执行b
函数的第2行告诉我们console.log(a);
。我们需要解决a
是什么,确保它正确。
bExeContext = {
a: 10
},
}
我们在bExeContext中找到了它。我们记录10
。我们执行完b
函数并将其从执行堆栈中弹出。它不再存在。
现在我们恢复评估全局代码。我们完成了第9行的b();
,现在我们在第10行。console.log(a);
为了解析a
,我们必须先找到它。为了刷新我们的globalExeContext是什么样子,这是最后一张图片:
globalExeContext = {
objForVariables = {
b: `points to function`,
a: 1
},
this:
}
果然,a
是 1
。我们记录下了 1
。完成了。
你看,提升
是在运行JS代码时实现的。它是将代码位排序的过程,更准确地说,是1.参数 2.函数声明 3.变量声明。当你的代码只有几行或一行,或者根本没有任何函数时,提升就会发生,因为当你尝试扮演解释器并布置代码时,你已经进行了提升。
b
中只有一个声明:即函数a
的声明。 - Sebastian Simon