请教一下js函数调用后,所返回函数,的调用。
代码一:
function show(){
alert(12);
return function(){
alert(3);
};
}
alert(show()());
我觉得这段函数应该会报错,因为 下面的show(括号一),返回的是
function(){ alert(3); }
那么这个返回的函数后面还有一个括号来调用它,即
function(){ alert(3); }()
。
我在全局环境下,写这段代码就会报错,
function(){ alert(3); }()
。
请问为什么代码一所示函数就可以正常运行呢?谢谢。
Answers
不好意思
可以参考知乎中的回答
http://www.zhihu.com/question/20292224
1)函数声明、函数表达式
function(){alert(3);}();
函数声明不能立即执行
函数表达式可以的
解析器识别函数声明的条件是执行语句以function关键字开始,那么自然,只要在function关键字的前面有任何其他的元素,就会从函数定义转变为函数表达式
所以
~function() {}();
!function() {}();
void function() {}();
可以执行的
而
function(){alert(3);}();
解析为函数申明,会报语法解析错误
2)括号的作用
(function(){alert(3);})();
确定优先级及分组运算,会将括号中语句作为表达式运行
代码一其实是 函数柯里化 即 将函数当做值传递给下一个函数,形如
show() --> 值
var k = show();
var g = k();
g是结果
那么你的这句为什么会报错呢?
function(){
alert(3);
}()
因为JavaScript可以执行函数表达式,但是不能执行函数声明,也就是说,JavaScript把
function(){
alert(3);
}
当做了函数声明,想要正常运行,在函数声明的外部套一对小括号即可,像这样:
(function(){
alert(3);
})();
当然,想要套其他的玩意也行,比如:
+function(){
alert(3);
}();
-function(){
alert(3);
}();
以上
其他地方你的理解是对的,但是你搞错了一点:
我觉得这段函数应该会报错,因为 下面的show(括号一),返回的是
function(){ alert(3); } 那么这个返回的函数后面还有一个括号来调用它,即function(){ alert(3); }()。
show()返回的并不是函数的那一大段,函数是存在内存里的,返回的只是指向这个函数的引用。
说到这里你可能还不太理解什么叫引用,简单来说就是:对象本身存在内存的某个位置,而变量只能持有一个指向这个位置的标记。你可以想一想C语言里的指针。
这时就好理解了,
show()()
并不是
function () {
alert(3);
} ()
这只是简单的字符串替换,JavaScript并不是这么工作的。
return function () {
alert(3);
}
这段代码的实际过程是:在内存中创建匿名函数,将这个函数的引用返回出去。
所以
show()
得到的是对匿名函数的引用x,然后
x()
执行了这个匿名函数。
所以根本不会有什么错误。
说了这么多题主并不一定能完全理解,所以给出一些代码,题主可以试一试。
var fa = function() {
alert('hello,world');
};
var fb = function() {
alert('hello,world');
}
alert(fa === fb); //结果是false
这是因为内存中出现了两个长得完全一样的函数,但是他们仍然是两个函数。
进一步:
alert(
function () { return 1 } === function () { return 1; }
); //结果仍然是false
现在考虑向一个函数传入另一个函数呢?
var f = function (x) {
alert('执行f,下面将执行x');
x();
alert('x执行完了,现在已经回到了f中');
}
f(function () {
alert('x执行中');
});
题主不妨亲自试一试。
上面的代码说明了在JavaScript中,函数和其他的引用类型一样,可以方便地传入另一个函数,被函数返回,当然,传入和返回的都只是对函数的引用,而不是函数本身,更不是函数的那段字符串。
函数表达式有两种,匿名的和具名的:
var af = function () {
//这是一个匿名函数表达式
};
var nf = function name() {
//这是一个具名函数表达式
};
匿名函数表达式很容易看出来,就是没有名字嘛啊哈哈哈。
具名函数表达式则需要和函数声明语法进行区别:
function name () {
//这是一个函数声明
}
var nf = function name() {
//这是将一个函数表达式赋值给一个变量
};
实际上只有明显的使用上面代码中那种函数声明方式,JS才会把它当作是声明,否则就会当作表达式,比如 @qianjiahao 提到的那几种形式:
(function name() {
//不管有没有函数名,这个东西都会被看作是函数表达式
}());
其他形式可以参考 @qianjiahao 的答案。
具名函数表达式(NFE)和函数声明还有一个有意思的区别,就是在NFE中,你可以访问函数名但是不能修改函数名。
例如:
function f1() {
console.log(f1); //执行后显示函数f1本身
f1 = 42;
console.log(f1); //执行后显示42
}
f1();
var f2 = function nfe() {
console.log(nfe); //执行后显示函数nfe本身
nfe = 17;
console.log(nfe); //执行后还是显示nfe本身,也就是说上面写nfe这个操作是无效的。
}
更详细的内容参考我之前的问题: http://segmentfault.com/q/1010000002810093