【问题标题】:Why does my function call only work when the function is an expression and not when it's a function declaration?为什么我的函数调用仅在函数是表达式而不是函数声明时才起作用?
【发布时间】:2020-06-15 23:15:07
【问题描述】:

了解闭包后,我编写了一个函数,该函数返回一个将名称打印到控制台的函数:

let myName = 'steven';

function printName() {
  console.log(`OUTER: ${myName}`);
  return function printAgain() {
    console.log(`INNER: ${myName}`);
  };
}

printName(); //Only prints 'OUTER: steven'

const newFunc = printName();

newFunc(); //Prints 'OUTER: steven' 
          //AND 'INNER: steven'

为什么只有在使用函数表达式时才调用内部函数?为什么当我用 printName() 而不是第二个调用函数声明时,它只运行外部控制台日志?

类似地,如果我调用我的函数表达式newFunc 而不使用括号,它只会打印OUTER: steven。 但是,如果我使用括号并将其命名为newFunc(),它会同时打印OUTER: stevenINNER: steven。这是为什么呢?

【问题讨论】:

    标签: javascript closures function-declaration function-expression


    【解决方案1】:
    newFunc(); //Prints 'OUTER: steven' 
              //AND 'INNER: steven'
    

    您的 cmets 不太正确。在这里它们是固定的:

    printName(); //Only prints 'OUTER: steven'
    
    const newFunc = printName(); //Only prints 'OUTER: steven' 
    
    newFunc(); //Only prints 'INNER: steven'
    

    当您调用printName() 时,外部函数运行并命中第一个日志语句。然后创建并返回一个新函数。内部函数不会自动发生任何事情;这完全取决于你之后如何处理它。

    在您的第一个示例中,您从未对返回的函数做任何事情。由于您不调用返回的函数,因此它不会执行,因此不会记录任何内容。在第二个示例中,您 do 对返回的函数执行某些操作,将其保存到变量中,然后调用它。通过调用它,您会导致它记录第二条消息

    注意:是否将新函数分配给变量实际上并不重要,只需调用它即可。以下将打印出两个日志语句:

    printName()();
    

    【讨论】:

    • 非常感谢!当您在上面示例中的 printName()() 等函数的末尾使用两组括号时,是否有一个术语?这样做只是不好的做法吗?
    • 函数返回函数的做法称为“高阶函数”。我不知道当你把他们两个背靠背叫的时候。这不是自动的坏习惯,它只取决于你的目标是什么。通常,高阶函数的用处在于您可以创建内部函数,然后多次重用它。只有将其分配给变量时,这才有效。如果你不需要,那么就没有必要这样做。
    【解决方案2】:

    看来你在这里误解了一些事情。在您的示例中:

    function printName() {
      console.log(`OUTER: ${myName}`);
      return function printAgain() {
        console.log(`INNER: ${myName}`);
      };
    }
    

    “外部”函数printName 在执行时记录"OUTER" 字符串。此执行也恰好返回一个新函数,即“内部”函数。这会在执行时记录"INNER" 字符串。

    所以,单步执行剩下的原始代码:

    printName(); //Only prints 'OUTER: steven'
    

    这会执行外部函数,因此会记录您记下的输出。它还返回一个新函数,但是由于您没有将其分配给变量或以其他方式对其进行任何操作,因此我们没有观察到这一点。请注意,如果您要执行这个返回的函数,例如printName()(),您会看到打印出"OUTER",然后是"INNER"

    这正是你接下来要做的,尽管分两个阶段:

    const newFunc = printName();
    
    newFunc(); //Prints 'OUTER: steven' 
              //AND 'INNER: steven'
    

    您的总体效果是正确的,但不是每行都在做什么。 "OUTER" 输出来自const newFunc = printName(),它执行printNamenewFunc() 然后调用返回的函数 - 内部函数 - 并因此记录 "INNER" 输出。

    在这种情况下,这与您使用函数声明还是函数表达式无关。

    【讨论】:

      【解决方案3】:

      printName() 做了两件事:

      1) 它console.logs 是全局变量myName的值。

      2) 它returns 是一个名为printAgain 的函数。

      你调用printName()是因为你想给const newFunc赋值(上面提到的第2项),但是你必须意识到每次你调用printName()它的console.log都会被调用(上述第 1 项)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-25
        • 2012-12-31
        • 2019-07-09
        • 2017-09-27
        相关资源
        最近更新 更多