【问题标题】:Javascript Couldn't understand a trick variable "hoisting": why it's NaN value?Javascript 无法理解“提升”的技巧变量:为什么它是 NaN 值?
【发布时间】:2016-07-27 13:47:38
【问题描述】:

我尝试了 JavaScript 来理解它的提升策略,但更加困惑:

function f(i){this.i+=i}
i=2
f(3)
console.log(i)

输出

5

(1) 这是我的预期。然后我尝试重新定位“i=2”语句:

function f(i){this.i+=i}
f(3)
console.log(i)
i=2

输出

NaN

(2) 为什么会这样?我期望因为“i”被提升到整个程序的前面,为什么它会打印“NaN”?一个可能的答案是,程序被编译器重构为:

var i
function f(i){this.i+=i}
f(3)
console.log(i)
i=2

(3) 所以当“console.log(i)”时,i没有被赋值,所以是“NaN”--->但是我尝试了下面的程序:

function f(i){this.i+=i}
f(3)
i=2
console.log(i)

如果上面的解释是正确的,我希望这也应该输出“NaN”。但实际上它输出

2

这更奇怪。在这种情况下,“提升”是否有效?

(4) 更有趣的是,如果我将程序更改为:

var i
function f(i){this.i+=i}
f(3)
console.log(i)
i=2

然后输出

undefined

这是为什么呢?

(5) 对于程序:

var i
function f(i){this.i+=i}
f(3)
i=2
console.log(i)

再次输出

2

您能否解释一下上述观察结果,因为它真的来自我对“提升”是什么的理解?

【问题讨论】:

  • 在 3) 和 5) 中,您在执行 console.log(i) 之前定义了 i = 2,这就是它显示为 2 的原因。
  • 您似乎将“提升”与“上下文”和“范围”混为一谈。
  • 值得指出的是,您从未在函数f(i) 中实际使用过参数ithis.i 将引用调用函数的任何对象,但 i 将引用参数。这些不一定是同一个对象。

标签: javascript function variables scope hoisting


【解决方案1】:

作为@zzzzBov has pointed out,这与提升无关,与上下文范围有关,特别是在非严格模式环境中。

function f(i){this.i+=i}
i=2
f(3)
console.log(i)

i=2 等同于window.i=2。由于这是在非严格模式下,thiswindow,所以this.i+=i 等价于window.i+=i,其中右边的i 由函数参数提供。所以这应该可以解释5 的输出。

function f(i){this.i+=i}
f(3)
console.log(i)
i=2

这里唯一的区别是i=2this.i+=i之后执行。向未声明的变量添加数字会按预期生成NaN

var i
function f(i){this.i+=i}
f(3)
console.log(i)
i=2

这里,var i 附加到 window 范围,因为这是在非严格模式下,所以 this.i+=i 正在将一个数字添加到已声明但未初始化的值 window.i,这仍会导致 @ 987654341@.

var i
function f(i){this.i+=i}
f(3)
i=2
console.log(i)

在这里,希望很明显。 i=2 将覆盖之前发生的任何事情(在本例中为 isNaN(i)===true

有什么问题吗?下课了。

【讨论】:

  • “运行代码 sn-p”的东西太棒了!你做了什么把它嵌入到这里?谢谢!!!
  • @Paurian i.stack.imgur.com/LWzth.png 在回答时单击突出显示的按钮以添加所谓的“堆栈 sn-p”
【解决方案2】:

要记住的一件非常重要的事情是,Javascript 只会提升函数声明,而不是在调用函数时。

function f(i) { ... } //will be hoisted
f(2); //won't be hoisted

继续……

我试图重新定位“i=2”语句...它输出NaN...这是为什么呢?我预计因为“i”被提升到整个程序的前面,为什么它会打印“NaN”?

function f(i){this.i+=i}
f(3) //the function executes i = undefined+3, which is NaN
console.log(i) //i is logged, which is currently NaN
i=2 //i has the value of 2 assigned to it

这会输出NaN,因为当undefined 的变量被视为Number 时,它会变成NaN

我希望这也应该输出“NaN”。但实际上它输出的是2 这更奇怪了。在这种情况下,“提升”是否有效?

function f(i){this.i+=i}
f(3) //the function executes i = undefined+3, which is NaN
i=2 //i has the value of 2 assigned to it
console.log(i) //i is logged, which is currently 2

这会输出 2,因为在 i 被记录之前,i 被分配了 2 的值。

...它输出undefined这是为什么?

var i //i is undefined
function f(i){this.i+=i} //f is hoisted and is line 1
f(3) //the function assigns (undefined + 3) to a variable which is never referenced
console.log(i) //i is logged, which is currently undefined
i=2 //i has the value of 2 assigned to it

这会输出 undefined,因为 i 在被记录之前从未分配过值。

再次输出2

var i //i is undefined
function f(i){this.i+=i} //f is hoisted and is line 1
f(3) //the function assigns (undefined + 3) to a variable which is never referenced
i=2 //i has the value of 2 assigned to it
console.log(i) //i is logged, which is currently 2

这会输出 2,因为在 i 被记录之前,i 被分配了 2 的值。

【讨论】:

    【解决方案3】:

    仅仅因为 i 被定义,并不意味着它具有数据类型。在 JavaScript 中,只有少数几种数据类型,Number 就是其中之一。

    如果没有事先赋值,函数就无法知道您是在使用“重载”加操作数中的数字还是字符串。

    使用提升,它不会阻止指令流,只是在变量声明发生的地方。如果一个变量没有初始化,它在第一次赋值之前一直是一个无类型变量。

    【讨论】:

    • “函数无法知道您使用的是数字还是字符串” - 这与为什么它是 NaN 无关。函数不必“知道”任何东西。 JavaScript 只是定义了添加 undefined 的数字类型为 NaN,故事结束。 JavaScript 中也没有“重载”,只有一组明确定义的规则,用于在将不同类型的对象添加在一起时进行隐式类型转换。 JavaScript 变量确实在声明但未初始化时有一个类型,它是undefinedtypeof undefined === "undefined".
    • 我意识到“过载”是一个糟糕的术语(我尝试引用它来说明这一点,但应该使用更好的术语)。我不知道如何描述 plus 操作数不是 unitasker 并且可以使用字符串和数字。感谢您的澄清。
    猜你喜欢
    • 2015-11-27
    • 2021-12-23
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    • 2010-09-30
    相关资源
    最近更新 更多