正确的方式来编写一个javascript闭包

时间:2014-08-27 01:29:47

标签: javascript

我正在学习javascript闭包。

我有一个功能

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

我得到输出为60.

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

1 个答案:

答案 0 :(得分:2)

关于闭包存在很多误解。 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 

方法 setA getA 对创建它们的执行上下文有一个闭包,因此具有对 a 的共享特权访问权限。正是持续存在对其他无法访问的变量的访问,这是闭包的重要特征。

关于comp.lang.javascript常见问题notes on Closures,有一个更为详尽的解释。

还有Douglas Crockford的Private Members in JavaScript

修改

以上内容已经过修改,其中包含了对comp.lang.javasscript:Confusion about closures上的闭包的详细讨论。