javascript中的返回函数,理解作用域&闭包
Returning functions in javascript, understanding scope & closures
我在Mozillas的开发者网站上看javascript闭包,他们有这样一个代码示例。
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的范围如何受到影响。我知道这是一个返回函数,但我的大脑在试图想象如何在没有返回的情况下设置y时陷入了混乱。有人能解释一下吗?
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);
}
你要求的是一个为你做某事的函数:
function giveMeAFunctionThatBeeps(){
return function () {
alert('Beep!');
}
}
var beeper = giveMeAFunctionThatBeeps();
beeper(); // beeps!
实际的givemefunctionthatbeeps只是一个工厂,它给你一个函数,做你想做的事。
在他们提供的例子中,你正在做与寻呼机相同的事情,但你也传递了一个值:
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);
创建beeper时,传递的是2。记住如上所述,我们不能在之后更改它!它会一直发出哔哔声…
…但是因为它是一个工厂(预配置值为2),返回一个接受参数的函数,所以我们可以在运行它时自定义它:
beeper(6); // beeps 8! because x was set when we created it, and y is what we pass in.
函数可以看作是包含可执行代码和属性的特殊对象。每个函数都有一个特殊的[scope]属性,表示它被定义时所处的环境。如果一个函数从另一个函数返回,那么这个对旧环境的引用将被"闭包"中的新函数关闭。
所以当你调用var add10 = makeAdder(10)
时,所发生的是返回函数的x
具有绑定到它的作用域的值10
,并且调用console.log(add10(2))
打印12
。
考虑阅读这篇文章,了解什么是闭包。关于闭包的更详细的解释可以在这里找到
函数makeAdder
在调用时返回一个函数。makeAdder
返回的函数接受一个参数;即y
.
变量y
仅在调用makeAdder
返回的函数时存在。它在每次调用时创建,并在函数返回时销毁。
另一方面,变量x
是在makeAdder
被调用时创建的,并且由于makeAdder
函数返回的闭包而持续存在。当不再存在对返回函数的引用时,该函数将被销毁。
所以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;
- 作用域问题-此函数是否形成闭包-JavaScript
- 使用JavaScript回调函数了解变量作用域和闭包
- 具有闭包函数作用域的意外行为
- 作为闭包的回调中的Javascript变量作用域
- javascript中的返回函数,理解作用域&闭包
- JavaScript闭包和作用域问题
- 为什么我的内部内部函数可以访问外部全局作用域变量?这是不是违反了作用域/闭包
- 闭包回调中参数的作用域
- javascript中的闭包只限制变量的作用域吗?
- 将作用域变量传递给在该作用域之外声明的闭包
- 闭包在函数作用域之外不起作用
- 将变量添加到函数作用域/闭包中.函数相当于窗口对象
- 如何程序设置Javascript getter/setter ?(或者实际上是闭包作用域)
- 当使用块作用域变量创建JS闭包时会发生什么?
- 如何在ES2015中解构所有属性到当前作用域/闭包
- 在闭包作用域中设置变量
- 从外部(即定义闭包的作用域)访问闭包内部定义的var
- 显式地将变量作用域设置在函数内而不是闭包内
- 在chrome开发工具中调试带有词法作用域(闭包)的angularjs指令时的奇怪行为
- Javascript作用域/闭包泄漏