我相信我们的 OP 已经尝到了互联网学习的权衡取舍。信息片段的可访问性,但没有指南。不幸的是,我们不知道你知道多少,我们假设很多事情,而那些你知道的事情很少,这些都是先验知识,最终导致了解可怕的 hoisting 是什么。这是典型的how magnets work,我将提供一些关键字来指导您理解 JavaScript。
Creation Stage + Activation aka Code execution Stage = Execution context
好的,但它们分别是什么?
Scope Chain + Creating arguments, functions, variables + value of 'this' keyword = Creation Stage 和
Assigning values and references to functions, then execute the code = Activation aka Code execution Stage
-
创作阶段
- 设置范围链
- 创建将包含变量的对象
- 创建参数对象
- 搜索函数声明并为它们中的每一个在上面的对象上创建具有该名称的属性,如果函数名称存在,则引用指针值将被覆盖
- 搜索变量声明并为它们中的每一个在上面的对象中创建具有该名称的属性,并将其值设置为
undefined。如果名称已经存在,则什么也不做。
-
this 关键字的值已解析。
-
执行阶段,也就是运行代码阶段
- 执行函数 exe
() 并赋值 to this = value is assigned。
代码1按照上面的算法开始逐行执行。
第一阶段:创作阶段
globalExeContext = {
//no scope
objForVariables = {
//no arguments because its no function
// function declarations
b: `points to function`,
// variable declarations
a: `undefined`
},
this: //not important for this example
}
创建阶段就完成了。我们按照上面定义的说明逐行进行。现在我们处于分配= 和执行() 发生的执行阶段。我们再次从第 1 行开始
第二阶段:执行阶段
globalExeContext = {
//no scope
objForVariables = {
//no arguments because its no function
// function declarations
b: `points to function`,
// variable declarations
a: 1 // because we did the `=` on line 1
},
this: //not important for this example
}
然后在第 8 行,我们找到了函数执行,这意味着在全局执行上下文之上创建新的执行上下文,这意味着我们对该函数再次遵循上述算法。
第一阶段:创作阶段
bExeContext = {
// This is the scope object, and in this object now is placed the global exe context we have worked on before
scope: {globalExeContext}
objForVariables = {
//the is arguments object for this one but its empty, because we have no arguments for this function
args:{},
// function declarations are none here
// variable declarations are none here
},
this: //not important for this example
}
现在,我们进入了执行阶段,我们执行() 和=。在第 1 行,它被告知 a = 10,这意味着我们需要找到 a 来为其分配值。但是我们在bExeContext 对象中没有a?现在怎么办?现在我们进入scope 并尝试在那里找到它。果然,在我们的全局空间中有a,现在我们为它分配了10。我们已经覆盖了它。它永远不会是一样的,我会带回 globalExeContext 给你看。
第二阶段:执行阶段
globalExeContext = {
//no scope
objForVariables = {
//no arguments because its no function
// function declarations
b: `points to function`,
// variable declarations
a: 10 // look what you have done
},
this: //not important for this example
}
现在问题解决了,我们返回执行b 函数中的下一行,即console.log(a);。我们需要解决a 是什么,然后重新开始,在b 中搜索什么都没有,但我们在 globalExeStack 中有它。你记得,它是10。所以我们登录10。我们已经到达函数的末尾,它从堆栈中弹出。没有了。
现在我们继续执行全局代码的最后一行:console.log(a);,而且很简单,在 globalExeStack 中有 a。是10。
代码 2 阶段 1:创建阶段。
globalExeContext = {
//no scope
objForVariables = {
//no arguments because its no function
// function declarations
b: `points to function`,
// variable declarations
a: `undefined`
},
this: //not important for this example
}
第 2 阶段:执行阶段 = 和 ()
第一行是一样的
globalExeContext = {
//no scope
objForVariables = {
//no arguments because its no function
// function declarations
b: `points to function`,
// variable declarations
a: 1
},
this: //not important for this example
}
第 8 行告诉执行b 函数。
第一阶段:创作阶段
bExeContext = {
scope: {globalExeContext}
objForVariables = {
//the is arguments object for this one but its empty, because we have no arguments for this function
args:{},
// function declarations
a: `points to function`
// variable declarations are none here
},
this: //not important for this example
}
第二阶段:执行阶段
第 1 行告诉找到 a 并将 10 分配给它。这次我们很幸运,因为a 可以在我们的 bExeContext 中找到。
bExeContext = {
scope: {globalExeContext}
objForVariables = {
//the is arguments object for this one but its empty, because we have no arguments for this function
args:{},
// function declarations
a: 10 // no longer points to `points to function`
// variable declarations are none here
},
this: //not important for this example
}
这意味着我们不必去全局空间寻找a。执行b 函数的第 2 行告诉console.log(a);。我们需要解决a是什么,果然
bExeContext = {
// blablbalblablbalblablblal
// blablbalblablbalblablblalb
a: 10 // no longer points to `points to function`
// blablbalblablbalblablblalb
},
// blablbalblablbalblablblalb
}
我们确实在 bExeContext 上找到了它。我们登录10。我们完成了b 函数的执行,并将其从执行堆栈中弹出。没有了。
我们现在继续评估全局代码。我们完成了第 9 行的b();,现在我们在第 10 行。console.log(a); 要解决a,我们必须先找到它。为了刷新我们的 globalExeContext 的外观,这是最后一张图片:
globalExeContext = {
//no scope
objForVariables = {
//no arguments because its no function
// function declarations
b: `points to function`,
// variable declarations
a: 1
},
this: //not important for this example
}
果然a就是1。我们登录1。我们完成了。
你看,hoisting 只要你运行 JS 代码就实现了。这是放置代码位的过程,如果您愿意,可以将其整理出来。更准确地说是 1.arguments 2.function 声明 3.variable 声明。当您的代码只有几行或一行,或者根本没有任何功能时,就会发生提升,因为一旦您尝试扮演解释器的角色并布置代码,您就完成了提升。