我已经玩ES6一段时间了,我注意到虽然声明的变量var按预期提升了......
console.log(typeof name); // undefined
var name = "John";
Run Code Online (Sandbox Code Playgroud)
... 用吊装声明let或const似乎有一些问题的变量:
console.log(typeof name); // ReferenceError
let name = "John";
Run Code Online (Sandbox Code Playgroud)
和
console.log(typeof name); // ReferenceError
const name = "John";
Run Code Online (Sandbox Code Playgroud)
这是否意味着变量声明let或未声明const?这是怎么回事?这个问题let和const这个问题有什么区别吗?
我刚刚阅读了一篇关于Ben Cherry的JavaScript范围和提升的精彩文章,其中他给出了以下示例:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Run Code Online (Sandbox Code Playgroud)
使用上面的代码,浏览器将发出"1"警报.
我仍然不确定它为什么会返回"1".他说的一些事情就像是:所有的功能声明都被提升到顶部.您可以使用函数来调整变量的范围.仍然没有为我点击.
我遇到了JavaScript'hoisting',我没有弄清楚这段代码是如何起作用的:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Run Code Online (Sandbox Code Playgroud)
我知道像(function a() {})这样的函数声明将被提升到函数b作用域的顶部,但是它不应该覆盖a(因为函数声明覆盖变量声明而不是变量初始化)的值,所以我期望警报的值会是10而不是1 !!
为什么JavaScript提升变量?
设计师决定实施吊装时的理由是什么?还有其他流行语言吗?
请提供文档和/或记录的相关链接.
JavaScript程序由语句和函数声明组成.执行JavaScript程序时,会执行以下两个步骤:
扫描代码以查找函数声明和每个函数.声明是"执行"(通过创建一个函数对象),并创建一个对该函数的命名引用(以便可以在语句中调用此函数)
语句按顺序执行(评估)(因为它们出现在代码中)
因此,这很好用:
<script>
foo();
function foo() {
return;
}
</script>
Run Code Online (Sandbox Code Playgroud)
虽然"foo"函数在声明之前被调用,但它起作用,因为函数声明在语句之前被计算.
但是,这不起作用:
<script>
foo();
</script>
<script>
function foo() {
return;
}
</script>
Run Code Online (Sandbox Code Playgroud)
抛出ReferenceError("foo未定义").这导致得出结论,Web页面的HTML代码中的每个SCRIPT元素代表一个单独的JavaScript程序,并且每次HTML解析器遇到SCRIPT元素时,它都会执行该元素内的程序(然后一旦程序执行,解析器转到SCRIPT元素后面的HTML代码.
然后,这确实有效:
<script>
function foo() {
return;
}
</script>
<script>
foo();
</script>
Run Code Online (Sandbox Code Playgroud)
我的理解是Global对象(在全局执行上下文中充当Variable对象)始终存在(并保持),因此第一个JavaScript程序将创建函数对象并为其创建引用,然后第二个JavaScript程序将使用该引用来调用该函数.因此,所有JavaScript程序(在单个Web页面中)"使用"相同的Global对象,并且随后运行的所有JavaScript程序都可以观察到一个JavaScript程序对Global对象所做的所有更改.
现在,请注意这个......
<script>
// assuming that foo is not defined
foo();
alert(1);
</script>
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,警报调用将不会执行,因为"foo()"语句抛出一个ReferenceError(它打破了整个JavaScript程序),因此,所有后续语句都不会执行.
但是,在这种情况下......
<script>
// assuming that foo is not defined
foo();
</script>
<script>
alert(1);
</script>
Run Code Online (Sandbox Code Playgroud)
现在,警报调用确实已执行.第一个JavaScript程序抛出一个ReferenceError(并因此中断),但第二个JavaScript程序正常运行.当然,浏览器会报告错误(尽管它在错误发生后确实执行了后续的JavaScript程序).
现在,我的结论是:
请事实查看这篇文章并告诉我是否有错误. …
Ben Cherry的优秀文章充分阐述了JavaScript中的提升.然而,我的问题是,我不能为这个臭名昭着的混淆犯罪者设想一个用例.请解释是否存在实际利用此语言功能的设计模式.
其次,是JavaScript独有的范围提升?
更新 ---我正在为满足我的好奇心的答案添加赏金:哪种设计模式实际上利用了JavaScript的提升行为?我理解为什么 JavaScript支持提升,但我想知道如何利用这个功能.
我知道在新的ES6模块语法中,JavaScript引擎不必评估代码以了解所有导入/导出,它只会解析它并"知道"要加载的内容.
这听起来像是在吊装.ES6模块是否悬挂?如果是这样,它们会在运行代码之前加载吗?
这段代码可以吗?
import myFunc1 from 'externalModule1';
myFunc2();
if (Math.random()>0.5) {
import myFunc2 from 'externalModule2';
}
Run Code Online (Sandbox Code Playgroud) alert(myVar1);
return false;
var myVar1;
Run Code Online (Sandbox Code Playgroud)
上面的代码在IE,FF和Opera中引发错误,说明return语句必须进入函数.但它undefined在Safari和Chrome中有效(显示).
上面的代码已经在全球范围内编写.在所有功能之外.
任何原因?
我不完全理解为什么以下显示"悬挂"到最后.
var x = 'set';
var y = function ()
{
// WHAT YOU DON'T SEE -> var x;
// is effectively "hoisted" to this line!
if (!x)
{
// You might expect the variable to be populated at this point...it is not
// though, so this block executes
var x = 'hoisted';
}
alert(x);
}
//... and this call causes an alert to display "hoisted"
y();
Run Code Online (Sandbox Code Playgroud)
任何指针将不胜感激.
我被问到一个问题
{
function foo() {
console.log('A');
}
foo();
foo = 1;
function foo() {
console.log('B');
}
foo = 2;
console.log(foo);
}
console.log(foo);Run Code Online (Sandbox Code Playgroud)
为什么第三个输出是1而不是2?
不应该foo创建块作用域,因为该块中既没有let也没有const。但是第二个foo输出2意味着确实foo已经创建了另一个引用。
到底是怎么回事?
PS 我正在使用 Chrome
Version 89.0.4389.90 (Official Build) (x86_64)。
hoisting ×10
javascript ×10
ecmascript-6 ×2
scope ×2
browser ×1
const ×1
es6-modules ×1
let ×1
scoping ×1