Javascript支持First Class Functions,在这种情况下,我们可以将函数作为参数传递。在另一个函数的参数列表中定义的匿名函数,该匿名函数的词法环境(即范围)是什么?
例如:
var m = 2;
(function(p1,p2){
p2(p1);
})(true, function(p1){ // an anonymous function passed as an argument.
m = 3;
if(p1){...}
}); // the end of self-invoked function expression.
答案 0 :(得分:2)
该函数可以访问定义它的范围,并包括任何父范围(例如全局/窗口)。如果在另一个函数内部定义,它将可以访问该函数中定义的任何变量。如果像回调一样作为参数传入,它将无法访问传递给它的函数中定义的变量,因为它是在该函数之外定义的并作为参数传入。
示例:
var a = 1;
(function(callback){ //func1
//access variable in parent scope
console.log('func1', a); //outputs 1
//define a new variable within this function's scope
var b = 2;
//call our callback
callback();
//define and call a function within this function's scope
(function(){ //func3
//access variable in parent scope
console.log('func3', a); //outputs 1
//access variable in parent function scope
console.log('func3', b); //outputs 2
})();
})(function(){ //func2
//access variable in parent scope
console.log('func2', a); //outputs 1
//access variable from invoking function
console.log('func2', b); //outputs undefined
});
这会输出类似:
func1 1
func2 1
func2 undefined
func3 1
func3 2
其中所有函数都可以看到变量a
,因为它位于所有函数的父作用域中。参数函数无法看到变量b
,因为b
在另一个函数中定义,参数函数在外部定义并作为参数传入。第一个函数中定义的函数可以同时看到a
和b
。
答案 1 :(得分:1)
调用IIFE实际上与首先将函数分配给变量,然后通过该变量调用函数相同;与任何其他匿名函数的使用一样,它只是一个避免给函数命名的快捷方式。所以:
(function(p1,p2){
p2(p1);
})(true, function(p1){ // an anonymous function passed as an argument.
m = 3;
if(p1){...}
});
相当于:
var temp = function(p1,p2){
p2(p1);
};
temp(true, function(p1) {
m = 3;
if(p1){...}
});
除了向外部范围添加temp
之外;由于此变量不会出现在其他任何地方,因此无效。所有其他变量的范围在两种情况下是相同的。
答案 2 :(得分:1)
如果您不确定调用的参数列表中定义的函数范围是什么,请注意
fn(function x(…) { … })
相当于
_temp = function x(…) { … };
fn(_temp)
在实际调用之前评估参数,并且在与评估调用本身相同的范围内对它们进行评估。