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

mus*_*afa 12 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
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*und 14

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

对于此示例的情况,输出相当于已写入:

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

console.log(add10(2)); // 12
Run Code Online (Sandbox Code Playgroud)

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

因此makeAdder,在这里,恰当地命名:当你向它传递10时,它会为你提供一个函数,它将为你传递给新函数的所有内容添加10 .

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

console.log(add10(1) + add20(1)); // 32
Run Code Online (Sandbox Code Playgroud)

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

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

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

在上面的代码中,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);
}
Run Code Online (Sandbox Code Playgroud)

这里的区别i在于单击按钮时没有使用(将在整个迭代之后),但是迭代期间使用它,在i每个按钮具有不同值的时候.

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

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


Nib*_*Pig 5

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

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

var beeper = giveMeAFunctionThatBeeps();

beeper(); // beeps!
Run Code Online (Sandbox Code Playgroud)

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

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

  function giveMeAFunctionThatBeepsANumber(x){
    return function () {
         alert('Beep ' + x);
        }
}
Run Code Online (Sandbox Code Playgroud)

这会返回一个蜂鸣器(它是一个工厂记得),但蜂鸣器会提醒x的值.

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

var beeper = giveMeAFunctionThatBeeps(5);

beeper(); // beeps 5!
Run Code Online (Sandbox Code Playgroud)

蜂鸣器现在正在嘀咕着价值5,我们无法做任何事情.

下一个示例是如果您要创建一个发出任何数字的蜂鸣声:

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

var beeper = giveMeAFunctionThatBeeps();

beeper(6); // beeps 6!
beeper(7); // beeps 7!
Run Code Online (Sandbox Code Playgroud)

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

最后,原始示例,以上两者合并:

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

var beeper = giveMeAFunctionThatBeeps(2);
Run Code Online (Sandbox Code Playgroud)

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

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

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