gpt4 book ai didi

javascript - 为什么这个赋值不抛出 ReferenceError?

转载 作者:搜寻专家 更新时间:2023-11-01 04:59:48 25 4
gpt4 key购买 nike

考虑三种情况,其中 ak 都未定义:

if (a) console.log(1); // ReferenceError

var a = k || "value"; // ReferenceError

似乎有道理,但是......

var a = a || "value"; // "value"

为什么最后一个案例没有抛出一个ReferenceErrora 不是在定义之前被引用了吗?

最佳答案

这是因为 var 的一项“功能”称为 hoisting .根据链接:

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code. (emphasis mine)

所以,例如:

console.log(a);
var a = "foo";

由于 a 在定义之前被引用,因此它不会像您预期的那样抛出 ReferenceError,而是记录 undefined。这是因为,如前所述,首先处理声明并且基本上发生在顶部,这意味着它与:

var a;
console.log(a);
a = "foo";

前面提到的函数也是如此:

function foo() {
console.log(a);
var a = "foo";
}

这等同于:

function foo() {
var a;
console.log(a);
a = "foo";
}

要了解原因,请查看 ECMAScript 2015 Language Specification :

13.3.2 Variable Statement

NOTE

A var statement declares variables that are scoped to the running execution context’s VariableEnvironment. Var variables are created when their containing Lexical Environment is instantiated and are initialized to undefined when created.

[...]

A variable defined by a VariableDeclaration with an Initializer is assigned the value of its Initializer’s AssignmentExpression when the VariableDeclaration is executed, not when the variable is created. (emphasis mine)

据此,我们可以了解到,var 声明是在任何代码执行之前创建的(在它们的词法环境中),并且范围限定为包含 VariableEnvironment ,它要么在全局范围内,要么在函数中。它们最初被赋予值 undefined。下一部分解释了 var 赋值的值是执行声明时右侧的值,而不是创建变量时的值。

这适用于您的情况,因为在您的示例中,a 的引用与示例中的一样。使用之前的信息,您的代码:

var a = a || "value";

可以重写为:

var a;
a = a || "value";

请记住,所有声明都是在执行任何代码之前处理的。 JavaScript 引擎发现有一个声明,即变量 a 并将其声明在当前函数或全局范围的顶部。然后它被赋予值 undefined。由于 undefined 是假的,a 被分配给 value

相比之下,您的第二个示例抛出一个ReferenceError:

var a = k || "value";

也可以改写为:

var a;
a = k || "value";

现在你看到问题了。由于 k 从未在任何地方声明过,因此不存在具有该标识符的变量。这意味着,与第一个示例中的 a 不同,k 从未声明并抛出 ReferenceError,因为它在声明之前被引用。

But how do you explain var a = "123"; var a = a || "124"; // a = "123"?

再次来自 ES2015 语言规范:

Within the scope of any VariableEnvironment a common BindingIdentifier may appear in more than one VariableDeclaration but those declarations collective define only one variable.

说白了:变量可以在同一个函数或全局范围内定义不止一次,但总是定义同一个变量。因此,在您的示例中:

var a = "123";
var a = a || "124";

可以重写为:

var a;
a = "123";
a = a || "124";

声明 a 在同一个函数或全局范围内 再次共同只声明一次。 a 被分配给 "123",然后又被分配给 "123" 因为 "123" 是真实。


从 ES2015 开始,在我看来,你应该不再使用 var。它具有函数作用域,可能会导致问题中提到的意外分配。相反,如果您仍然想要可变性,请尝试使用 let:

let a = a || "value";

这将抛出一个ReferenceError。即使所有变量都被提升,无论您使用哪个声明符(varletconst),对于 letconst 引用未初始化的变量是无效的。此外,letconst 具有 block 作用域,而不是函数作用域。这对于其他语言来说更加清晰和正常:

function foo() {
{
var a = 3;
}
console.log(a); //logs 3
}

对比:

function foo() {
{
let a = 3;
}
console.log(a); //ReferenceError
}

关于javascript - 为什么这个赋值不抛出 ReferenceError?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41436194/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com