繁体   English   中英

Javascript闭包

[英]Javascript Closures

我仍然对JavaScript中的闭包概念感到困惑。 我得到的结论是,闭包是内部函数在母函数返回后访问其母函数中创建的变量的能力。 但我仍然困惑为什么我们必须创建内部函数来保护局部变量,如果我们可以在函数内部创建一个变量?

我们需要创建一个内部函数,以便外部函数返回后外部函数中的变量有一些存在。

考虑一个简单的功能:

function f() {
  var x = 0;
  return ++x; // x=1
} // Once the function has exited then "x" no longer exists.

注意,当程序的控制从“f()”函数的开始流到它的结尾时,变量“x”仅是“活动的”(存活的,存在的)。 但是如果我们在内部函数中包含“x”,那么只要内部函数执行x,它就会存活:

function g() {
  var x = 0;
  return function() {
    // Now "x" will live for as long as this function.
    return ++x;
  }
};
var counter = g();
counter(); // => 1
counter(); // => 2
counter(); // => 3

现在,当我们调用“g()”时,我们得到另一个函数,只要该函数被变量引用,“x”就会激活。

为何使用封闭?

(function(){
    var current_page = 1;
    function previous_page() {
        current_page--;
        // update interface
    }
    function next_page() {
        current_page++;
        // update interface
    }
    // a bit of jQuery, ok?
    $('#previous').click(previous_page);
    $('#next').click(next_page);
})();

看:我们没有全局变量,甚至没有在全局空间中定义的任何函数......但是,我们已经为“#previous”和“#next”按钮的点击事件添加了一个行为,用于分页功能。 如果没有关闭,你会怎么做? 你会如何定义函数内的current_page变量?

您需要使用范围变量创建内部函数的原因是面向对象的封装。 它本质上是私有变量。

变量是“封闭的”。

// constructor function
var myObject = function(message) {
    // private - scope is function level.  It's CLOSED OVER the the inner function (closure).
    //           not delcared as a JSON property so not visible externally
    var value = 0;
    // constructor returns JSON object with public methods
    // always constructed from the myObject var so it always hands back the same instance
    // of the public methods
    return {
        // nested functions have access to outer function variables.
        increment: function (inc) {
            value ++;
        },
        getValue: function() {
            return value;
        },
        // the inner function even has access to the outer function's args!
        getMessage: message
    }
};

看看return语句。 它返回公共接口 - 一些可以访问私有变量的方法,因为它们位于内部函数中。 它使用JavaScripts函数作用域变量来创建面向对象的封装。

之后,我可以这样:

var obj = myObject('Hello World');
obj.increment();
obj.increment();
console.log(obj.getValue());
console.log(obj.getMessage);
// should be undefined
console.log(obj.value);

请注意,此时,使用者无权访问受保护/封装的值或消息。

现在,这里是踢球者 - 对象是可变的,因此调用者可以添加方法甚至替换方法。 所以,你会认为有人可以添加一个暴露内部的方法。 但是,他们不能因为功能范围(关闭 - 他们被关闭)。 只有嵌套函数才能访问外部函数的变量。 因此,如果调用者添加了一个返回内部的方法,则它们无法访问,并且它将是未定义的。

上面的代码输出:

2
Hello World
undefined

作为旁注,我正在使用node.js运行javascript

这是关于使用闭包的模块模式的一篇很好的博客文章:

http://www.yuiblog.com/blog/2007/06/12/module-pattern/

你刚刚回答了你的问题,内部函数保护它的变量。 的jsfiddle

(function outer(){
    var foo = 'bar';
    function inner(){
        var foo = 'OMG NO!';
    }
    alert(foo);//alerts 'bar'
})()

来自MDN CLOSURES

   why to use:

闭包允许您将一些数据(环境)与对该数据进行操作的函数相关联。 这与面向对象编程有明显的相似之处,其中对象允许我们将一些数据(对象的属性)与一个或多个方法相关联。

when not to use

如果特定任务不需要闭包,则在其他函数中不必要地创建函数是不明智的,因为它将在处理速度和内存消耗方面对脚本性能产生负面影响。

例如,在创建新对象/类时,方法通常应与对象的原型相关联,而不是定义到对象构造函数中。 原因是每当调用构造函数时,方法都会被重新分配(即,对于每个对象的创建)。

关于闭包有很多正确的答案,但它总是看起来很技术,而许多人要求可能首先寻找更高级别的简单解释。

我喜欢把它想象成一辆汽车。 当你开车时,有许多复杂的过程正在进行,但普通人不需要平均每天知道这些。 把所有这些复杂性想象成闭合隐藏的“私人”变量,使油门踏板,断路器,换档杆,方向盘等更容易使用。

那么关闭的目的是什么? 隐藏所有复杂的变量,以使脚本更加可用。 如果你每次想要使用脚本中的任何函数时都不得不担心脚本中的每个变量,那很快就会变得非常困难。 YAY CLOSURES!

关键是变量在两个函数之间共享。 如果在内部函数中声明了变量,那么外部函数将无法访问它,因此不会共享它。

如果在内部函数中声明了变量,那么对内部函数的每次调用都会创建一个新变量:前一次调用所做的任何修改都将丢失。

但是如果变量在外部函数中声明,那么对内部函数的多次调用将看到相同的变量,并且一次调用将看到前一次调用的修改,只要它们都作用于外部函数的相同版本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM