【问题标题】:Why is variable definition not hoisted in JS but function为什么在JS中没有提升变量定义而是函数
【发布时间】:2020-02-28 23:12:06
【问题描述】:

我正在学习 JS,我很好奇为什么一个函数可以在定义之前被调用并且运行良好。我知道这是由于提升,其中代码被预先扫描以在范围内引入声明的变量和函数。

如果只是将这些实体的声明纳入范围,为什么函数调用在其定义之前被调用时也不返回 undefined(或类似的东西)——就像变量一样?

【问题讨论】:

  • 可能用于代码组织目的。您可以在文件底部定义一个函数并在顶部调用它。但是用变量来做这件事就没那么有意义了。虽然我不能说这是设计时使用的确切推理。
  • 另外,只是指出 - 变量定义被提升。这就是为什么你得到undefined 而不是ReferenceError: <variable> is not defined。直到实际的var variable = "some value" 行才处理分配。
  • 第一条评论是有道理的,但我不同意第二条。在这个语句中“var x = 5;”如果 x 之前被访问过,它会说 undefined ;这意味着没有提升确切的定义。因为它没有给出参考错误,我会说它是被提升的声明。因为如果语句是“var x”
  • @nikel 我认为第二条评论是正确的。 var 声明被提升,分配没有。
  • @VLAZ 我认为您总体上是对的,但是如果该变量引用了一个函数,则该变量将有意义

标签: javascript function variables hoisting


【解决方案1】:

正如 VLAZ 在评论中指出的那样,变量定义也被提升了。考虑这个例子:

console.log(a) // undefined 
a = 2
console.log(a) // 2
var a
console.log(b) // ReferenceError: b is not defined

我们可以说undefined 大约是变量a 的值。函数声明以相同的方式提升,但函数表达式不是:

foo() // foo
bar() // TypeError: bar is not a function

function foo () { 
  console.log('foo')
}

var bar = function () {
  console.log('bar')
}

【讨论】:

    【解决方案2】:

    区别在于var声明是VariableDeclaration,而function关键字声明是FunctionDeclaration

    FunctionDeclaration 是一起提升的,与 VariableDeclaration 不同的是,它有一个 body 字段,其中包含函数的主体。您可以使用ESLint parser 发现这种差异。

    这就是为什么:

    someFunc();
    
    function someFunc(){ console.log('someFunc'); } // hoisted as FunctionDeclaration
    var someOtherFunc = () => {console.log('someOtherFunc');}; // not hoisted because the value of the variable is a function expression
    var someNewFunc = function () {console.log('someNewFunc');}; // not hoisted because the value of the variable is a function expression
    
    someOtherFunc();
    someNewFunc();
    

    【讨论】:

    • 这不太正确。 var 声明被提升到封闭范围的顶部,const 没有。在分配执行之前,两者都是undefined
    • 你是对的,但我具体解释的是变量声明的提升与函数声明的提升,并指出,除了函数声明之外,函数体不会出现在任何地方。我在这里看到了混乱,因此将第二个声明更改为 var。
    • 是的,但是您通过添加const 增加了概念空间,这不是问题
    • @AluanHaddad 实际上,const 声明 被提升了。不是初始化。 myVar = 5; let myVar 引发错误的原因是因为它知道 let myVar 存在于范围更小的范围内。该信息来自于提升声明。它是未提升的初始化阶段,仅发生在let myVar 行。这就是为什么错误消息在初始化之前读取can't access lexical declaration myVar' - 它不是初始化。如果它根本没有声明,错误消息将是myVar is not defined
    • 这是一个很好的说明,我很感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 2018-03-10
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多