我知道what is the temporal dead zone(TDZ),但我无法理解它存在的目的。
任何人都可以解释为什么它被创造出来了吗?
提出ReferenceError或SyntaxError而不是返回undefined的逻辑是什么?
的ReferenceError:
console.log(typeof foo);
let foo;
语法错误:
let foo;
let foo;
未定义:
console.log(typeof foo);
答案 0 :(得分:2)
在初始化之前使用变量始终是一个错误。使这个错误是合理的,因为它有助于开发人员注意到他们的错误并能够修复它。 var
以undefined
开头的行为已经导致了太多问题,如果将const
变量或静态类型注释用于相似的语义,它们会变得更糟。
答案 1 :(得分:2)
从定义变量开始就存在变量是有意义的。由于外部作用域中的变量可以在嵌套作用域内访问,因此以下代码非常混乱:
var foo = 'out';
function bar () {
foo = 'in';
console.log(foo);
var foo;
}
bar();
bar()
函数有什么作用?它创建了一个名为foo的新变量,并在它显示在控制台中之前为其分配'in'
。之后,来自外部范围的变量仍然等于'out'
。因此,在使用变量之前定义变量是一个更聪明的事情。我相信你可以在声明之前使用变量只是一个实现简单和效率的问题,但我在这里大胆猜测。
但是,在JS中,使用var
关键字创建的变量可以从其函数中访问,而不是从块中访问。这允许更宽松的语法,如下所示:
function setGameMode (mode) {
if (mode === 'peaceful') {
var count = 0;
for (var i = 0; i < mobs.length; ++i) {
if (mobs[i] instanceOf EvilMob) {
mobs[i].despawn();
++count;
}
}
console.log('Removed ' + count+ ' evil mobs out of ' + i);
mobSpawner.evil = false;
} else if (mode ==='chaotic') {
var count = 0;
for (var i = 0; i < mobs.length; ++i) {
if (mobs[i] instanceOf NiceMob) {
mobs[i].despawn();
++count;
}
}
console.log('Removed ' + count + ' nice mobs out of ' + i);
mobSpawner.nice = false;
}
}
由于函数范围的变量,{for循环后i
变量仍然存在。这也是var
关键字允许您定义变量两次的原因。如果你被迫只写一次var
,那就不切实际了。使用let
变量时,这个“松散”功能变得毫无用处,因为这些变量应该在不再需要时立即释放。
当您在大多数编程语言中调用函数时,执行环境会在内存中为您需要的变量创建一个空间。在这里,没有办法在不实际运行代码的情况下判断是否需要变量i
,因为它位于if块内。但是,由于JS具有函数范围的变量,因此必须从函数的开头创建变量。在let
变量的情况下,不需要这样做。
至于typeof someundefinedvar
返回'undefined'背后的原因,那是因为你需要一种方法来检查可能已经在外部范围内声明的变量。但是,对于块作用域的变量,您不需要该功能。 let
变量意味着立即使用并丢弃。
答案 2 :(得分:0)
console.log(typeof a);
let a;
在上面的陈述中,您没有定义变量a
,而您正在使用它。在java脚本中,有必要定义一个变量。该变量是您的值的参考因此,这就是为什么显示未定义的参考错误。
let a;
let a;
在第二个语句中,您已经定义了两次变量。 js不允许您将任何变量多次定义到相同的块范围内。
console.log(typeof foo);
在第3个语句中,因为它在第一个函数中显示错误,即您的变量未定义。默认情况下,它是未定义的。你可以使用未定义的变量。
答案 3 :(得分:0)
如果你检查了你在问题中链接的那些例外的文档,你可以看到为什么,我认为这里没有提到。
首先要注意的是:值得一提的是,在版本3之前,EMCAScript中不存在例外情况.var显然早于这种语言功能。 为什么 var和let不同主要是因为引入let时异常可用,而不是在引入var时。这段历史强调了这一切。 1999年也是忙碌的一年!
无论如何,进入齿轮。看看这里发生了什么:
// example A
(function () {
console.log(somethingUndefined - 1);
var somethingUndefined;
console.log('another operation');
})();
错误,然后代码继续。我们可以抓住这个并处理它吗?
// example B
(function () {
try {
console.log(somethingUndefined - 1);
var somethingUndefined = 50;
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here');
return;
}
console.log('plowing on');
})();
不。
在幕后,此代码如下所示:
// example C
(function () {
var somethingUndefined = undefined;
try {
console.log(somethingUndefined - 1);
somethingUndefined = 50;
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here');
return;
}
console.log('plowing on');
})();
没有“暂时死区”,因为例B和B中没有任何意义。 C变量somethingUndefined
不是什么的。这是一种“未定义”,somethingUndefined === undefined
,这不是什么都没有。然后它是50,但为时已晚,无法发挥作用。有用与否,我们可以用它来做事,因为它有价值。第1行,第8行,它始终具有某些值。比较输出的差异:
// example D
(function () {
try {
console.log(somethingUndeclared - 1);
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here');
console.log(e);
}
})();
在示例D中的每一点,somethingUndeclared
都不算什么。这是一个永远死亡的区域。我不确定上面的代码开始抛出异常的哪个EMCAScript版本,但它不会因此而破坏,因为这种情况总是会出错。
除非在同一范围的某些其他部分或父范围somethingUndeclared
已定义,否则可能出于某些其他目的。或者代码var somethingUndeclared;
可能由于某种原因而在范围或父范围内的某处放置,因此在上面的代码中没有抛出任何异常。这是几乎完全使用let或const的论据。
当你使用let或const时,有一个“死区”,一个什么时候它不是什么东西,那么它就是某种东西。它不是undefined
,等待发生是一个例外。在let语句到达之前,它就像一个未声明的变量,抛出异常,然后在声明行中它就像一个带有值的var。它是var的行为与未声明变量的结果的混合。
// example D
(function () { // temporal dead zone, something is nothing
try { // temporal dead zone, something is nothing
console.log(something - 1); // exceptional behavior! temporal dead zone
let something = 50; // temporal live zone begins here!
console.log('another operation');
} catch (e) {
console.log('I want to deal with problems here'); // you could call this a dead zone
console.log(e); // dead
}
// dead
})(); // way dead
这让我们接受了乞求的问题,“为什么不拉开乐队,为了语言的一致性而处理BC休息?”答案是因为足够好就足够了。有数百万行javascript管理手风琴和图像画廊以及其他UI铃声和口哨声。当EMCAScript填补关键任务角色时,可以选择更成熟的一组语言功能。或者你只是不喜欢草率的代码为您的甜选项卡导航。语言的一致性并不值得打破所有代码,这些代码足以完成大多数时间所需的代码。想象一下已经积累的足够好的山脉,因为它甚至可以用这种语言抛出异常('99)。
当我们需要它做它应该做的事情时,我们可以利用这些功能。当undefined = 100;
成为项目中某个文件的灾难时,我们可以选择加入异常。当渐进增强失败并且我们没有工具提示时,我们有一个不太好的用户体验,而不是我们希望的。我们肩膀上有不同的历史和不同的重量,所以他们可能总是采取不同的行动。