【问题标题】:Why do these two functions have different results?(Sorry, I don't know how to describe them)为什么这两个函数有不同的结果?(对不起,我不知道如何描述它们)
【发布时间】:2021-04-15 10:43:36
【问题描述】:

我有两个问题

  1. counter1()counter1()() 有什么区别?
    counter1 不是已经是函数名了吗?为什么是第二个()

  2. 为什么counter2可以记忆数值?

这是我的代码:

const counter1 = function(){
  let initValue = 0
  return function(){
    initValue++;
    return initValue
  }
}

const counter2 = (function(){
  let initValue = 0
  return function(){
    initValue++;
    return initValue
  }
})()

console.log(counter1());
console.log(counter1()());
console.log(counter1()());
console.log(counter2());
console.log(counter2());

这是输出

【问题讨论】:

标签: javascript iife


【解决方案1】:

counter1 是一个返回函数的函数,也就是所谓的higher-order function

为了便于讨论,让innerCounter1counter1 的返回值的名称。因此,以下代码与您的示例中的代码等效。

 const counter1 = function(){
   let initValue = 0
   const innerCounter1 = function(){
     initValue++;
     return initValue
   }
   return innerCounter1;
 }

counter1 不是已经是函数名了吗?为什么是第二个 ()?

是的,counter1 是一个函数,但它也返回一个函数。通过将返回值命名为innerCounter1,我希望可以清楚地知道当你调用counter1()时,你得到的值是innerCounter1。而当你调用innerCounter1()时,你得到的值就是号码initValue。所以counter1()() 正在获取innerCounter1 的值并在一个简短的表达式中调用该内部函数。

为什么counter2可以记忆数值?

当一个函数被创建时(在你的例子中是innerCounter1),并且函数引用了在函数之外定义的值(在你的例子中是initValue),一个closure被创建了,你可以直观的理解为“记忆”变量。 counter1()counter2这两个函数都记住了这个值,但是这里要注意的是,每次调用counter1()时,局部变量(initValueinnerCounter1)都是独立的。例如:

let counter1A = counter1();
let counter1B = counter1();

counter1A(); // 1
counter1A(); // 2
counter1B(); // 1
counter1B(); // 2

换句话说,counter1Acounter1B 记住了一个单独的 initValue 变量,因此调用一个变量不会影响另一个变量。

counter2的这个定义:let counter2 = counter1();,和你上面的匿名函数语法是等价的,所以应该清楚,发生的事情和我上面解释的counter1A完全一样。

【讨论】:

  • 非常感谢。这真的很详细。也感谢您的编辑。
【解决方案2】:

JS 中,您可以从function 返回一个函数,然后可以在您想要的任何地方使用,添加:返回的函数仍然可以访问定义它的变量(可以访问其词法范围变量)此功能称为闭包。

请仔细阅读带有代码的注释

const counter1 = function () {
    let initValue = 0
    return function () {
        initValue++;
        return initValue
    }
}
/**
 * is the same as
 */
function counter1() {
    let initValue = 0

    /** this function is returned */
    return function () {
        /** 
         * and can access the variable `initValue` at run time because at auth time its scope is inside 
         * the `counter1` scope where the variable is defined in
         * (because inner scope can access outer scope defined in them)
         * 
         */
        initValue++;
        return initValue
    }
}
/**
 * as for using counter1
 * in each time we call the `counter1` we get a reference to the inner anonymous function that has 
 * access to that variable but in each call we have new `initValue` variable that's why 
 * no matter how many times you call `counter1` you keep getting the same result because you have new 
 * `initValue` for each call 
 */





const counter2 = (function () {
    let initValue = 0
    return function () {
        initValue++;
        return initValue
    }
})()
/**
 * this form of defining a function and immediately executing it called IIEF(Immediately invoked function expression)
 * 
 * what this code is executed you have counter2 which is equal to the inner function returned from the outer function expression
 * 
 */

// naming anonymous functions for easing
const counter2 = (function IIFE_counter2() {

    let initValue = 0

    return function counter2_returned_function() {
        initValue++;
        return initValue
    }
})()

/**
 * no counter2 = counter2_returned_function
 *
 * so
 * 1- it can access `initValue` each time it's called
 * 2- for each call of counter2 we are not creating new instance of `IIFE_counter2` instead we just call the inner
 * `counter2_returned_function` which still have the old value of `initValue` and can update it successfully
 */

请阅读YDKJS 以获取有关此主题的更多经验 https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch7.md

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-11
    • 2020-08-17
    • 1970-01-01
    • 2019-08-21
    • 2014-02-03
    • 2023-03-22
    • 2013-11-14
    • 2021-04-09
    相关资源
    最近更新 更多