在javascript中返回函数,理解范围&关闭

时间:2011-12-13 10:39:09

标签: javascript

我正在关注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

现在我理解正在设置的X属性,但我没有得到的是y的范围如何受到影响。我知道它有一个返回功能,但我的大脑试图想象你如何设置一个没有参考的时候。有人能解释一下吗

5 个答案:

答案 0 :(得分:14)

makeAdder返回一个可以传递y参数的函数。它是在调用时设置的,而不是在创建新函数时设置的x(在调用makeAdder时)。

对于此示例的情况,输出等同于写入:

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

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

这里没有新的东西。示例代码主要是试图说明正在为x创建一个闭包。

所以makeAdder,恰好命名为:当你向它传递10时,它会为你提供一个函数,它会将你传递给所有新函数的所有内容添加10

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

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

当然,为了添加,可能更容易只有一个接受两个参数并添加它们的函数。但这不是一个补充的教训,它是封闭课程。

现实世界的场景可能是这样的:

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

在上面的代码中,i将在点击任何按钮之前迭代整个集合。因此,所有按钮都会提醒buttons.length。相反,您可以执行以下操作:

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

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

这里的不同之处在于单击按钮时将不使用i(将在整个迭代之后),但在迭代期间使用,一次何时i会 每个按钮都有不同的值。

您不会创建变量makeAlert,而是经常会看到这种类型的代码被编写为匿名函数,并立即调用。下面的代码基本上等同于上面的代码:

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

答案 1 :(得分:5)

你所要求的是一个为你做点什么的功能:

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

var beeper = giveMeAFunctionThatBeeps();

beeper(); // beeps!

实际的giveMeAFunctionThatbeeps只是一个工厂,它为您提供了一个能够满足您需求的功能。

在他们提供的示例中,您正在做与蜂鸣器相同的事情,但您也传递了一个值:

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

这会返回一个蜂鸣器(它是一个工厂记得),但是蜂鸣器警告x的值。

但是,首次创建蜂鸣器时会设置此值:

var beeper = giveMeAFunctionThatBeeps(5);

beeper(); // beeps 5!

蜂鸣器现在正在嘀嗒声5,我们无法做任何事情。

下一个例子是你想创建一个发出任何号码的蜂鸣声:

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

var beeper = giveMeAFunctionThatBeeps();

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

现在我们要求工厂给我们一个函数,我们可以插入一个数字。

最后,最初的例子,都是以上两者的组合:

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

var beeper = giveMeAFunctionThatBeeps(2);

当我们创建蜂鸣器时,我们正在传递2.记住,如上所述,之后我们无法改变它!它总是会发出哔哔声...... ...

...但是因为它是一个工厂(预先配置了值2),返回一个带参数的函数,我们可以在运行时自定义它:

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

答案 2 :(得分:2)

可以将函数视为包含可执行代码和属性的特殊对象。每个函数都有一个特殊的[scope]属性,表示定义它时所处的环境。如果从另一个函数返回一个函数,那么这个对旧环境的引用将被“闭包”中的新函数关闭。

所以当你调用var add10 = makeAdder(10)时会发生的事情是返回的函数x的值10与其范围绑定,并且调用console.log(add10(2))打印{{ 1}}。

考虑阅读this文章,以便可视化什么是闭包。关于封闭的更详细解释可以找到here

答案 3 :(得分:1)

函数makeAdder在调用时返回一个函数。 makeAdder返回的此函数接受一个参数;这被称为y

变量y仅在调用makeAdder返回的函数期间存在。它是在每次调用时创建的,并在函数返回时被销毁。

另一方面,变量x在调用makeAdder时创建,并且由于函数makeAdder创建的闭包而返回。当不再有对返回函数的引用时,它将被销毁。

答案 4 :(得分:1)

所以add10 = makeAdder(10);实际上正在返回此函数:

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

然后add10(2)正在调用该函数,将y替换为2:

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