我正在关注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的范围如何受到影响。我知道它有一个返回功能,但我的大脑试图想象你如何设置一个没有参考的时候。有人能解释一下吗
答案 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}}。
答案 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;