JavaScript关闭如何工作?

发布于 2025-01-22 18:12:41 字数 214 浏览 0 评论 0 原文

您将如何向有知识的人解释JavaScript的关闭(例如函数,变量等),但不了解自己的封闭方式?

我已经看过 wikipedia上给出的方案示例,但不幸的是,它没有帮助。

How would you explain JavaScript closures to someone with a knowledge of the concepts they consist of (for example functions, variables and the like), but does not understand closures themselves?

I have seen the Scheme example given on Wikipedia, but unfortunately it did not help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

高跟鞋的旋律 2025-01-29 18:12:41

闭合是:

  1. 一个函数和
  2. 对该功能的外部范围(词汇环境)的函数和引用

一个词汇环境是每个执行上下文(堆栈帧)的一部分,并且是标识符(即本地变量名称)和值之间的映射。

JavaScript中的每个功能都会引用其外词汇环境。此引用用于配置当调用函数时创建的执行上下文。此引用使函数中的代码能够在函数之外声明的“查看”变量,无论何时何地调用函数。

如果通过一个函数调用函数,而该函数又通过另一个函数调用,则创建了对外词汇环境的引用链。该链被称为范围链。

在以下代码中,内部在调用 foo 时创建的执行上下文的词汇环境形成一个封闭, 闭合 actible varable 秘密

function foo() {
  const secret = Math.trunc(Math.random() * 100)
  return function inner() {
    console.log(`The secret number is ${secret}.`)
  }
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret` is to invoke `f`

换句话说:在JavaScript中,功能带有对私人“状态盒”的引用,只有它们(以及在同一词汇环境中声明的任何其他功能)才能访问该功能。该盒子的框对函数的呼叫者看不见,为数据隐藏和封装提供了出色的机制。

请记住:JavaScript中的功能可以像变量(一流的功能)一样传递,这意味着可以围绕程序传递这些功能和状态配对,类似于您如何通过C ++中的类实例。

如果JavaScript没有关闭,则必须在函数显式之间传递更多的状态,从而使参数列表更长,代码噪声更加嘈杂。

因此,如果您希望函数始终可以访问私人状态,则可以使用闭合。

...而且我们经常 do 想要将状态与函数相关联。例如,在Java或C ++中,当您在类中添加一个私有实例变量和方法时,您将状态与功能相关联。

在C和大多数其他通用语言中,函数返回后,由于堆栈框架被破坏,因此所有本地变量都无法访问。在JavaScript中,如果您在另一个函数中声明一个函数,则外部功能的本地变量可以在返回后仍可访问。通过这种方式,在上面的代码中,秘密仍然可用于函数对象 innine 之后,它已从 foo < /代码>。

的用途

每当您需要与功能关联的私人状态时,关闭封闭 都是有用的。这是一个非常常见的情况 - 记住:JavaScript直到2015年才有类语法,并且仍然没有私人字段语法。关闭满足了这一需求。

私有实例变量

在以下代码中,函数 toString 关闭了汽车的详细信息。

function Car(manufacturer, model, year, color) {
  return {
    toString() {
      return `${manufacturer} ${model} (${year}, ${color})`
    }
  }
}

const car = new Car('Aston Martin', 'V8 Vantage', '2012', 'Quantum Silver')
console.log(car.toString())

功能编程

在以下代码中,函数内部可以通过 fn args 关闭。

function curry(fn) {
  const args = []
  return function inner(arg) {
    if(args.length === fn.length) return fn(...args)
    args.push(arg)
    return inner
  }
}

function add(a, b) {
  return a + b
}

const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5

面向事件的编程

以下代码中

,函数 onclick 通过变量 background_color 关闭。

const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200, 200, 242, 1)'

function onClick() {
  $('body').style.background = BACKGROUND_COLOR
}

$('button').addEventListener('click', onClick)
<button>Set background color</button>

在下面的示例

中,所有实现详细信息都隐藏在立即执行的函数表达式中。功能 tick toString 关闭了他们完成工作所需的私人状态和功能。关闭使我们能够模块化并封装我们的代码。

let namespace = {};

(function foo(n) {
  let numbers = []

  function format(n) {
    return Math.trunc(n)
  }

  function tick() {
    numbers.push(Math.random() * 100)
  }

  function toString() {
    return numbers.map(format)
  }

  n.counter = {
    tick,
    toString
  }
}(namespace))

const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())

示例

示例1

此示例表明,局部变量未在闭合中复制:闭合维持对原始变量本身的引用。即使在外部功能退出后,堆栈框架似乎仍在存储器中保持活力。

function foo() {
  let x = 42
  let inner = () => console.log(x)
  x = x + 1
  return inner
}

foo()() // logs 43

示例2

在以下代码中,三种方法 log 增量 UPDATE 都在同一词汇环境上关闭。

每次都称为 createObject 都会创建一个新的执行上下文(堆栈帧),并且全新的变量 x 和一组新的函数( log> log << /code>等)是创建的,它靠近此新变量。

function createObject() {
  let x = 42;
  return {
    log() { console.log(x) },
    increment() { x++ },
    update(value) { x = value }
  }
}

const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42

示例3

如果您使用的是使用 var 声明的变量,请小心您了解要关闭的变量。使用 var 声明的变量被提升。由于引入 LET const ,这在现代JavaScript中的问题要小得多。

在以下代码中,每次在循环周围,创建了一个新功能内部,可以通过 i 关闭。但是,由于 var i 是在循环外悬挂的,所以所有这些内部函数都关闭在同一变量上,这意味着打印了 i (3)的最终值,三次。

function foo() {
  var result = []
  for (var i = 0; i < 3; i++) {
    result.push(function inner() { console.log(i) } )
  }

  return result
}

const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
  result[i]() 
}

最终积分:

  • 每当创建JavaScript闭合中声明函数时。
  • 从另一个函数内部返回函数是闭合的经典示例,因为即使外部函数完成执行,外部函数内部的状态也隐含地可用于返回的内部函数。
  • 每当您在功能中使用 eval()时,都会使用封闭。您的文本 eval 可以引用该函数的本地变量,在非图案模式下,您甚至可以使用 eval('var foo =…')。
  • 当您使用新函数(…)函数构造函数)在函数中,它不会在其词汇环境上关闭:它在全局上下文上关闭。新功能不能引用外部函数的局部变量。
  • JavaScript中的关闭就像在函数声明时将参考(不是副本)保留到范围上,这反过来又保持了对其外部范围的参考,依此类推,依此类推。范围链顶部的全局对象。
  • 声明函数时会创建关闭;此闭合用于调用函数时配置执行上下文。
  • 每次调用函数时,都会创建一组新的本地变量。

链接

A closure is a pairing of:

  1. A function and
  2. A reference to that function's outer scope (lexical environment)

A lexical environment is part of every execution context (stack frame) and is a map between identifiers (i.e. local variable names) and values.

Every function in JavaScript maintains a reference to its outer lexical environment. This reference is used to configure the execution context created when a function is invoked. This reference enables code inside the function to "see" variables declared outside the function, regardless of when and where the function is called.

If a function was called by a function, which in turn was called by another function, then a chain of references to outer lexical environments is created. This chain is called the scope chain.

In the following code, inner forms a closure with the lexical environment of the execution context created when foo is invoked, closing over variable secret:

function foo() {
  const secret = Math.trunc(Math.random() * 100)
  return function inner() {
    console.log(`The secret number is ${secret}.`)
  }
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret` is to invoke `f`

In other words: in JavaScript, functions carry a reference to a private "box of state", to which only they (and any other functions declared within the same lexical environment) have access. This box of the state is invisible to the caller of the function, delivering an excellent mechanism for data-hiding and encapsulation.

And remember: functions in JavaScript can be passed around like variables (first-class functions), meaning these pairings of functionality and state can be passed around your program, similar to how you might pass an instance of a class around in C++.

If JavaScript did not have closures, then more states would have to be passed between functions explicitly, making parameter lists longer and code noisier.

So, if you want a function to always have access to a private piece of state, you can use a closure.

...and frequently we do want to associate the state with a function. For example, in Java or C++, when you add a private instance variable and a method to a class, you are associating the state with functionality.

In C and most other common languages, after a function returns, all the local variables are no longer accessible because the stack-frame is destroyed. In JavaScript, if you declare a function within another function, then the local variables of the outer function can remain accessible after returning from it. In this way, in the code above, secret remains available to the function object inner, after it has been returned from foo.

Uses of Closures

Closures are useful whenever you need a private state associated with a function. This is a very common scenario - and remember: JavaScript did not have a class syntax until 2015, and it still does not have a private field syntax. Closures meet this need.

Private Instance Variables

In the following code, the function toString closes over the details of the car.

function Car(manufacturer, model, year, color) {
  return {
    toString() {
      return `${manufacturer} ${model} (${year}, ${color})`
    }
  }
}

const car = new Car('Aston Martin', 'V8 Vantage', '2012', 'Quantum Silver')
console.log(car.toString())

Functional Programming

In the following code, the function inner closes over both fn and args.

function curry(fn) {
  const args = []
  return function inner(arg) {
    if(args.length === fn.length) return fn(...args)
    args.push(arg)
    return inner
  }
}

function add(a, b) {
  return a + b
}

const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5

Event-Oriented Programming

In the following code, function onClick closes over variable BACKGROUND_COLOR.

const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200, 200, 242, 1)'

function onClick() {
  $('body').style.background = BACKGROUND_COLOR
}

$('button').addEventListener('click', onClick)
<button>Set background color</button>

Modularization

In the following example, all the implementation details are hidden inside an immediately executed function expression. The functions tick and toString close over the private state and functions they need to complete their work. Closures have enabled us to modularize and encapsulate our code.

let namespace = {};

(function foo(n) {
  let numbers = []

  function format(n) {
    return Math.trunc(n)
  }

  function tick() {
    numbers.push(Math.random() * 100)
  }

  function toString() {
    return numbers.map(format)
  }

  n.counter = {
    tick,
    toString
  }
}(namespace))

const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())

Examples

Example 1

This example shows that the local variables are not copied in the closure: the closure maintains a reference to the original variables themselves. It is as though the stack-frame stays alive in memory even after the outer function exits.

function foo() {
  let x = 42
  let inner = () => console.log(x)
  x = x + 1
  return inner
}

foo()() // logs 43

Example 2

In the following code, three methods log, increment, and update all close over the same lexical environment.

And every time createObject is called, a new execution context (stack frame) is created and a completely new variable x, and a new set of functions (log etc.) are created, that close over this new variable.

function createObject() {
  let x = 42;
  return {
    log() { console.log(x) },
    increment() { x++ },
    update(value) { x = value }
  }
}

const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42

Example 3

If you are using variables declared using var, be careful you understand which variable you are closing over. Variables declared using var are hoisted. This is much less of a problem in modern JavaScript due to the introduction of let and const.

In the following code, each time around the loop, a new function inner is created, which closes over i. But because var i is hoisted outside the loop, all of these inner functions close over the same variable, meaning that the final value of i (3) is printed, three times.

function foo() {
  var result = []
  for (var i = 0; i < 3; i++) {
    result.push(function inner() { console.log(i) } )
  }

  return result
}

const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
  result[i]() 
}

Final points:

  • Whenever a function is declared in JavaScript closure is created.
  • Returning a function from inside another function is the classic example of closure, because the state inside the outer function is implicitly available to the returned inner function, even after the outer function has completed execution.
  • Whenever you use eval() inside a function, a closure is used. The text you eval can reference local variables of the function, and in the non-strict mode, you can even create new local variables by using eval('var foo = …').
  • When you use new Function(…) (the Function constructor) inside a function, it does not close over its lexical environment: it closes over the global context instead. The new function cannot reference the local variables of the outer function.
  • A closure in JavaScript is like keeping a reference (NOT a copy) to the scope at the point of function declaration, which in turn keeps a reference to its outer scope, and so on, all the way to the global object at the top of the scope chain.
  • A closure is created when a function is declared; this closure is used to configure the execution context when the function is invoked.
  • A new set of local variables is created every time a function is called.

Links

爱人如己 2025-01-29 18:12:41

JavaScript中的每个功能都保持着与其外词汇环境的链接。词汇环境是范围内所有名称(例如变量,参数)的地图,其值。

因此,每当您看到函数关键字时,该函数内部的代码都可以访问在功能之外声明的变量。

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

这将记录 16 ,因为函数 bar 通过参数 x 和变量 tmp 关闭,这两个都存在于外部功能的词汇环境 foo

函数 bar ,以及其链接以及功能的词汇环境 foo 是封闭。

一个函数不必返回才能创建闭合。仅仅凭借其声明,每个功能都会在其封闭的词汇环境上关闭,形成封闭。

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2);
bar(10); // 16
bar(10); // 17

以上功能也将log 16,因为 bar 内部的代码仍然可以参考参数 x 和变量 tmp ,即使它们不再是直接在范围内。

但是,由于 tmp 仍在内部闲逛 bar 的关闭,因此可以增加。每次调用 bar 时,它都会增加。

关闭的最简单例子是:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

调用JavaScript函数时,创建了新的执行上下文 EC 。与函数参数和目标对象一起,此执行上下文还接收到指调执行上下文的词汇环境的链接,这意味着在外词法环境中声明的变量(在上面的示例中,这两个 a 和 b )可从 ec 获得。

每个功能都会闭合,因为每个功能都有与其外词汇环境的链接。

请注意,变量本身在闭合中可见,不是副本。

Every function in JavaScript maintains a link to its outer lexical environment. A lexical environment is a map of all the names (eg. variables, parameters) within a scope, with their values.

So, whenever you see the function keyword, code inside that function has access to variables declared outside the function.

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

This will log 16 because function bar closes over the parameter x and the variable tmp, both of which exist in the lexical environment of outer function foo.

Function bar, together with its link with the lexical environment of function foo is a closure.

A function doesn't have to return in order to create a closure. Simply by virtue of its declaration, every function closes over its enclosing lexical environment, forming a closure.

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2);
bar(10); // 16
bar(10); // 17

The above function will also log 16, because the code inside bar can still refer to argument x and variable tmp, even though they are no longer directly in scope.

However, since tmp is still hanging around inside bar's closure, it is available to be incremented. It will be incremented each time you call bar.

The simplest example of a closure is this:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

When a JavaScript function is invoked, a new execution context ec is created. Together with the function arguments and the target object, this execution context also receives a link to the lexical environment of the calling execution context, meaning the variables declared in the outer lexical environment (in the above example, both a and b) are available from ec.

Every function creates a closure because every function has a link to its outer lexical environment.

Note that variables themselves are visible from within a closure, not copies.

思慕 2025-01-29 18:12:41

前言:当问题是:

就像老阿尔伯特(Albert失败。

有人可以认为我是6岁,对该主题很奇怪吗?

?令人难以置信的愚蠢


;时间:

有一个公主...

function princess() {

她生活在一个充满冒险的美好世界中。

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

    return {

她经常会告诉他们她作为公主的最新惊人冒险。

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

但是他们只会看到一个小女孩...

var littleGirl = princess();

讲述魔术和幻想的故事。

littleGirl.story();

即使大人知道真正的公主,他们也永远不会相信独角兽或龙,因为他们永远看不到它们。大人说,它们仅存在小女孩的想象中。

但是我们知道真实的真理。那个里面有公主的小女孩……

实际上是一个有一个小女孩的公主。

FOREWORD: this answer was written when the question was:

Like the old Albert said : "If you can't explain it to a six-year old, you really don't understand it yourself.”. Well I tried to explain JS closures to a 27 years old friend and completely failed.

Can anybody consider that I am 6 and strangely interested in that subject ?

I'm pretty sure I was one of the only people that attempted to take the initial question literally. Since then, the question has mutated several times, so my answer may now seem incredibly silly & out of place. Hopefully the general idea of the story remains fun for some.


I'm a big fan of analogy and metaphor when explaining difficult concepts, so let me try my hand with a story.

Once upon a time:

There was a princess...

function princess() {

She lived in a wonderful world full of adventures. She met her Prince Charming, rode around her world on a unicorn, battled dragons, encountered talking animals, and many other fantastical things.

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

But she would always have to return back to her dull world of chores and grown-ups.

    return {

And she would often tell them of her latest amazing adventure as a princess.

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

But all they would see is a little girl...

var littleGirl = princess();

...telling stories about magic and fantasy.

littleGirl.story();

And even though the grown-ups knew of real princesses, they would never believe in the unicorns or dragons because they could never see them. The grown-ups said that they only existed inside the little girl's imagination.

But we know the real truth; that the little girl with the princess inside...

...is really a princess with a little girl inside.

金兰素衣 2025-01-29 18:12:41

认真考虑这个问题,我们应该找出一个典型的6岁儿童能够在认知上能够有什么能力,尽管肯定是一个对JavaScript感兴趣的人并不那么典型。

儿童发展:5至7年它说:

您的孩子将能够遵循两个步骤的方向。例如,如果您对孩子说:“去厨房,给我一个垃圾袋”,他们将能够记住这个方向。

我们可以使用此示例来解释关闭,如下所示:

厨房是一个具有局部变量的关闭,称为 trashbags 。厨房内有一个名为 getTrashbag 的功能,可以获取一个垃圾袋并返回。

我们可以在JavaScript中对此进行编码:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

进一步解释了关闭为什么有趣的观点:

  • 每次 makekitchen()被调用,使用其独立的 trashbags 创建了一个新的封闭。
  • trashbags 变量是每个厨房内部的本地,在外部无法访问,但是 getTrashbag 属性的内部功能确实可以访问它。
  • 每个函数调用都会创建一个封闭式,但是除非可以从闭合外部调用内部函数(可以访问闭合的内部),否则无需保持闭合。使用 getTrashBag 函数返回对象。

Taking the question seriously, we should find out what a typical 6-year-old is capable of cognitively, though admittedly, one who is interested in JavaScript is not so typical.

On Childhood Development: 5 to 7 Years it says:

Your child will be able to follow two-step directions. For example, if you say to your child, "Go to the kitchen and get me a trash bag" they will be able to remember that direction.

We can use this example to explain closures, as follows:

The kitchen is a closure that has a local variable, called trashBags. There is a function inside the kitchen called getTrashBag that gets one trash bag and returns it.

We can code this in JavaScript like this:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

Further points that explain why closures are interesting:

  • Each time makeKitchen() is called, a new closure is created with its own separate trashBags.
  • The trashBags variable is local to the inside of each kitchen and is not accessible outside, but the inner function on the getTrashBag property does have access to it.
  • Every function call creates a closure, but there would be no need to keep the closure around unless an inner function, which has access to the inside of the closure, can be called from outside the closure. Returning the object with the getTrashBag function does that here.
流云如水 2025-01-29 18:12:41

稻草人

我需要知道单击一个按钮的

,每第三次点击一次做点什么...相当明显的解决方案

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

现在这将起作用,但是它确实通过添加一个变量来侵占外部范围,其唯一目的是跟踪计数。在某些情况下,这将是可取的,因为您的外部应用程序可能需要访问此信息。但是在这种情况下,我们只会更改每三个点击的行为,因此比封闭了事件处理程序内的此功能更可取。

考虑此选项

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

在这里注意几件事。

在上面的示例中,我使用JavaScript的封闭行为。 此行为允许任何功能无限期地访问其创建的范围。要实际应用此功能,我立即调用一个返回另一个功能的函数,并且因为我返回的功能具有访问内部计数变量(由于上面解释的封闭行为),这导致了由此产生的函数使用的私人范围...不是那么简单吗?让我们将其稀释为...

简单的单线闭合

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

返回函数返回函数以外的所有变量均可用于返回的函数,但是它们不能直接用于返回的功能对象...

func();  // Alerts "val"
func.a;  // Undefined

获取吗?因此,在我们的主要示例中,计数变量包含在闭合中,并始终可用于事件处理程序,因此它可以从单击点击中保留其状态。

同样,对于读取和分配给其私人范围的变量,此私人变量状态是完全可访问的。

你去那里;您现在已经完全封装了这种行为。

完整的博客文章 (包括JQUERY考虑)

The Straw Man

I need to know how many times a button has been clicked and do something on every third click...

Fairly Obvious Solution

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

Now this will work, but it does encroach into the outer scope by adding a variable, whose sole purpose is to keep track of the count. In some situations, this would be preferable as your outer application might need access to this information. But in this case, we are only changing every third click's behavior, so it is preferable to enclose this functionality inside the event handler.

Consider this option

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

Notice a few things here.

In the above example, I am using the closure behavior of JavaScript. This behavior allows any function to have access to the scope in which it was created, indefinitely. To practically apply this, I immediately invoke a function that returns another function, and because the function I'm returning has access to the internal count variable (because of the closure behavior explained above) this results in a private scope for usage by the resulting function... Not so simple? Let's dilute it down...

A simple one-line closure

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

All variables outside the returned function are available to the returned function, but they are not directly available to the returned function object...

func();  // Alerts "val"
func.a;  // Undefined

Get it? So in our primary example, the count variable is contained within the closure and always available to the event handler, so it retains its state from click to click.

Also, this private variable state is fully accessible, for both readings and assigning to its private scoped variables.

There you go; you're now fully encapsulating this behavior.

Full Blog Post (including jQuery considerations)

东走西顾 2025-01-29 18:12:41

很难解释封闭,因为它们被用来使每个人都直觉期望工作的某些行为起作用。我找到了解释它们的最佳方法(以及 i 了解他们所做的事情)就是想象没有它们的情况:

const makePlus = function(x) {
    return function(y) { return x + y; };
}

const plus5 = makePlus(5);
console.log(plus5(3));

如果JavaScript 不知道关闭,这里会发生什么?只需通过其方法主体(基本上是函数调用的)替换最后一行中的呼叫即可:

console.log(x + 3);

现在, x 的定义在哪里?我们没有在当前范围中定义它。唯一的解决方案是让 plus5 随身携带其范围(或更确切地说是其父母的范围)。这样, x 是定义明确的,并且与值5绑定。

Closures are hard to explain because they are used to make some behaviour work that everybody intuitively expects to work anyway. I find the best way to explain them (and the way that I learned what they do) is to imagine the situation without them:

const makePlus = function(x) {
    return function(y) { return x + y; };
}

const plus5 = makePlus(5);
console.log(plus5(3));

What would happen here if JavaScript didn't know closures? Just replace the call in the last line by its method body (which is basically what function calls do) and you get:

console.log(x + 3);

Now, where's the definition of x? We didn't define it in the current scope. The only solution is to let plus5 carry its scope (or rather, its parent's scope) around. This way, x is well-defined and it is bound to the value 5.

扛起拖把扫天下 2025-01-29 18:12:41

tldr

闭合是函数与其外词汇(即撰写)环境之间的链接,使得标识符(变量,参数,函数声明等)在该环境中定义了该功能,无论何时或从何处调用函数。

详细信息

在Ecmascript规范的术语中,可以说闭合可以由 [[环境]] 每个函数-Object的引用,指向词汇环境在其中定义了该函数。

当通过内部 [[call]] 方法, [[环境]] function-object上的引用被复制到外部环境参考 < a href =“ https://www.ecma-international.org/ecma-262/10.0/index.html#sec-sec-environment-records“ rel =“ noreferrer”>环境记录 a href =“ https://www.ecma-international.org/ecma-262/10.0/index.html#sec-execution-contexts“ rel =“ noreferrer”>“ noreferrer”>“ noreferrer”>“执行”上下文(stack Frame)。

在下面的示例中,函数 f 在全局执行上下文的词汇环境上关闭:

function f() {}

在下面的示例中,函数 h 在函数的词汇环境 g上关闭,反过来又关闭了全局执行上下文的词汇环境。

function g() {
    function h() {}
}

如果外部函数返回外部功能,则外词函数返回后,外词词环境将持续存在。这是因为如果最终调用内部函数,则需要可用外词汇环境。

在下面的示例中,函数 j 在函数的词汇环境 i 上关闭,这意味着可变 x 可以从内部函数 j可见,函数<代码> i 已经完成了执行:

function i() {
    var x = 'mochacchino'
    return function j() {
        console.log('Printing the value of x, from within function j: ', x)
    }
} 

const k = i()
setTimeout(k, 500) // invoke k (which is j) after 500ms

在封闭中,外词词环境中的变量可用, copies。

function l() {
  var y = 'vanilla';

  return {
    setY: function(value) {
      y = value;
    },
    logY: function(value) {
      console.log('The value of y is: ', y);
    }
  }
}

const o = l()
o.logY() // The value of y is: vanilla
o.setY('chocolate')
o.logY() // The value of y is: chocolate

通过外部环境参考的执行上下文之间链接的词汇环境链形成范围链,并定义了从任何给定功能可见的标识符。

请注意,为了提高清晰度和准确性,此答案已与原始作品发生了根本变化。

TLDR

A closure is a link between a function and its outer lexical (ie. as-written) environment, such that the identifiers (variables, parameters, function declarations etc) defined within that environment are visible from within the function, regardless of when or from where the function is invoked.

Details

In the terminology of the ECMAScript specification, a closure can be said to be implemented by the [[Environment]] reference of every function-object, which points to the lexical environment within which the function is defined.

When a function is invoked via the internal [[Call]] method, the [[Environment]] reference on the function-object is copied into the outer environment reference of the environment record of the newly-created execution context (stack frame).

In the following example, function f closes over the lexical environment of the global execution context:

function f() {}

In the following example, function h closes over the lexical environment of function g, which, in turn, closes over the lexical environment of the global execution context.

function g() {
    function h() {}
}

If an inner function is returned by an outer, then the outer lexical environment will persist after the outer function has returned. This is because the outer lexical environment needs to be available if the inner function is eventually invoked.

In the following example, function j closes over the lexical environment of function i, meaning that variable x is visible from inside function j, long after function i has completed execution:

function i() {
    var x = 'mochacchino'
    return function j() {
        console.log('Printing the value of x, from within function j: ', x)
    }
} 

const k = i()
setTimeout(k, 500) // invoke k (which is j) after 500ms

In a closure, the variables in the outer lexical environment themselves are available, not copies.

function l() {
  var y = 'vanilla';

  return {
    setY: function(value) {
      y = value;
    },
    logY: function(value) {
      console.log('The value of y is: ', y);
    }
  }
}

const o = l()
o.logY() // The value of y is: vanilla
o.setY('chocolate')
o.logY() // The value of y is: chocolate

The chain of lexical environments, linked between execution contexts via outer environment references, forms a scope chain and defines the identifiers visible from any given function.

Please note that in an attempt to improve clarity and accuracy, this answer has been substantially changed from the original.

猫弦 2025-01-29 18:12:41

好的,6岁的关闭迷。您想听听最简单的封闭例子吗?

让我们想象下一个情况:驾驶员坐在汽车上。那辆车在飞机内。飞机在机场。驾驶员能够在汽车外面进入东西的能力,但是即使飞机离开机场,驾驶员也可以关闭。就是这样。 27岁时,查看更详细的说明或在下面的示例中。

这是我可以将飞机故事转换为代码的方式。

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");

OK, 6-year-old closures fan. Do you want to hear the simplest example of closure?

Let's imagine the next situation: a driver is sitting in a car. That car is inside a plane. Plane is in the airport. The ability of driver to access things outside his car, but inside the plane, even if that plane leaves an airport, is a closure. That's it. When you turn 27, look at the more detailed explanation or at the example below.

Here is how I can convert my plane story into the code.

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");

有木有妳兜一样 2025-01-29 18:12:41

这是为了清除对其他答案中出现的封闭情况的几种(可能的)误解。

  • 不仅会在返回内部函数时创建封闭。实际上,封闭功能根本不需要返回才能创建其关闭。取而代之的是,您可以将内部函数分配给外部范围中的变量,或将其作为参数传递给另一个函数,在此函数中可以立即或任何时候调用。因此,一旦称为封闭功能,封闭函数的闭合可能会立即创建,因为任何内部函数在呼叫内部函数的调用,封闭函数返回之前或之后均可访问该闭合。
  • 封闭不会引用其范围中变量的旧值的副本。变量本身是关闭的一部分,因此在访问其中一个时看到的值变量是访问时的最新值。这就是为什么在循环内部创建的内部函数可能很棘手的原因,因为每个函数都可以访问相同的外部变量,而不是在创建或调用函数时抓取变量的副本。
  • 闭合中的“变量”包括在函数中声明的任何命名函数。它们还包括该功能的论点。关闭还可以访问其包含的封闭变量,一直到全球范围。
  • 封闭使用内存,但不会导致内存泄漏,因为JavaScript本身会清理其自己未引用的圆形结构。 Internet&nbsp;当涉及关闭的Explorer内存泄漏是在无法断开闭合的DOM属性值时创建的,从而维持对可能的圆形结构的引用。

This is an attempt to clear up several (possible) misunderstandings about closures that appear in some of the other answers.

  • A closure is not only created when you return an inner function. In fact, the enclosing function does not need to return at all in order for its closure to be created. You might instead assign your inner function to a variable in an outer scope, or pass it as an argument to another function where it could be called immediately or any time later. Therefore, the closure of the enclosing function is probably created as soon as the enclosing function is called since any inner function has access to that closure whenever the inner function is called, before or after the enclosing function returns.
  • A closure does not reference a copy of the old values of variables in its scope. The variables themselves are part of the closure, and so the value seen when accessing one of those variables is the latest value at the time it is accessed. This is why inner functions created inside of loops can be tricky, since each one has access to the same outer variables rather than grabbing a copy of the variables at the time the function is created or called.
  • The "variables" in a closure include any named functions declared within the function. They also include arguments of the function. A closure also has access to its containing closure's variables, all the way up to the global scope.
  • Closures use memory, but they don't cause memory leaks since JavaScript by itself cleans up its own circular structures that are not referenced. Internet Explorer memory leaks involving closures are created when it fails to disconnect DOM attribute values that reference closures, thus maintaining references to possibly circular structures.
空袭的梦i 2025-01-29 18:12:41

我不久前写了一篇博客文章,解释了封闭。这是我所说的关于为什么的关闭所说的话。

封闭是使函数具有持续性的私有变量的一种方式,也就是说,只有一个函数知道的变量,它可以从以前的运行时间跟踪信息。

从这个意义上讲,它们让函数的作用有点像具有私有属性的对象。


示例
var iplus1= (function () 
{
    var plusCount = 0;
    return function () 
    {
        return ++plusCount;
    }
})();

此处外部自我启动匿名函数仅运行一次,并将 pluscount 变量设置为0,并返回内部函数表达式。

而内部功能可以访问 plusCount 变量。现在,每次我们调用函数 iplus1()时,内部函数会增加 plusCount variable。

要记住的重要点是,页面上没有其他脚本可以访问 plusCount 变量,而更改 pluscount 变量的唯一方法是通过 iplus1 函数。


阅读更多参考:那是什么封闭的东西?

I wrote a blog post a while back explaining closures. Here's what I said about closures in terms of why you'd want one.

Closures are a way to let a function have persistent, private variables - that is, variables that only one function knows about, where it can keep track of info from previous times that it was run.

In that sense, they let a function act a bit like an object with private attributes.


Example
var iplus1= (function () 
{
    var plusCount = 0;
    return function () 
    {
        return ++plusCount;
    }
})();

Here the outer self-invoking anonymous function run only once and sets plusCount variable to 0, and returns the inner function expression.

Whereas inner function has access to plusCount variable. Now every time we invoke the function iplus1(), the inner function increments the plusCount variable.

The important point to keep in mind is that no other script on the page has access to plusCount variable and the only way to change the plusCount variable is through iplus1 function.


Read More for reference: So what are these closure thingys?

差↓一点笑了 2025-01-29 18:12:41

最初的问题有报价:

如果您无法向六岁的孩子解释,那么您真的不理解它。

这就是我试图向一个真正的六岁孩子解释它的方式:

您知道大人如何拥有房屋,他们称它为家?当妈妈有孩子时,孩子真的没有任何东西,对吗?但是它的父母拥有一所房子,所以每当有人问“您的家在哪里?”时,孩子都可以回答“那所房子!”,并指向父母的房子。

“封闭”是孩子总是(即使在国外)能够参考其房屋的能力,即使实际上是父母拥有房屋的能力。

The original question had a quote:

If you can't explain it to a six-year old, you really don't understand it yourself.

This is how I'd try to explain it to an actual six-year-old:

You know how grown-ups can own a house, and they call it home? When a mom has a child, the child doesn't really own anything, right? But its parents own a house, so whenever someone asks "Where's your home?", the child can answer "that house!", and point to the house of its parents.

A "Closure" is the ability of the child to always (even if abroad) be able to refer to its home, even though it's really the parent's who own the house.

此生挚爱伱 2025-01-29 18:12:41

封闭很简单:

以下简单示例涵盖了JavaScript关闭的所有要点。*
&nbsp;

这是一个生产可以添加和乘积的计算器的工厂:

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

关键点:每个调用 make_calculator 创建一个新的本地变量 n ,该计算器的添加乘以函数在 make_calculator 返回返回之后,继续使用。

如果您熟悉堆栈框架,这些计算器似乎很奇怪: make_calculator 返回之后,如何继续访问 n ?答案是想象JavaScript不使用“堆栈帧”,而是使用“堆帧”,可以在使它们返回的功能调用后持续存在。

内在函数,例如添加 >和乘数,在外部函数中声明的访问变量 ** 被称为 closures

这几乎是关闭的所有

内容


。 a href =“ https://stackoverflow.com/a/111111/706054”>另一个答案,除了示例6之外,它只是显示可以在声明之前使用变量,这是一个很好的事实,这是一个很好的事实与关闭无关。它还涵盖了的所有点(命名函数参数)和(2)复制数字会创建一个新数字,但是复制对象引用为您提供了对同一对象的另一个引用。这些也很高兴知道,但再次与关闭完全无关。它也与这个答案此评论,这就是JavaScript使loop variable variable varriable变量很难插入进入您的内部函数:“插入”步骤只能使用包含您内部功能并在每个环路迭代中调用的辅助函数来完成。 (严格地说,内部函数访问了助手函数的变量副本,而不是插入任何内容。)再次,在创建封闭时非常有用,而不是封闭的一部分是什么是闭合或工作原理的一部分。由于关闭的封闭方式在功能语言等功能性语言上的工作有所不同,其中变量绑定到值而不是存储空间,从而提供了一种恒定的人流,这些人以某种方式(即“插入”方式)是仅对JavaScript不正确,其中变量始终与存储空间绑定,而永远不会与值绑定。

** 如果嵌套甚至在全球上下文中,任何外部功能,则为此答案明确指出。

Closures are simple:

The following simple example covers all the main points of JavaScript closures.*
 

Here is a factory that produces calculators that can add and multiply:

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

The key point: Each call to make_calculator creates a new local variable n, which continues to be usable by that calculator's add and multiply functions long after make_calculator returns.

If you are familiar with stack frames, these calculators seem strange: How can they keep accessing n after make_calculator returns? The answer is to imagine that JavaScript doesn't use "stack frames", but instead uses "heap frames", which can persist after the function call that made them returns.

Inner functions like add and multiply, which access variables declared in an outer function**, are called closures.

That is pretty much all there is to closures.


* For example, it covers all the points in the "Closures for Dummies" article given in another answer, except example 6, which simply shows that variables can be used before they are declared, a nice fact to know but completely unrelated to closures. It also covers all the points in the accepted answer, except for the points (1) that functions copy their arguments into local variables (the named function arguments), and (2) that copying numbers creates a new number, but copying an object reference gives you another reference to the same object. These are also good to know but again completely unrelated to closures. It is also very similar to the example in this answer but a bit shorter and less abstract. It does not cover the point of this answer or this comment, which is that JavaScript makes it difficult to plug the current value of a loop variable into your inner function: The "plugging in" step can only be done with a helper function that encloses your inner function and is invoked on each loop iteration. (Strictly speaking, the inner function accesses the helper function's copy of the variable, rather than having anything plugged in.) Again, very useful when creating closures, but not part of what a closure is or how it works. There is additional confusion due to closures working differently in functional languages like ML, where variables are bound to values rather than to storage space, providing a constant stream of people who understand closures in a way (namely the "plugging in" way) that is simply incorrect for JavaScript, where variables are always bound to storage space, and never to values.

** Any outer function, if several are nested, or even in the global context, as this answer points out clearly.

揽清风入怀 2025-01-29 18:12:41

您能解释一下5--年龄吗

? a>效果很好,很简单:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

“证明,即使内部函数不返回” <,即使内在函数不返回”>

< sub>*ac#问题

Can you explain closures to a 5-year-old?*

I still think Google's explanation works very well and is concise:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

Proof that this example creates a closure even if the inner function doesn't return

*A C# question

淡紫姑娘! 2025-01-29 18:12:41

我倾向于通过好/坏的比较来更好地学习。我喜欢看到工作代码,然后是某人可能会遇到的非工作代码。我将

正确完成的关闭:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index of arr) {
    console.log(arr[index]());
}
  • 在上面的代码> Code> createClosure(n)中都在循环的每一个迭代中调用。请注意,我命名了变量 n ,以突出显示它是在新功能范围中创建的 new 变量,并且与 index 不相同与外部范围结合。

  • 这将创建一个新的范围, n 绑定到该范围。这意味着我们有10个独立的范围,每个迭代一个。

  • createClosure(n)返回一个返回该范围内n的函数。

  • 在每个范围内 n 绑定到 createClosure(n)被调用时所拥有的任何值> n 在调用 createClosure(n)时具有。

关闭错误:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index of badArr) {
    console.log(badArr[index]());
}
  • 在上面的代码中,循环被移动到 createClosurearray()函数中,并且该函数现在只是返回完成的阵列,乍一看似乎更直观。

  • 可能并不明显的是,由于 createclosurearray()仅调用一旦创建了一个范围,而不是为循环的每一个迭代创建一个范围。

  • 在此函数中,定义了一个名为索引>的变量。循环运行并添加函数到返回 index 的数组中。请注意, index 是在 createClosurearray 函数中定义的,该功能仅一次调用一次。


  • 因为 createclosurearray()函数中只有一个范围, index 仅绑定到该范围内的一个值。换句话说,每次循环更改 index 的值时,都会为在该范围内引用它的所有内容更改它。

  • 添加到数组中的所有函数返回相同的 index 变量,从父范围定义的范围,而不是从第一个示例(例如第一个示例)中的10个不同范围中的10个不同的函数。最终结果是所有10个函数从同一范围返回相同的变量。

  • 循环完成和 index 进行修改后,最终值为10,因此添加到数组中的每个函数都会返回单个 index 变量的值现在设置为10。

结果

关闭正确
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9

关闭错误
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10

I tend to learn better by GOOD/BAD comparisons. I like to see working code followed by non-working code that someone is likely to encounter. I put together a jsFiddle that does a comparison and tries to boil down the differences to the simplest explanations I could come up with.

Closures done right:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index of arr) {
    console.log(arr[index]());
}
  • In the above code createClosure(n) is invoked in every iteration of the loop. Note that I named the variable n to highlight that it is a new variable created in a new function scope and is not the same variable as index which is bound to the outer scope.

  • This creates a new scope and n is bound to that scope; this means we have 10 separate scopes, one for each iteration.

  • createClosure(n) returns a function that returns the n within that scope.

  • Within each scope n is bound to whatever value it had when createClosure(n) was invoked so the nested function that gets returned will always return the value of n that it had when createClosure(n) was invoked.

Closures done wrong:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index of badArr) {
    console.log(badArr[index]());
}
  • In the above code the loop was moved within the createClosureArray() function and the function now just returns the completed array, which at first glance seems more intuitive.

  • What might not be obvious is that since createClosureArray() is only invoked once only one scope is created for this function instead of one for every iteration of the loop.

  • Within this function a variable named index is defined. The loop runs and adds functions to the array that return index. Note that index is defined within the createClosureArray function which only ever gets invoked one time.

  • Because there was only one scope within the createClosureArray() function, index is only bound to a value within that scope. In other words, each time the loop changes the value of index, it changes it for everything that references it within that scope.

  • All of the functions added to the array return the SAME index variable from the parent scope where it was defined instead of 10 different ones from 10 different scopes like the first example. The end result is that all 10 functions return the same variable from the same scope.

  • After the loop finished and index was done being modified the end value was 10, therefore every function added to the array returns the value of the single index variable which is now set to 10.

Result

CLOSURES DONE RIGHT
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9

CLOSURES DONE WRONG
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10

逆光下的微笑 2025-01-29 18:12:41

wikipedia on Closures on Closures

在计算机科学中,闭合是该功能的非本地名称(自由变量)的引用环境。

从技术上讲,在 javascript 每个函数都是关闭。它总是可以访问周围范围中定义的变量。

由于JavaScript中范围定义构造是一个函数,而不是许多其他语言中的代码块,因此我们通常含义 closure javascript 函数,与已经执行的周围函数中定义的非局部变量一起工作

封闭通常用于使用一些隐藏的私人数据来创建功能(但并非总是如此)。

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

EMS

上面的示例是使用匿名函数,该函数已执行一次。但这不一定是。它可以命名(例如 MKDB )并稍后执行,每次调用数据库功能。每个生成的函数都将具有自己的隐藏数据库对象。关闭的另一个用法是,当我们不返回函数时,而是包含多个功能的对象,每个功能都可以访问相同的数据。

Wikipedia on closures:

In computer science, a closure is a function together with a referencing environment for the nonlocal names (free variables) of that function.

Technically, in JavaScript, every function is a closure. It always has an access to variables defined in the surrounding scope.

Since scope-defining construction in JavaScript is a function, not a code block like in many other languages, what we usually mean by closure in JavaScript is a function working with nonlocal variables defined in already executed surrounding function.

Closures are often used for creating functions with some hidden private data (but it's not always the case).

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

ems

The example above is using an anonymous function, which was executed once. But it does not have to be. It can be named (e.g. mkdb) and executed later, generating a database function each time it is invoked. Every generated function will have its own hidden database object. Another usage example of closures is when we don't return a function, but an object containing multiple functions for different purposes, each of those function having access to the same data.

浅黛梨妆こ 2025-01-29 18:12:41

即使父母是父母,孩子们永远不会忘记与父母分享的秘密
走了。这是函数的关闭。

JavaScript函数的秘密是

var parent = function() {
 var name = "Mary"; // secret
}

每次调用它时的私有变量,都会创建局部变量“名称”并给出名称“ Mary”。每当函数退出时,变量就会丢失,名称被遗忘了。

您可能会猜到,因为每次调用该函数时都会重新创建变量,而且没有其他人会知道它们,因此必须有一个秘密的地方存储它们。它可以称为秘密商会 stack 本地范围,但这并不重要。我们知道他们在那里,隐藏在记忆中。

但是,在JavaScript中,有一个非常特殊的功能,它在其他功能中创建的功能也可以知道父母的本地变量,并且只要他们的生活就可以保留。

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

因此,只要我们在父函数中,它就可以创建一个或多个孩子的功能,这些功能确实从秘密的地方共享秘密变量。

但是,可悲的是,如果孩子也是其父函数的私人变量,那么当父母结束时,它也会死亡,秘密会随着他们而死。

因此,要活下去,孩子必须在为时已晚之前离开

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

,现在,即使玛丽“不再跑步”,对她的记忆也不会丢失,她的孩子将永远记住她的名字和他们在一起共享的其他秘密。

因此,如果您称孩子为“爱丽丝”,她会回答,

child("Alice") => "My name is Alice, child of Mary"

这就是要说的。

The children will never forget the secrets they have shared with their parents, even after their parents are
gone. This is what closures are for functions.

The secrets for JavaScript functions are the private variables

var parent = function() {
 var name = "Mary"; // secret
}

Every time you call it, the local variable "name" is created and given the name "Mary". And every time the function exits the variable is lost and the name is forgotten.

As you may guess, because the variables are re-created every time the function is called, and nobody else will know them, there must be a secret place where they are stored. It could be called Chamber of Secrets or stack or local scope but it doesn't matter. We know they are there, somewhere, hidden in the memory.

But, in JavaScript, there is this very special thing that functions which are created inside other functions, can also know the local variables of their parents and keep them as long as they live.

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

So, as long as we are in the parent -function, it can create one or more child functions which do share the secret variables from the secret place.

But the sad thing is, if the child is also a private variable of its parent function, it would also die when the parent ends, and the secrets would die with them.

So to live, the child has to leave before it's too late

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

And now, even though Mary is "no longer running", the memory of her is not lost and her child will always remember her name and other secrets they shared during their time together.

So, if you call the child "Alice", she will respond

child("Alice") => "My name is Alice, child of Mary"

That's all there is to tell.

千笙结 2025-01-29 18:12:41

我整理了一个互动的JavaScript教程,以解释关闭的工作方式。
什么是封闭?

这是其中一个示例:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here

I put together an interactive JavaScript tutorial to explain how closures work.
What's a Closure?

Here's one of the examples:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here
萌辣 2025-01-29 18:12:41

我不明白为什么答案在这里如此复杂。

这是一个封闭:

var a = 42;

function b() { return a; }

是的。您可能每天多次使用这么多次。

没有理由相信关闭是解决特定问题的复杂设计。不,封闭只是从声明函数(不运行)的角度来使用来自较高范围的变量。

现在允许您做的事情可以更加壮观,请参阅其他答案。


I do not understand why the answers are so complex here.

Here is a closure:

var a = 42;

function b() { return a; }

Yes. You probably use that many times a day.

There is no reason to believe closures are a complex design hack to address specific problems. No, closures are just about using a variable that comes from a higher scope from the perspective of where the function was declared (not run).

Now what it allows you to do can be more spectacular, see other answers.

白龙吟 2025-01-29 18:12:41

封闭是内部功能可以在其外部功能中访问变量的地方。这可能是您可以闭合的最简单的单行解释。

并且内部函数不仅可以访问外部函数的变量,还可以访问外部函数的参数,如

示例

// Closure Example
function addNumbers(firstNumber, secondNumber) 
{
    var returnValue = "Result is : ";
    
    // This inner function has access to the outer function's variables & parameters
    function add() 
    {
        return returnValue + (firstNumber + secondNumber);
    }
    return add();
}

var result = addNumbers(10, 20);
console.log(result); //30

A closure is where an inner function has access to variables in its outer function. That's probably the simplest one-line explanation you can get for closures.

And the inner function has access not only to the outer function’s variables, but also to the outer function’s parameters as in the example below

Example

// Closure Example
function addNumbers(firstNumber, secondNumber) 
{
    var returnValue = "Result is : ";
    
    // This inner function has access to the outer function's variables & parameters
    function add() 
    {
        return returnValue + (firstNumber + secondNumber);
    }
    return add();
}

var result = addNumbers(10, 20);
console.log(result); //30

enter image description here

深海夜未眠 2025-01-29 18:12:41

Dlaliberte的第一点的示例:

返回内部函数时,不仅会创建闭合。实际上,封闭功能根本不需要返回。取而代之的是,您可以将内部函数分配给外部范围中的变量,或将其作为参数传递给可以立即使用的另一个函数。因此,封闭函数的闭合可能已经存在,因为任何内部函数都可以在称为封闭功能。

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);

Example for the first point by dlaliberte:

A closure is not only created when you return an inner function. In fact, the enclosing function does not need to return at all. You might instead assign your inner function to a variable in an outer scope, or pass it as an argument to another function where it could be used immediately. Therefore, the closure of the enclosing function probably already exists at the time that enclosing function was called since any inner function has access to it as soon as it is called.

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);
悲喜皆因你 2025-01-29 18:12:41

我知道已经有很多解决方案了,但是我想这个小而简单的脚本可以证明这一概念很有用:

// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined

I know there are plenty of solutions already, but I guess that this small and simple script can be useful to demonstrate the concept:

// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined
最冷一天 2025-01-29 18:12:41

您正在睡觉,邀请Dan。
您告诉Dan带一个Xbox控制器。

丹邀请保罗。
丹要求保罗带一个控制者。该党有多少人被带到党?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

You're having a sleep over and you invite Dan.
You tell Dan to bring one XBox controller.

Dan invites Paul.
Dan asks Paul to bring one controller. How many controllers were brought to the party?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");
忆梦 2025-01-29 18:12:41

封闭 都很好地解释了关闭,这解释了我们需要的原因它们以及解释词汇环境,这是理解封闭的必要条件。
这是摘要:

如果访问变量,但不是本地的怎么办?像这里一样:

“在此处输入图像描述“

在这种情况下,解释器在
外部 lexicalEnvironment 对象。

该过程由两个步骤组成:

  1. 首先,当创建函数f时,它不是在空中创建的
    空间。当前有一个词汇环境对象。在情况下
    上面,它的窗口(在功能时不确定A
    创建)。

创建函数时,它将获得一个隐藏的属性,名为[[scope]],该属性引用了当前的词汇环境。

如果读取变量,但在任何地方都找不到,则会生成错误。

嵌套函数

函数可以嵌套在另一个内部,形成了词汇环境链,也可以称为范围链。

因此,功能G可以访问G,A和F。

关闭

外部功能完成后可能会继续使用嵌套功能:

“在此处输入图像描述”

标记lexicalEnvironments:

”

如我们所见是用户对象中的属性,因此在用户完成后它将继续使用。

如果您还记得,当创建 this.say 时,它(每个函数)将获得一个内部参考 this.say。[[scope]] 到当前的LexicalEnvironment。因此,当前用户执行的词汇环境保留在内存中。用户的所有变量也是其属性,因此它们也被仔细保存,而不是往常的垃圾。

重点是确保内部函数将来要访问外部变量,它将能够做到。

总结:

  1. 内部函数将保持对外部的参考
    词汇环境。
  2. 内部功能可能会从中访问变量
    即使外部函数完成。
  3. 浏览器将词汇环境及其所有属性(变量)保留在内存中,直到有一个内部函数引用它。

这称为封闭。

The author of Closures has explained closures pretty well, explaining the reason why we need them and also explaining LexicalEnvironment which is necessary to understanding closures.
Here is the summary:

What if a variable is accessed, but it isn’t local? Like here:

Enter image description here

In this case, the interpreter finds the variable in the
outer LexicalEnvironment object.

The process consists of two steps:

  1. First, when a function f is created, it is not created in an empty
    space. There is a current LexicalEnvironment object. In the case
    above, it’s window (a is undefined at the time of function
    creation).

Enter image description here

When a function is created, it gets a hidden property, named [[Scope]], which references the current LexicalEnvironment.

Enter image description here

If a variable is read, but can not be found anywhere, an error is generated.

Nested functions

Functions can be nested one inside another, forming a chain of LexicalEnvironments which can also be called a scope chain.

Enter image description here

So, function g has access to g, a and f.

Closures

A nested function may continue to live after the outer function has finished:

Enter image description here

Marking up LexicalEnvironments:

Enter image description here

As we see, this.say is a property in the user object, so it continues to live after User completed.

And if you remember, when this.say is created, it (as every function) gets an internal reference this.say.[[Scope]] to the current LexicalEnvironment. So, the LexicalEnvironment of the current User execution stays in memory. All variables of User also are its properties, so they are also carefully kept, not junked as usually.

The whole point is to ensure that if the inner function wants to access an outer variable in the future, it is able to do so.

To summarize:

  1. The inner function keeps a reference to the outer
    LexicalEnvironment.
  2. The inner function may access variables from it
    any time even if the outer function is finished.
  3. The browser keeps the LexicalEnvironment and all its properties (variables) in memory until there is an inner function which references it.

This is called a closure.

看春风乍起 2025-01-29 18:12:41

JavaScript函数可以访问其:

  1. 参数
  2. 当地人(即他们的本地变量和本地功能)
  3. 环境,其中包括:
    • 全球,包括dom
    • 外部功能中的任何东西

的任何内容,则该函数是闭合。

请注意,不需要外部功能,尽管它们确实提供了好处,但我在这里不讨论。通过在其环境中访问数据,封闭可以使数据存活。在外部/内部函数的子案例中,外部功能可以创建本地数据并最终退出,但是,如果任何内部功能(s)在外部功能退出后生存,则内部函数(s)保持外部功能的本地数据活。

使用全球环境的关闭示例:

想象一下,堆栈溢出投票和投票按钮事件被用作关闭,clotup_click和fotedown_click,它们可以访问外部变量,并在全球定义。 (为了简单起见,我指的是Stackoverflow的问题投票按钮,而不是答案表按钮的数组。)

当用户单击“投票”按钮时,dogtup_click函数检查是否iSvotedDown == true是确定是否要投票还是仅仅取消一个投票。函数coptup_click是一个关闭,因为它正在访问其环境。

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

这四个功能都是封闭的,因为它们都可以访问环境。

JavaScript functions can access their:

  1. Arguments
  2. Locals (that is, their local variables and local functions)
  3. Environment, which includes:
    • globals, including the DOM
    • anything in outer functions

If a function accesses its environment, then the function is a closure.

Note that outer functions are not required, though they do offer benefits I don't discuss here. By accessing data in its environment, a closure keeps that data alive. In the subcase of outer/inner functions, an outer function can create local data and eventually exit, and yet, if any inner function(s) survive after the outer function exits, then the inner function(s) keep the outer function's local data alive.

Example of a closure that uses the global environment:

Imagine that the Stack Overflow Vote-Up and Vote-Down button events are implemented as closures, voteUp_click and voteDown_click, that have access to external variables isVotedUp and isVotedDown, which are defined globally. (For simplicity's sake, I am referring to StackOverflow's Question Vote buttons, not the array of Answer Vote buttons.)

When the user clicks the VoteUp button, the voteUp_click function checks whether isVotedDown == true to determine whether to vote up or merely cancel a down vote. Function voteUp_click is a closure because it is accessing its environment.

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

All four of these functions are closures as they all access their environment.

蓝眼泪 2025-01-29 18:12:41

作为一个6岁的父亲,目前教幼儿(以及不需要正规教育的相对新手,因此需要进行更正),我认为这堂课将通过动手玩耍来表现最好。如果这位6岁的孩子准备好了解关闭是什么,那么他们已经足够大了,可以自己去。我建议将代码粘贴到jsfiddle.net中,并解释一下,然后让它们独自构造一首独特的歌曲。下面的解释性文本可能更适合10岁。

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

指令

数据:数据是事实的集合。它可以是数字,单词,测量值,观察结果,甚至只是对事物的描述。您无法触摸它,闻到它或品尝它。您可以写下来,说话并听到。您可以使用计算机将其用于创建触摸气味和味道。使用代码可以通过计算机使其有用。

代码:上面的所有写作都称为代码。它用JavaScript编写。

JavaScript:JavaScript是一种语言。像英语,法语或中文一样。计算机和其他电子处理器可以理解很多语言。为了使JavaScript被计算机理解,需要解释器。想象一下,如果只会说俄语的老师来学校教您的课。当老师说“�Comvimumb。”课时不了解。但幸运的是,您班上有一个俄罗斯学生,告诉所有人,这意味着“每个人都坐下” - 所以大家都这样做。该课程就像一台计算机,俄罗斯学生是解释者。对于JavaScript,最常见的解释器称为浏览器。

浏览器:当您在计算机,平板电脑或电话上连接到Internet以访问网站时,您会使用浏览器。您可能知道的例子是Internet Explorer,Chrome,Firefox和Safari。浏览器可以理解JavaScript并告诉计算机需要做什么。 JavaScript指令称为函数。

功能:JavaScript中的功能就像工厂。它可能是一个小工厂,里面只有一台机器。或者它可能包含许多其他小工厂,每个工厂都有许多机器从事不同的工作。在一个现实生活中的服装工厂中,您可能会有一块布和螺纹的螺丝孔以及T恤和牛仔裤出来。我们的JavaScript工厂仅处理数据,它不能缝制,钻孔或熔化金属。在我们的JavaScript工厂数据中,数据出现了。

所有这些数据的东西听起来有些无聊,但真的很酷。我们可能有一个功能,可以告诉一个机器人晚餐做什么。假设我邀请您和您的朋友到我家。您最喜欢鸡腿,我喜欢香肠,您的朋友总是想要您想要的东西,而我的朋友不吃肉。

我没有时间去购物,因此该功能需要知道我们在冰箱中做出的决定。每种成分都有不同的烹饪时间,我们希望机器人同时将所有东西都加热。我们需要提供有关我们喜欢的数据的功能,该功能可以与冰箱“交谈”,并且该功能可以控制机器人。

功能通常具有名称,括号和括号。像这样:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

请注意, //...../ // 停止代码正在由浏览器读取。

名称:您可以调用功能几乎要涉及您想要的任何单词。典型的示例是将两个单词结合在一起并在一开始就给第二个大写字母的示例 - 但这不是必需的。它不能有空间,并且不能单独是数字。

括号:“括号”或()是JavaScript功能工厂的门上的字母框或街上的邮政信箱,以将信息包发送到工厂。有时,邮箱可能会标记为,例如 cookmeal(您,我,您的朋友,我的朋友,冰箱,晚餐时间),在这种情况下,您知道您必须提供哪些数据。

牙套:“括号”,看起来像 {} 是我们工厂的有色窗户。 看不到。

从工厂内部您可以

看到,但是从外部 那是一个!然后,函数的名称​​ sing - 这是我对函数的描述。然后括号()。括号始终在那里用于函数。有时它们是空的,有时它们有东西。这个单词在:(person)中。之后,有这样的支架 {。这标志着函数 sing()的开始。它的合作伙伴标记了 sing()的结尾 }

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

因此此功能可能与唱歌有关,并且可能需要一些有关某人的数据。它有内部使用该数据做点事的说明。

现在,在函数 sing()之后,代码末尾是线

var person="an old lady";

变量:字母 var 代表“变量”。变量就像一个信封。在外面,这个信封标记为“人”。在内部,它包含一张纸条,其中包含我们功能所需的信息,一些字母和空间像一条字符串(称为字符串)一样融合在一起,使一句话读为“老太太”。我们的信封可能包含其他类型的东西,例如数字(称为整数),指令(称为函数),列表(称为 arrays )。因为该变量在所有括号 {} 之外写成,并且由于您可以通过有色窗口在括号内看到,因此可以从代码中的任何地方看到此变量。我们将其称为“全局变量”。

全球变量: person 是一个全球变量,这意味着,如果您将其价值从“老太太”更改为“年轻人”,那么 Person 将不断成为年轻人直到您决定再次更改它,并且代码中的任何其他功能都可以看到它是一个年轻人。按下 f12 按钮,或查看选项设置以打开浏览器的开发人员控制台,然后键入“人”以查看此值是什么。键入 person =“一个年轻人” 更改它,然后再次键入“人”以查看它已经改变。

之后,我们有

sing(person);

这条线正在调用该功能,好像它在呼唤狗

“来 sing ,来获取 Person

当浏览器加载JavaScript代码A时,它将启动该功能。我将线路放在最后,以确保浏览器具有运行它所需的所有信息。

函数定义动作 - 主要功能是关于唱歌。它包含一个称为 firstPart 的变量,该变量适用于适用于歌曲的每个经文的人的唱歌:“有“ + person +”吞咽“ + person +”。如果将 firstPart 键入控制台,则不会得到答案,因为该变量已锁定在功能中 - 浏览器在括号的有色窗户内看不到。

关闭:封闭是大 sing()函数内部的较小功能。大厂内的小工厂。他们每个人都有自己的牙套,这意味着从外部看不到内部变量。这就是为什么可以在封闭中重复变量( creature result )的名称的原因,但具有不同的值。如果在控制台窗口中键入这些变量名称,则不会获得其值,因为它被两层有色窗口隐藏。

封闭都知道 sing()函数的变量称为 firstpart 是,因为它们可以从有色窗口中看到。

关闭后,

fly();
spider();
bird();
cat();

线()函数将按照给出的顺序调用每个功能。然后,将完成SING()函数的工作。

As a father of a 6-year-old, currently teaching young children (and a relative novice to coding with no formal education so corrections will be required), I think the lesson would stick best through hands-on play. If the 6-year-old is ready to understand what a closure is, then they are old enough to have a go themselves. I'd suggest pasting the code into jsfiddle.net, explaining a bit, and leaving them alone to concoct a unique song. The explanatory text below is probably more appropriate for a 10 year old.

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

INSTRUCTIONS

DATA: Data is a collection of facts. It can be numbers, words, measurements, observations or even just descriptions of things. You can't touch it, smell it or taste it. You can write it down, speak it and hear it. You could use it to create touch smell and taste using a computer. It can be made useful by a computer using code.

CODE: All the writing above is called code. It is written in JavaScript.

JAVASCRIPT: JavaScript is a language. Like English or French or Chinese are languages. There are lots of languages that are understood by computers and other electronic processors. For JavaScript to be understood by a computer it needs an interpreter. Imagine if a teacher who only speaks Russian comes to teach your class at school. When the teacher says "все садятся", the class would not understand. But luckily you have a Russian pupil in your class who tells everyone this means "everybody sit down" - so you all do. The class is like a computer and the Russian pupil is the interpreter. For JavaScript the most common interpreter is called a browser.

BROWSER: When you connect to the Internet on a computer, tablet or phone to visit a website, you use a browser. Examples you may know are Internet Explorer, Chrome, Firefox and Safari. The browser can understand JavaScript and tell the computer what it needs to do. The JavaScript instructions are called functions.

FUNCTION: A function in JavaScript is like a factory. It might be a little factory with only one machine inside. Or it might contain many other little factories, each with many machines doing different jobs. In a real life clothes factory you might have reams of cloth and bobbins of thread going in and T-shirts and jeans coming out. Our JavaScript factory only processes data, it can't sew, drill a hole or melt metal. In our JavaScript factory data goes in and data comes out.

All this data stuff sounds a bit boring, but it is really very cool; we might have a function that tells a robot what to make for dinner. Let's say I invite you and your friend to my house. You like chicken legs best, I like sausages, your friend always wants what you want and my friend does not eat meat.

I haven't got time to go shopping, so the function needs to know what we have in the fridge to make decisions. Each ingredient has a different cooking time and we want everything to be served hot by the robot at the same time. We need to provide the function with the data about what we like, the function could 'talk' to the fridge, and the function could control the robot.

A function normally has a name, parentheses and braces. Like this:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

Note that /*...*/ and // stop code being read by the browser.

NAME: You can call a function just about whatever word you want. The example "cookMeal" is typical in joining two words together and giving the second one a capital letter at the beginning - but this is not necessary. It can't have a space in it, and it can't be a number on its own.

PARENTHESES: "Parentheses" or () are the letter box on the JavaScript function factory's door or a post box in the street for sending packets of information to the factory. Sometimes the postbox might be marked for example cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime), in which case you know what data you have to give it.

BRACES: "Braces" which look like this {} are the tinted windows of our factory. From inside the factory you can see out, but from the outside you can't see in.

THE LONG CODE EXAMPLE ABOVE

Our code begins with the word function, so we know that it is one! Then the name of the function sing - that's my own description of what the function is about. Then parentheses (). The parentheses are always there for a function. Sometimes they are empty, and sometimes they have something in. This one has a word in: (person). After this there is a brace like this { . This marks the start of the function sing(). It has a partner which marks the end of sing() like this }

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

So this function might have something to do with singing, and might need some data about a person. It has instructions inside to do something with that data.

Now, after the function sing(), near the end of the code is the line

var person="an old lady";

VARIABLE: The letters var stand for "variable". A variable is like an envelope. On the outside this envelope is marked "person". On the inside it contains a slip of paper with the information our function needs, some letters and spaces joined together like a piece of string (it's called a string) that make a phrase reading "an old lady". Our envelope could contain other kinds of things like numbers (called integers), instructions (called functions), lists (called arrays). Because this variable is written outside of all the braces {}, and because you can see out through the tinted windows when you are inside the braces, this variable can be seen from anywhere in the code. We call this a 'global variable'.

GLOBAL VARIABLE: person is a global variable, meaning that if you change its value from "an old lady" to "a young man", the person will keep being a young man until you decide to change it again and that any other function in the code can see that it's a young man. Press the F12 button or look at the Options settings to open the developer console of a browser and type "person" to see what this value is. Type person="a young man" to change it and then type "person" again to see that it has changed.

After this we have the line

sing(person);

This line is calling the function, as if it were calling a dog

"Come on sing, Come and get person!"

When the browser has loaded the JavaScript code an reached this line, it will start the function. I put the line at the end to make sure that the browser has all the information it needs to run it.

Functions define actions - the main function is about singing. It contains a variable called firstPart which applies to the singing about the person that applies to each of the verses of the song: "There was " + person + " who swallowed". If you type firstPart into the console, you won't get an answer because the variable is locked up in a function - the browser can't see inside the tinted windows of the braces.

CLOSURES: The closures are the smaller functions that are inside the big sing() function. The little factories inside the big factory. They each have their own braces which mean that the variables inside them can't be seen from the outside. That's why the names of the variables (creature and result) can be repeated in the closures but with different values. If you type these variable names in the console window, you won't get its value because it's hidden by two layers of tinted windows.

The closures all know what the sing() function's variable called firstPart is, because they can see out from their tinted windows.

After the closures come the lines

fly();
spider();
bird();
cat();

The sing() function will call each of these functions in the order they are given. Then the sing() function's work will be done.

猫瑾少女 2025-01-29 18:12:41

好的,与一个6岁的孩子交谈,我可能会使用以下协会。

想象 - 您正在与整个房子里的小兄弟姐妹一起玩,您正在和玩具一起走动,将其中一些带入哥哥的房间。过了一会儿,您的兄弟从学校回来去了他的房间,他锁在里面,所以现在您无法直接访问那里的玩具。但是您可以敲门,向您的兄弟询问那个玩具。这称为玩具的关闭;您的兄弟为您弥补了它,他现在进入了范围

与某种情况相比,当门被选秀锁定,没有人内部(一般功能执行),然后发生一些当地的大火并烧毁房间(垃圾收集器:D),然后建造了一个新房间,现在您可以离开那里的另一个玩具(新功能实例),但永远不会得到第一个房间实例中留下的相同玩具。

对于一个高级孩子,我会列出以下内容。它不是完美的,但是它会让您对它的含义:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

如您所见,房间里留下的玩具仍然可以通过兄弟进入,无论房间是否被锁定。这是 a jsbin 与之一起玩。

Okay, talking with a 6-year old child, I would possibly use following associations.

Imagine - you are playing with your little brothers and sisters in the entire house, and you are moving around with your toys and brought some of them into your older brother's room. After a while your brother returned from the school and went to his room, and he locked inside it, so now you could not access toys left there anymore in a direct way. But you could knock the door and ask your brother for that toys. This is called toy's closure; your brother made it up for you, and he is now into outer scope.

Compare with a situation when a door was locked by draft and nobody inside (general function execution), and then some local fire occur and burn down the room (garbage collector:D), and then a new room was build and now you may leave another toys there (new function instance), but never get the same toys which were left in the first room instance.

For an advanced child I would put something like the following. It is not perfect, but it makes you feel about what it is:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

As you can see, the toys left in the room are still accessible via the brother and no matter if the room is locked. Here is a jsbin to play around with it.

淑女气质 2025-01-29 18:12:41

JavaScript中的功能不仅是对一组指令(如C语言)的引用,而且还包括一个隐藏的数据结构,该结构由对其使用的所有非局部变量的引用组成(捕获的变量)。这种两件式功能称为关闭。 JavaScript中的每个功能都可以视为关闭。

封闭是具有状态的功能。从某种意义上说,它在某种意义上与“ this”有点相似,因为“ this”也为函数提供了状态,但函数和“ this”是单独的对象(“此”只是一个花哨的参数,也是永久绑定到一个的唯一方法功能是创建闭合)。虽然“此”和“函数”始终单独使用,但函数不能与其闭合分开,该语言无法提供访问捕获变量的手段。

因为所有这些由词汇嵌套函数引用的所有外部变量实际上是其词汇封闭函数链中的局部变量(可以假定全局变量是某些根函数的局部变量),并且每个执行函数的每个执行都会创建新实例它的本地变量,遵循返回函数的每个执行(或以其他方式将其传输出来,例如将其注册为回调)嵌套函数都会创建一个新的封闭(具有其自身可能独特的参考非局部变量集,代表其执行语境)。

同样,必须理解,JavaScript中的局部变量不是在堆栈框架上创建的,而是在堆上创建的,只有在没有人引用它们时才被销毁。当功能返回时,对其本地变量的引用会减少,但是如果在当前执行中它们成为封闭的一部分,并且仍然被其词汇嵌套的函数引用(只有在引用对引用到引用到对此的引用时,它们仍然可以是无效的这些嵌套功能被返回或以其他方式传输到某些外部代码)。

一个例子:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();

A function in JavaScript is not just a reference to a set of instructions (as in C language), but it also includes a hidden data structure which is composed of references to all nonlocal variables it uses (captured variables). Such two-piece functions are called closures. Every function in JavaScript can be considered a closure.

Closures are functions with a state. It is somewhat similar to "this" in the sense that "this" also provides state for a function but function and "this" are separate objects ("this" is just a fancy parameter, and the only way to bind it permanently to a function is to create a closure). While "this" and function always live separately, a function cannot be separated from its closure and the language provides no means to access captured variables.

Because all these external variables referenced by a lexically nested function are actually local variables in the chain of its lexically enclosing functions (global variables can be assumed to be local variables of some root function), and every single execution of a function creates new instances of its local variables, it follows that every execution of a function returning (or otherwise transferring it out, such as registering it as a callback) a nested function creates a new closure (with its own potentially unique set of referenced nonlocal variables which represent its execution context).

Also, it must be understood that local variables in JavaScript are created not on the stack frame, but on the heap and destroyed only when no one is referencing them. When a function returns, references to its local variables are decremented, but they can still be non-null if during the current execution they became part of a closure and are still referenced by its lexically nested functions (which can happen only if the references to these nested functions were returned or otherwise transferred to some external code).

An example:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();
会傲 2025-01-29 18:12:41

一个六岁的人的答案(假设他知道什么是函数,什么是变量,以及什么是数据):

函数可以返回数据。您可以从函数返回的一种数据是另一个函数。当该新功能返回时,创建的函数中使用的所有变量和参数不会消失。相反,该父函数“关闭”。换句话说,除了它返回的函数外,除了它使用的变量外,没有任何东西可以看到它的内部。该新功能具有特殊的能力,可以回顾创建它的功能,并查看其内部的数据。

function the_closure() {
  var x = 4;
  return function () {
    return x; // Here, we look back inside the_closure for the value of x
  }
}

var myFn = the_closure();
myFn(); //=> 4

解释它的另一种真正简单的方法是范围:

每当您在较大范围内创建较小的范围时,较小的范围都会始终能够看到较大范围中的内容。

An answer for a six-year-old (assuming he knows what a function is and what a variable is, and what data is):

Functions can return data. One kind of data you can return from a function is another function. When that new function gets returned, all the variables and arguments used in the function that created it don't go away. Instead, that parent function "closes." In other words, nothing can look inside of it and see the variables it used except for the function it returned. That new function has a special ability to look back inside the function that created it and see the data inside of it.

function the_closure() {
  var x = 4;
  return function () {
    return x; // Here, we look back inside the_closure for the value of x
  }
}

var myFn = the_closure();
myFn(); //=> 4

Another really simple way to explain it is in terms of scope:

Any time you create a smaller scope inside of a larger scope, the smaller scope will always be able to see what is in the larger scope.

四叶草在未来唯美盛开 2025-01-29 18:12:41

除了最早熟的六岁儿童之外,也许有些超出了一切,但是一些有助于使我关闭的概念的例子为我点击了我。

闭合是可以访问另一个函数范围(其变量和函数)的函数。创建闭合的最简单方法是在功能中具有功能。原因是在JavaScript中,函数始终可以访问其包含函数的范围。

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    innerFunction();
}

outerFunction();

警报:猴子

在上面的示例中称为外部功能,而外部功能又调用了内部功能。请注意,Outervar如何可用于内部功能,可以正确警告Outervar的值。

现在考虑以下内容:

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

警报:Monkey

ReferenceToInnerFunction设置为外部功能(),该功能只需返回内部功能的引用即可。当调用ReferenceToInnerFunction时,它将返回Outervar。同样,如上所述,这表明内部功能可以访问OuterVar,outervar是外部功能的变量。此外,有趣的是,即使外部功能完成执行,它仍保留此访问。

这是事情变得非常有趣的地方。如果我们要摆脱外部功能,说将其设置为null,您可能会认为ReferenceToInnerFunction会失去其对Outervar价值的访问。但事实并非如此。

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

outerFunction = null;
alert(referenceToInnerFunction());

警报:猴子
警报:猴子

,但是这是怎么回事呢?既然外部功能已设置为null,referenceToinnerFunction如何仍然知道Outervar的值?

ReferenceToInnerFunction仍然可以访问OuterVar的值的原因是,当闭合是通过在外部功能内部放置内部功能而创建的闭合时,InterFunction在其范围链中添加了对外部功能的范围(其变量和功能)的引用。这意味着Intrunction具有指针或对所有外部功能的变量(包括Outervar)的引用。因此,即使外部功能完成执行,或者即使将其删除或设置为null,其范围中的变量(例如Outervar)也会在内存中粘贴在内存中,因为在内部功能中对它们的出色引用已返回到已返回到已返回到ReferenceToinnerFunction。要真正将Outervar和外部功能的其余变量从内存中释放出来,您将不得不摆脱对它们的出色引用,例如,也将ReferenceToinnerFunction设置为null。

//////////

关于关闭的另外两件事。首先,闭合将始终可以访问其包含函数的最后值。

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    outerVar = "gorilla";

    innerFunction();
}

outerFunction();

警报:大猩猩的

第二,当创建闭合时,它保留了对其所有封闭函数的变量和函数的引用;它无法选择。但是,因此,封闭情况应谨慎或至少仔细地使用,因为它们可能是记忆密集型的;在包含功能完成执行后很长时间,可以将许多变量保存在内存中。

Perhaps a little beyond all but the most precocious of six-year-olds, but a few examples that helped make the concept of closure in JavaScript click for me.

A closure is a function that has access to another function's scope (its variables and functions). The easiest way to create a closure is with a function within a function; the reason being that in JavaScript a function always has access to its containing function’s scope.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    innerFunction();
}

outerFunction();

ALERT: monkey

In the above example, outerFunction is called which in turn calls innerFunction. Note how outerVar is available to innerFunction, evidenced by its correctly alerting the value of outerVar.

Now consider the following:

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

ALERT: monkey

referenceToInnerFunction is set to outerFunction(), which simply returns a reference to innerFunction. When referenceToInnerFunction is called, it returns outerVar. Again, as above, this demonstrates that innerFunction has access to outerVar, a variable of outerFunction. Furthermore, it is interesting to note that it retains this access even after outerFunction has finished executing.

And here is where things get really interesting. If we were to get rid of outerFunction, say set it to null, you might think that referenceToInnerFunction would loose its access to the value of outerVar. But this is not the case.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

outerFunction = null;
alert(referenceToInnerFunction());

ALERT: monkey
ALERT: monkey

But how is this so? How can referenceToInnerFunction still know the value of outerVar now that outerFunction has been set to null?

The reason that referenceToInnerFunction can still access the value of outerVar is because when the closure was first created by placing innerFunction inside of outerFunction, innerFunction added a reference to outerFunction’s scope (its variables and functions) to its scope chain. What this means is that innerFunction has a pointer or reference to all of outerFunction’s variables, including outerVar. So even when outerFunction has finished executing, or even if it is deleted or set to null, the variables in its scope, like outerVar, stick around in memory because of the outstanding reference to them on the part of the innerFunction that has been returned to referenceToInnerFunction. To truly release outerVar and the rest of outerFunction’s variables from memory you would have to get rid of this outstanding reference to them, say by setting referenceToInnerFunction to null as well.

//////////

Two other things about closures to note. First, the closure will always have access to the last values of its containing function.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    outerVar = "gorilla";

    innerFunction();
}

outerFunction();

ALERT: gorilla

Second, when a closure is created, it retains a reference to all of its enclosing function’s variables and functions; it doesn’t get to pick and choose. And but so, closures should be used sparingly, or at least carefully, as they can be memory intensive; a lot of variables can be kept in memory long after a containing function has finished executing.

心欲静而疯不止 2025-01-29 18:12:41

我只是简单地将它们指向 Mozilla Closures Page 。这是我发现的封闭基础知识和实际用法的最好,最简洁,简单的解释。强烈建议任何学习JavaScript的人。

是的,我什至会推荐给一个6岁的孩子 - 如果6岁的孩子正在学习有关关闭的知识,那么这是合乎逻辑的,他们准备理解简洁而简单的解释在文章中。

I'd simply point them to the Mozilla Closures page. It's the best, most concise and simple explanation of closure basics and practical usage that I've found. It is highly recommended to anyone learning JavaScript.

And yes, I'd even recommend it to a 6-year old -- if the 6-year old is learning about closures, then it's logical they're ready to comprehend the concise and simple explanation provided in the article.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文