我正在尽最大努力理解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();

当前回答

我正在尝试学习闭包,我认为我创建的示例是一个实际的用例。您可以运行一个代码片段并在控制台中查看结果。

我们有两个不同的用户,他们拥有不同的数据。它们中的每一个都可以看到实际的状态并进行更新。

function createUserWarningData(user) { const data = { name: user, numberOfWarnings: 0, }; function addWarning() { data.numberOfWarnings = data.numberOfWarnings + 1; } function getUserData() { console.log(data); return data; } return { getUserData: getUserData, addWarning: addWarning, }; } const user1 = createUserWarningData("Thomas"); const user2 = createUserWarningData("Alex"); //USER 1 user1.getUserData(); // Returning data user object user1.addWarning(); // Add one warning to specific user user1.getUserData(); // Returning data user object //USER2 user2.getUserData(); // Returning data user object user2.addWarning(); // Add one warning to specific user user2.addWarning(); // Add one warning to specific user user2.getUserData(); // Returning data user object

其他回答

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

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

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

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

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

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

我正在添加示例的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>

闭包的另一个常见用途是将方法中的this绑定到特定对象,允许在其他地方调用它(例如作为事件处理程序)。

function bind(obj, method) {
    if (typeof method == 'string') {
        method = obj[method];
    }
    return function () {
        method.apply(obj, arguments);
    }
}
...
document.body.addEventListener('mousemove', bind(watcher, 'follow'), true);

每当鼠标移动事件触发时,都会调用watch .follow(evt)。

闭包也是高阶函数的重要组成部分,通过参数化不同部分,可以将多个相似函数重写为一个高阶函数,这是非常常见的模式。举个抽象的例子,

foo_a = function (...) {A a B}
foo_b = function (...) {A b B}
foo_c = function (...) {A c B}

就变成了

fooer = function (x) {
    return function (...) {A x B}
}

其中A和B不是语法单位,而是源代码字符串(不是字符串字面量)。

具体示例请参见“用函数简化我的javascript”。

闭包的使用:

闭包是JavaScript最强大的特性之一。JavaScript允许函数嵌套,并授予内部函数对外部函数中定义的所有变量和函数的完全访问权(以及外部函数可以访问的所有其他变量和函数)。但是,外部函数不能访问内部函数内部定义的变量和函数。

这为内部函数的变量提供了一种安全性。此外,由于内部函数可以访问外部函数的作用域,如果内部函数能够在外部函数的生命周期之后继续存在,那么外部函数中定义的变量和函数将比外部函数本身的生命周期更长。当内部函数以某种方式对外部函数之外的任何作用域可用时,就会创建闭包。

例子:

<script>
var createPet = function(name) {
  var sex;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    },
    
    getSex: function() {
      return sex;
    },
    
    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
console.log(pet.getName());                  // Vivie

console.log(pet.setName("Oliver"));   
console.log(pet.setSex("male"));
console.log(pet.getSex());                   // male
console.log(pet.getName());                  // Oliver
</script>

在上面的代码中,外部函数的name变量可以被内部函数访问,除了通过内部函数,没有其他方法访问内部变量。内部函数的内部变量充当内部函数的安全存储。它们保存“持久的”但安全的数据,供内部函数使用。这些函数甚至不需要赋值给变量,也不需要有名称。 详情请阅读此处。

在给定的示例中,所包含的变量'counter'的值是受保护的,只能使用给定的函数(自增,自减)来更改。因为它在闭包中,

var MyCounter =函数(){ Var计数器= 0; 返回{ 增量:函数(){返回计数器+= 1;}, 递减:函数(){返回计数器= 1;}, 获取:函数(){返回计数器;} }; }; var x = MyCounter(); / /或 var y = MyCounter(); 警报(x.get ());/ / 0 警报(x.increment ());/ / 1 警报(x.increment ());/ / 2 警报(y.increment ());/ / 1 警报(x.get ());// x仍然是2