【问题标题】:JavaScript Closures example and explanationJavaScript 闭包示例和解释
【发布时间】:2017-08-03 23:23:01
【问题描述】:

我在 codeproject 上找到了这个闭包示例,但它没有解释它是如何工作的。

    function getMultiplier(multiplyBy){
       function multiply(num){
          return multiplyBy * num;
       }
 
       return multiply;
    }
 
    var multiplyByTwo = getMultiplier(2);
    var multiplyByTen = getMultiplier(10);
    var twoIntoFive = multiplyByTwo(5); 
    var tenIntoSix = multiplyByTen(6);  

    console.log(twoIntoFive); // 10
    console.log(tenIntoSix); // 60

现在我将用我的 C 大脑假设正在发生的事情。请纠正我或给出你的解释。

  1. javascript中的函数也可以是对象,所以内部函数multiply(num)是getMultiplier的一个方法,从外面看。
  2. var multiplyByTwo 在使用参数 2 调用时被赋予函数 getMultiplier 的返回值。
  3. 当您调用 getMultiplier(2) 时,javascript 解释器会根据 getMultiplier() 的定义在内存中创建一个对象。
  4. 该对象有一个方法 multiply,它的地址被分配给变量 multiplyByTwo。
  5. var twoIntoFive = multiplyByTwo(5);使用参数 5 调用 getMultiplier(2) 对象的方法 multiply(num)。
  6. 将简单的数字 10 返回到变量 twoIntoFive 中
  7. 乘以二 = 0;将使 javascript 的垃圾收集器从内存中删除对象 getMultiplier(2)。

【问题讨论】:

  • 您可以参考此链接了解更多关于闭包的信息。 developer.mozilla.org/en/docs/Web/JavaScript/Closures
  • 是的。只是 method 在这里被错误地使用(如果它是 js 对象意义上的对象)@downvoter 你是认真的吗??
  • @georg 不必要的关闭。请求重开。链接的问题解释了闭包的工作原理,但没有回答 op 的具体问题。
  • @TomM:这个骗局看起来很详尽,我怀疑有什么新东西要说,但让我们试一试吧!

标签: javascript closures


【解决方案1】:

其实multiply在OOP方面只是一个函数而不是一个方法。

基本上函数是对象,但可以调用。在这种情况下,函数是否是对象不是问题,而是如果您可以交出对函数的引用则更多。这可以通过return multiply 完成。

使用参数值调用getMultiplier 后,该值被存储并返回(并分配)一个函数。

然后你需要调用该函数,该函数的引用存储在multiplyByTwo中。

局部变量multiplyBy用于返回结果。没有创建对象。

【讨论】:

  • 但是 multiplyByTwo 和 multiplyByTen 都引用同一个函数 multiply(num) ,如果内存中没有创建对象, multiply(num) 在哪里得到对应的 multiplyBy 值呢?简单地调用 multiply(num) 的引用将有 multipleBy 未定义。
  • 它为里面的变量生成一个新的局部作用域。通过返回函数,为它保存范围。
  • @b'stard - 不,它们引用了不同的函数。每次调用getMultiplier 时都会创建并返回函数(或对象,如果你想这样称呼它们,它们就是它们)。这样做getMultiplier(2) == getMultiplier(10) - 这是错误的 - 它们是不同的对象
  • 基于 getMultiplier(multiplyBy) 定义的内部变量的新局部范围是内存中的某种对象。但是哪里?它使用什么符号来引用内存中的这个地方?此外,它在内存中创建了其中两个。一个用于 multiplyByTwo,一个用于 multiplyByTen。它们必须是 multiply(num) 可以访问的新对象的符号。内部函数 multiply(num) 的内部表示必须有一些指向 getMultiplier 对象的隐藏指针,就像 C++ 函数有隐藏对象的 this 指针一样。
  • 这可能是语义,但multiply 本身不需要知道getMultiplier,它只需要知道它的本地范围内可用的内容(恰好与调用getMultiplier 时创建的范围)。 JS 运行时显然会跟踪这个作用域,但是我还没有遇到一个引擎可以为你提供访问作用域的机制。
【解决方案2】:

有趣的问题。

  1. 几乎是正确的,除了在基本层面上,实际上在 javascript 中 all functions are objects。此外,查看后两个变量twoIntoFivetenIntoSixmultiply()getMultiplier() 范围内的独立函数(意味着它还包含对该函数内部变量的引用)。

  2. 正是

  3. 正确,但请记住,它与getMultiplier 仍然不同。

  4. 正如this article 中所解释的,javascript 不是创建一个对象,而是创建一个接口,该接口引用函数内已声明的变量。

  5. 这就是它的工作方式。但是twoIntoFive实际上调用了引用getMultiplier()函数参数的返回接口

  6. 正确。

  7. 这是正确的。由于您删除了对接口的引用,它将被删除。

进一步阅读

当有关于 javascript 的问题时,参考 MDN 通常是个好主意。这是迄今为止我读过的最完整的文档。

如果您在我的回答中发现错误或有其他问题,请随时纠正我或提供一些反馈

【讨论】:

  • 我对 3、4 和 5 的看法是错误的。因为 C 没有嵌套函数,我假设 getMultiplier 的对象是在堆上使用它的成员变量创建的,但这并不能让您访问到论点。对嵌套函数的 Pascal 调用在嵌套函数的堆栈帧中有一个附加信息,即指向外部函数堆栈帧的指针。您需要两个指针来调用嵌套函数,它们作为 getMultiplier(multiplyBy) 的返回值传递给 multiplyByTwo。一个用于 getMultiplier(2) 的堆栈帧,另一个用于乘法(num)。
  • 垃圾收集器标记 multiplyByTwo 有对该堆栈帧的引用,并且不会在从 getMultiplier(2) 返回时自动释放它。那么对 multiplyByTwo(5) 的调用等于 multiply(5) 将指针传递给 getMultiplier(2) 的堆栈帧。这就是这里可以说发生的事情吗?
  • 该链接对我不起作用。是的,在声明变量的同时引用和执行函数的能力有点令人困惑,
  • (...) "然后对 multiplyByTwo(5) 的调用等于 multiply(5) 将指针传递给 getMultiplier(2) 的堆栈帧。这可以说是这里发生的事情吗?”我不确定这一点,但当您在调试器中运行脚本时似乎是这样。
  • 这个嵌套函数的解释最适合理解闭包drdobbs.com/architecture-and-design/…
【解决方案3】:

基本上,函数就是函数。我不会说 multiply(num) 是 getMultiplier 的方法,它只是在它的主体中声明。

也许这样更容易理解?

var x = function getMultiplier(multiplyBy){
   var y = function (num){
      return multiplyBy * num;
   }

   return y;
}

无论如何。它的工作方式是:调用 getMultiplier 返回一个函数“乘法”。 multiply 函数返回 multiplyBy * num,但 getMultiplier 返回某种预制乘法函数,其中 multiplyBy 已经被 getMultiplier 的参数替换。

因此,当您调用 getMultiplier(2) 时,您在 multiplyByTwo 变量下得到的是:

function multiply(num){
   return 2 * num;
}

由于 getMultiplier(num) 只是在返回的乘法函数中替换一个参数,因此您可以按字面意思传递任何内容,并且不会删除任何内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    相关资源
    最近更新 更多