如何向某人解释JavaScript关闭,知道它们所构成的概念(例如功能、变量等),但不了解关闭本身?

我已经在维基百科上看到了图表的例子,但不幸的是,它没有帮助。


当前回答

下面的简单例子涵盖了JavaScript关闭的所有主要点。

下面是一家工厂,生产可以添加和复制的计算机:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

关键点:每个呼叫做_计算机创建一个新的本地变量n,该计算机的添加和复制功能在做_计算机返回后很长时间仍然可用。

内部函数,如添加和加倍,其访问变量在外部函数中声明**,被称为关闭。

这是几乎所有的关闭。

此分類上一篇


* 例如,它涵盖了在另一个答案中提供的“关闭为Dummies”文章中的所有点,除了例子6,这简单地表明,变量可以在被宣布之前使用,这是一个很好的事实,但完全与关闭无关。

** 任何外部功能,如果有几种是无缝的,甚至在全球背景下,因为这个答案清楚地表明。

其他回答

我相信更短的解释,所以看下面的图像。

此分類上一篇

函数 f1()..> 光红盒

函数 f2()..> 红小盒子

在这里,我们有两个功能,f1()和f2()。f2()是内部到f1()。f1()有一个变量, var x = 10.

在引用函数f1(),f2()可以访问 var x = 10 的值。

这里是代码:

function f1() {
    var x=10;

    function f2() {
        console.log(x)
    }

    return f2

}
f1()

f1 ) 请求:

此分類上一篇

也许我们应该切断你的27岁的朋友,因为整个“关闭”的概念是(!)...... voodoo!

我意思的是:(a)你不直觉地期望它......(b)当有人花时间向你解释它时,你肯定不会期望它工作!

当你终于意识到这样的事情是可能的,那么......肯定......任何人的后事实反应会是:“whoa-a-a(!)...... kew-el-l-l...(!!!)”

直觉给了你很多完全可靠的期望,这样的事情会“当然,绝对是无意义的,因此是完全不可能的。

正如我所说的那样,“这就是伏地。

var foo = function() {
  alert("Hello World!");
};

var bar = function(arg) {
  return arg;
};

bar(foo)();

function add(value1, value2) {
  function doAdd(operand1, operand2) {
    return operand1 + operand2;
  }

  return doAdd(value1, value2);
}

var foo = add(1, 2);
// foo equals 3

function add(value1, value2) {
  function doAdd() {
    return value1 + value2;
  }

  return doAdd();
}

var foo = add(1, 2);
// foo equals 3

创建关闭 一个关闭是当一个内部函数从创建它的函数的外部可访问时创建的,这通常发生在一个外部函数返回一个内部函数时,当这种情况发生时,内部函数保持了一个参考到它创建的环境。

function add(value1) {
  return function doAdd(value2) {
    return value1 + value2;
  };
}

var increment = add(1);
var foo = increment(2);
// foo equals 3

function increment(value2) {
  return 1 + value2;
}

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Closures</title>
  <meta charset="UTF-8" />
  <script>
    window.addEventListener("load", function() {
      window.setInterval(showMessage, 1000, "some message<br />");
    });

    function showMessage(message) {
      document.getElementById("message").innerHTML += message;
    }
  </script>
</head>
<body>
  <span id="message"></span>
</body>
</html>

window.addEventListener("load", function() {
  var showMessage = getClosure("some message<br />");

  window.setInterval(showMessage, 1000);
});

function getClosure(message) {
  function showMessage() {
    document.getElementById("message").innerHTML += message;
  }

  return showMessage;
}

模拟私人数据

function Person(name) {
  this._name = name;

  this.getName = function() {
    return this._name;
  };
}

var person = new Person("Colin");

person._name = "Tom";
// person.getName() now returns "Tom"

function Person(name) {
  var _name = name;

  this.getName = function() {
    return _name;
  };
}

var person = new Person("Colin");

person._name = "Tom";
// person._name is "Tom" but person.getName() returns "Colin"

在LOPS

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Closures</title>
  <meta charset="UTF-8" />
  <script>
    window.addEventListener("load", function() {
      for (var i = 1; i < 4; i++) {
        var button = document.getElementById("button" + i);

        button.addEventListener("click", function() {
          alert("Clicked button " + i);
        });
      }
    });
  </script>
</head>
<body>
  <input type="button" id="button1" value="One" />
  <input type="button" id="button2" value="Two" />
  <input type="button" id="button3" value="Three" />
</body>
</html>

要解决这个问题,关闭必须从实际路径变量中分开,这可以通过呼叫一个新的函数来完成,这反过来创造了一个新的参考环境,下面的例子表明如何做到这一点,路径变量转移到 getHandler() 函数, getHandler() 然后返回一个独立于原来的“为”路径的关闭。

function getHandler(i) {
  return function handler() {
    alert("Clicked button " + i);
  };
}
window.addEventListener("load", function() {
  for (var i = 1; i < 4; i++) {
    var button = document.getElementById("button" + i);
    button.addEventListener("click", getHandler(i));
  }
});

function Person(name) {
  var _name = name;

  this.getName = function() {
    return _name;
  };

  this.sayHello = function() {
    alert("Hello!");
  };
}

function Person(name) {
  var _name = name;

  this.getName = function() {
    return _name;
  };
}

Person.prototype.sayHello = function() {
  alert("Hello!");
};

要记住的事情

最好的方法是不断地解释这些概念:

console.log(x);
// undefined

var x = 42;
console.log(x);
// 42

现在,JavaScript知道X是什么意思。

x = 43;
console.log(x);
// 43

现在,X意味着别的东西。

范围

当您创建一个函数时,该函数为变量具有自己的“盒子”。

function A() {
  var x = 42;
}

console.log(x);

// undefined

var x = 42;

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

// 42

在函数 A 中,您有“范围访问”到 x。

function A() {
  var x = 42;
}

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

// undefined

function A() {

  var x = 42;

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

}

// 42

功能

在JavaScript中,您通过称之为:

function A() {
  console.log(42);
}

A();

// 42

var a = function() {
  console.log(42);
};

变量现在意味着一个功能,你可以运行它。

a();
// 42

setTimeout(a, 1000);

在一秒钟(1000毫秒),函数一个点被称为:

// 42

现在,当你定义函数时,这些函数可以访问它们的外部目标。

var a = function() {

  var text = 'Hello!'

  var b = function() {
    console.log(text);
    // inside function `b`, you have access to `text`
  };

  // but you want to run `b` later, rather than right away
  setTimeout(b, 1000);

}

现在发生了什么?

// 'Hello!'

var c;

var a = function() {

  var text = 'Hello!'

  var b = function() {
    console.log(text);
    // inside function `b`, you have access to `text`
  };

  c = b;

}

// now we are out side of function `a`
// call `a` so the code inside `a` runs
a(); 

// now `c` has a value that is a function
// because what happened when `a` ran

// when you run `c`
c();

// 'Hello!'

您仍然可以在关闭范围内访问变量。

即使一个已经完成了运行,现在你正在运行C的外部。

在这里发生的事情被称为JavaScript中的“关闭”。

一个关闭是内部函数在其外部函数中有变量的访问,这可能是最简单的单线解释,你可以获得关闭。