简体   繁体   English

在javascript中返回函数,理解范围和闭包

[英]Returning functions in javascript, understanding scope & closures

I was looking at Mozillas developer site on javascript closure and they had this example of code. 我正在关注javascript关闭的Mozillas开发者网站,他们有这个代码示例。

  function makeAdder(x){
    return function (y) {
        console.log(y + " this is y")
        console.log(x + " this is x")
        return x + y;
        }
}
var add10 = makeAdder(10);
console.log(add10(2)); // 12

Now i understand the X attribute being set but what i dont get is how the scope of the y is being affected. 现在我理解正在设置的X属性,但我没有得到的是y的范围如何受到影响。 I know its a return function but my brain went to mush trying to visualise how you could set ay when there was no ref to it. 我知道它有一个返回功能,但是当我没有参考时,我的大脑试图想象你如何设置它。 could someone explain? 有人能解释一下吗

makeAdder returns a function to which you can pass the y parameter. makeAdder返回一个可以传递y参数的函数。 It is set at the time of invocation, as opposed to x which is set at the time of creation of the new function (at the time of the invocation of makeAdder ). 它是在调用时设置的,而不是在创建新函数时设置的x (在调用makeAdder )。

For the case of this example, the output is equivalent to having written: 对于此示例的情况,输出相当于已写入:

function add10(y) {
    return 10 + y;
}

console.log(add10(2)); // 12

Nothing new is going on here. 这里没有新的东西。 The sample code is mainly trying to illustrate that a closure is being created for x . 示例代码主要是试图说明正在为x创建一个闭包。

So makeAdder , here, is aptly named: when you pass 10 to it, it gives you a function that will add 10 to everything you pass to that new function . 所以makeAdder在这里恰当地命名:当你向它传递10时,它会为你提供一个函数 ,它将为你传递给新函数的所有内容添加10。

var add10 = makeAdder(10);
var add20 = makeAdder(20);

console.log(add10(1) + add20(1)); // 32

Surely, for the purpose of adding, it might be easier to just have a function that accepts two parameters and adds them. 当然,为了添加,可能更容易只有一个接受两个参数并添加它们的函数。 But this is not a lesson in adding, it is a lesson in closures. 但这不是一个补充的教训,它是闭包的一个教训。

A real world scenario might be something like this: 现实世界的场景可能是这样的:

var buttons = document.getElementsByClassName('myButton');
for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = function() {
        alert('You clicked button ' + i);
    };
}

In the above code, i will have iterated through the entire set before any of the buttons are clicked. 在上面的代码中, i将在点击任何按钮之前迭代整个集合。 Therefore, all buttons will alert whatever buttons.length is. 因此, 所有按钮都会提醒任何buttons.length是。 Instead, you could do the following: 相反,您可以执行以下操作:

var makeAlert = function(x) {
    return function() {
        alert('You clicked button ' + x);
    };
};

for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = makeAlert(i);
}

The difference here is that i is not being used when the button is clicked (which will be after the entire iteration), but it is used during the iteration, at a time when i will have a different value for each button. 这里的不同之处在于单击按钮时没有使用i (将在整个迭代之后),但是迭代期间使用它,此时i将为每个按钮设置不同的值。

Instead of creating a variable, makeAlert , you will often see this type of code being written as an anonymous function, invoked immediately. 您不会创建变量makeAlert ,而是经常会看到这种类型的代码被编写为匿名函数,并立即调用。 The code below is essentially equivalent to the code above: 下面的代码基本上等同于上面的代码:

for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = (function(x) {
        return function() {
            alert('You clicked button ' + x);
        };
    })(i);
}

What you're asking for is a function that does something for you: 你要求的是一个为你做点什么的功能:

  function giveMeAFunctionThatBeeps(){
    return function () {
         alert('Beep!');
        }
}

var beeper = giveMeAFunctionThatBeeps();

beeper(); // beeps!

The actual giveMeAFunctionThatbeeps is just a factory that gives you a function that does what you want. 实际的giveMeAFunctionThatbeeps只是一个工厂,它为您提供了一个能够满足您需求的功能。

In the example they have provided, you're doing the same thing as the beeper but you're also passing in a value: 在他们提供的示例中,您正在做与蜂鸣器相同的事情,但您也传递了一个值:

  function giveMeAFunctionThatBeepsANumber(x){
    return function () {
         alert('Beep ' + x);
        }
}

This returns a beeper (it's a factory remember), but the beeper alerts the value of x. 这会返回一个蜂鸣器(它是一个工厂记得),但蜂鸣器会提醒x的值。

However, this value is set when you first create the beeper: 但是,首次创建蜂鸣器时会设置此值:

var beeper = giveMeAFunctionThatBeeps(5);

beeper(); // beeps 5!

The beeper is stuck beeping the value 5 now, and we can't do anything about it. 蜂鸣器现在正在嘀咕着价值5,我们无法做任何事情。

The next example is if you want to create a beeper that beeps any number: 下一个示例是如果您要创建一个发出任何数字的蜂鸣声:

  function giveMeAFunctionThatBeepsANumber(){
    return function (x) {
         alert('Beep ' + x);
        }
}

var beeper = giveMeAFunctionThatBeeps();

beeper(6); // beeps 6!
beeper(7); // beeps 7!

As now we're asking the factory to give us a function we can plug a number into. 现在我们要求工厂给我们一个函数,我们可以插入一个数字。

Then lastly, the original example, is both of the above combined: 最后,最初的例子,是以上两者的组合:

  function giveMeAFunctionThatBeepsANumber(x){
    return function (y) {
         alert('Beep ' + (x + y));
        }
}

var beeper = giveMeAFunctionThatBeeps(2);

When we create the beeper, we're passing in 2. Remember as above, we can't change this afterwards! 当我们创建蜂鸣器时,我们正在传递2.记住,如上所述,我们之后无法改变它! It will always beep 2... 它会一直发出哔哔声......

...but because it's a factory (preconfigured with value 2) returning a function that takes a parameter, we can customise it when we run it: ...但是因为它是一个工厂(预先配置了值2)返回一个带参数的函数,我们可以在运行时自定义它:

beeper(6); // beeps 8! because x was set when we created it, and y is what we pass in.

Functions can be seen as special objects that contain executable code as well as properties. 函数可以看作包含可执行代码和属性的特殊对象。 Every function has a special [scope] property that represents the environment it was in when it was defined. 每个函数都有一个特殊的[scope]属性,表示定义它时所处的环境。 If a function is returned from another function then this reference to the old environment is closed over by the new function in a "closure". 如果从另一个函数返回一个函数,那么这个对旧环境的引用将由“闭包”中的新函数关闭。

so when you call var add10 = makeAdder(10) what happens is that the returned function's x has the value 10 which is bound to it's scope, and the call console.log(add10(2)) prints 12 . 所以当你调用var add10 = makeAdder(10)时,返回的函数的x的值是10 ,它绑定到它的作用域,并且调用console.log(add10(2))打印12

Consider reading this article for visualizing what are closures. 考虑阅读文章的可视化是什么倒闭。 A more detailed explanation of closure could be found here . 关于闭合的更详细解释可以在这里找到。

The function makeAdder returns a function when it is called. makeAdder函数在调用时返回一个函数。 This function that makeAdder returns accepts one parameter; makeAdder返回的这个函数接受一个参数; which is called y . 这叫做y

The variable y exists only during the invocation of the function returned by the makeAdder . 变量y仅在调用makeAdder返回的函数期间存在。 It is created each time is is called, and is destroyed when the function returns. 每次调用时都会创建它,并在函数返回时被销毁。

The variable x on the other hand is created when makeAdder is called, and persists due to the closure created by the function makeAdder returns. 另一方面,变量x是在调用makeAdder时创建的,并且由于makeAdder函数返回的闭包而持续存在。 It will be destroyed when no more references to the function returned exists. 当不再存在对返回函数的引用时,它将被销毁。

So add10 = makeAdder(10); 所以add10 = makeAdder(10); is actually returning this function: 实际上是返回此功能:

function(y) {
  console.log(y + " this is y")
  console.log("10" + " this is x")
  return 10 + y;
}

Then add10(2) is calling that function, replacing y with 2 everywhere: 然后add10(2)调用该函数,将y替换为2:

  console.log("2" + " this is y")
  console.log("10" + " this is x")
  return 10 + 2;

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

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