我正在尽最大努力理解JavaScript闭包。

通过返回一个内部函数,它可以访问直接父函数中定义的任何变量。

这对我有什么用?也许我还没完全搞清楚。我在网上看到的大多数示例都没有提供任何真实的代码,只是一些模糊的示例。

有人能告诉我一个闭包的真实用法吗?

比如这个吗?

var warnUser = function (msg) {
    var calledCount = 0;
    return function() {
       calledCount++;
       alert(msg + '\nYou have been warned ' + calledCount + ' times.');
    };
};

var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();

当前回答

这里我有一个闭包概念的简单例子,我们可以在我们的电子商务网站或其他许多网站上使用它。

我正在添加示例的JSFiddle链接。它包含一个由三种商品组成的小产品清单和一个购物车柜台。

JSFiddle

// Counter closure implemented function; var CartCouter = function(){ var counter = 0; function changeCounter(val){ counter += val } return { increment: function(){ changeCounter(1); }, decrement: function(){ changeCounter(-1); }, value: function(){ return counter; } } } var cartCount = CartCouter(); function updateCart() { document.getElementById('cartcount').innerHTML = cartCount.value(); } var productlist = document.getElementsByClassName('item'); for(var i = 0; i< productlist.length; i++){ productlist[i].addEventListener('click', function(){ if(this.className.indexOf('selected') < 0){ this.className += " selected"; cartCount.increment(); updateCart(); } else{ this.className = this.className.replace("selected", ""); cartCount.decrement(); updateCart(); } }) } .productslist{ padding: 10px; } ul li{ display: inline-block; padding: 5px; border: 1px solid #DDD; text-align: center; width: 25%; cursor: pointer; } .selected{ background-color: #7CFEF0; color: #333; } .cartdiv{ position: relative; float: right; padding: 5px; box-sizing: border-box; border: 1px solid #F1F1F1; } <div> <h3> Practical use of a JavaScript closure concept/private variable. </h3> <div class="cartdiv"> <span id="cartcount">0</span> </div> <div class="productslist"> <ul> <li class="item">Product 1</li> <li class="item">Product 2</li> <li class="item">Product 3</li> </ul> </div> </div>

其他回答

我已经使用闭包做了如下的事情:

a = (function () {
    var privatefunction = function () {
        alert('hello');
    }

    return {
        publicfunction : function () {
            privatefunction();
        }
    }
})();

正如你在那里看到的,a现在是一个对象,它有一个方法publicfunction(a.publicfunction()),它调用privatefunction,它只存在于闭包中。你不能直接调用privatefunction(即a.b ratefunction()),只能调用publicfunction()。

这是一个最小的例子,但也许你可以看到它的用途?我们使用它来强制公共/私有方法。

JavaScript模块模式使用闭包。它的良好模式允许你拥有类似“公共”和“私有”变量的东西。

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function(foo) {
      console.log(foo);
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function(bar) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod(bar);
    }
  };

})();

是的,这是一个有用闭包的好例子。对warnUser的调用在其作用域中创建calledCount变量,并返回一个匿名函数,该函数存储在warnForTamper变量中。因为仍然有一个使用calledCount变量的闭包,所以在函数退出时不会删除它,所以每次调用warnForTamper()都会增加作用域变量并提醒该值。

我在Stack Overflow上看到的最常见的问题是,有人想要“延迟”使用在每次循环中增加的变量,但因为变量是有作用域的,所以对变量的每次引用都是在循环结束后,导致变量的结束状态:

for (var i = 0; i < someVar.length; i++)
    window.setTimeout(function () {
        alert("Value of i was "+i+" when this timer was set" )
    }, 10000);

这将导致每个警报都显示相同的i值,即循环结束时它增加到的值。解决方案是创建一个新的闭包,一个变量的独立作用域。这可以使用一个立即执行的匿名函数来完成,该函数接收变量并将其状态存储为参数:

for (var i = 0; i < someVar.length; i++)
    (function (i) {
        window.setTimeout(function () {
            alert("Value of i was " + i + " when this timer was set")
        }, 10000);
    })(i);

闭包有各种各样的用例。在这里,我将解释闭包概念的最重要的用法。

闭包可以用来创建私有方法和变量,就像面向对象的语言,如java、c++等。一旦你实现了私有方法和变量,你在函数中定义的变量将不能被窗口对象访问。这有助于数据隐藏和数据安全。

const privateClass = () => {
  let name = "sundar";
  function setName(changeName) {
    name = changeName;
  }
  function getName() {
    return name;
  }
  return {
    setName: setName,
    getName: getName,
  };
};

let javaLikeObject = privateClass(); \\ similar to new Class() in OOPS.

console.log(javaLikeObject.getName()); \\this will give sundar
javaLikeObject.setName("suresh");
console.log(javaLikeObject.getName()); \\this will give suresh

另一个关于闭包的现实例子:

创建index . html:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Program with Javascript</title>
  </head>
  <body>
    <p id="first"></p>
    <p id="second"></p>
    <button onclick="applyingConcepts()">Click</button>
    <script src="./index.js"></script>
  </body>
</html>

2)在index.js:

  let count = 0;
  return () => {
    document.getElementById("first").innerHTML = count++;
  };
})();

在本例中,当您单击一个按钮时,计数将在p#id上更新。 注意:您可能想知道这段代码有什么特别之处。检查时,您将注意到不能使用window对象更改count的值。这意味着你已经声明了私有变量count,这样可以防止你的状态被客户端破坏。

解释JavaScript闭包的实际用法

当我们在另一个函数中创建一个函数时,我们是在创建一个闭包。闭包功能强大,因为它们能够读取和操作其外部函数的数据。无论何时调用函数,都会为该调用创建一个新的作用域。在函数内部声明的局部变量属于该作用域,并且只能从该函数访问它们。当函数完成执行时,作用域通常被销毁。

这类函数的一个简单例子是:

function buildName(name) {
    const greeting = "Hello, " + name;
    return greeting;
}

在上面的例子中,函数buildName()声明了一个局部变量greeting并返回它。每次函数调用都会创建一个新的作用域和一个新的局部变量。在函数执行完成后,我们无法再次引用该作用域,因此它被垃圾收集。

但如果我们有一个指向范围的链接呢?

让我们看看下一个函数:

函数buildName(name) { const greeting = "Hello, " + name + " Welcome "; const sayName = function() { console.log(问候); }; 返回sayName; } const sayMyName = buildName("Mandeep"); sayMyName ();//你好,曼迪普

本例中的sayName()函数是一个闭包。sayName()函数有自己的局部作用域(变量welcome),也可以访问外部(封闭)函数的作用域。在本例中,是来自buildName()的greeting变量。

在执行buildName之后,在本例中不会销毁作用域。sayMyName()函数仍然可以访问它,因此它不会被垃圾收集。但是,除了闭包之外,没有其他从外部作用域访问数据的方法。闭包充当全局上下文和外部作用域之间的网关。