【问题标题】:Correct way to write a javascript closure [closed]编写javascript闭包的正确方法[关闭]
【发布时间】:2014-10-20 11:21:16
【问题描述】:

我正在学习 javascript 闭包。

我有一个函数

function outer(x){
     var y = 10;
     function inner(z){
         return x + y + z;
     }
     console.log(inner(20));
}
outer(30);

我得到的输出是 60。

这是一个很好的闭包例子吗?

【问题讨论】:

标签: javascript


【解决方案1】:

关于闭包有很多误解。 OP 是 词法作用域 的一个示例,即可以访问外部函数变量的“内部”函数。

有些人认为,ECMAScript 中的每个函数都与其外部执行上下文形成一个闭包,但是这个定义并不表示闭包更广泛和更强大的方面。

下面演示了“每个函数都创建一个闭包”的概念。

var x = 'global x';

function foo() {
  console.log(x);
}

function bar() {
  var x = 'local x';
  foo();
}

bar(); // 'global x'

foo 创建时,它的范围被定义并且它可以在全局执行上下文中访问 x。当 bar 被调用时,它会创建一个新的执行上下文并调用 foo。由于 foo 的作用域链是基于它在代码中定义的位置而不是从它被调用的位置创建的,因此它将 x 解析为全局变量而不是全局变量bar 的本地。所以 foo 对包含 x (以及所有其他全局变量)的全局执行上下文有一个闭包。

这展示了 ECMAScript 的词法范围性质和“平凡”的闭包。它没有被利用或允许持续存在,所以它是否真的存在是推测。

闭包更显着的方面是利用它们在创建它们的执行上下文完成后访问局部变量的能力,例如

var foo = (function() {
  var closureVariable = 'foo';
  return function() {
    console.log(closureVariable);
  }
}());

foo();  // 'foo'

在上面,立即调用的函数表达式 (IIFE) 使用名为 closureVariable 的变量创建一个执行上下文,并为其分配一个值。然后它返回一个内部函数对象,该对象在其作用域链上具有此变量。

一旦 IIFE 返回,它的执行上下文仍然可供返回的函数访问(现在由 foo 引用)。正是这种对已完成执行上下文的持续访问允许闭包利用对某些“特权”函数“私有”的共享变量,例如

var bar = (function() {
  var a;
  return {
    setA: function(value) {
            a = value;
    },
    getA: function() {
            return a;
    }
  }
}());

bar.setA(6);
console.log(bar.getA()); // 6 

方法 setAgetA 对创建它们的执行上下文有一个闭包,因此共享对 a 的特权访问。正是这种对原本无法访问的变量的持续访问,才是闭包更重要的特征。

comp.lang.javascript 常见问题解答notes on Closures 有更详尽的解释。

还有 Douglas Crockford 的 Private Members in JavaScript

编辑

上面的内容已经过修改,以合并 comp.lang.javasscript 上关于闭包的长时间讨论的特性:Confusion about closures

【讨论】:

  • 对现有内容的简要回顾似乎表明关于闭包的定义存在一些歧义,特别是函数引用是否必须被持久化或保存在封闭范围之外的某个地方才能被考虑一个关闭。我知道狭义的闭包不是很有趣,并且大多数人使用该术语来指代函数带有其外部范围的情况,但是您是否知道定义的任何明确参考?跨度>
  • 上面的 clj FAQ 参考非常权威(主要作者是 Richard Cornford,搜索他的posts on clj),还有WikipediaA closure…allows a function to access those non-local variables even when invoked outside its immediate lexical scope。我敢肯定还有其他参考资料,但这两个就足够了。
  • @torazaburo — 你让我搜索示例,并在此过程中发现了一个关于该主题的长期被遗忘的线索。谢谢。我已经更新了答案以合并线程中的主题,请随时进一步评论。 :-)
  • 谢谢,很棒的信息。我想底线是“意见不一”。就个人而言,我喜欢“非平凡的封闭”术语。
猜你喜欢
  • 1970-01-01
  • 2013-05-24
  • 2012-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多