var f = function g(){ return 23; };typeof g();//报错
这里如何理解?
我的理解是:g()代表了调用函数,结果为什么不是number呢?
请大神讲解
var f = function g(){ return 23; };typeof g();//报错
这里如何理解?
我的理解是:g()代表了调用函数,结果为什么不是number呢?
请大神讲解
var f = function g(){ return 23; };typeof g();//报错
会有这段代码的来由,主要是IE8前的浏览器并不会报错,而是呈现你要的结果,也就是'number'字符串。
其他楼主的回答并是正确的,我只是来补充一些的。
JS中对于函数的声明语法在标准中就有两种不同的语法样式,其一称为函数声明
,另一个是函数表达式
,实际上标准中也写得很简略,像下面这样,上面的是函数声明
下面则是函数表达式
,opt记号代表的是可选的,也就是可有可无的意思:
FunctionDeclaration :
function Identifier ( FormalParameterList opt ){ FunctionBody }
FunctionExpression :
function Identifier opt ( FormalParameterList opt ){ FunctionBody }
所以在函式表达式
这种样式,函数的识别名是可以不需要有的,但它因为是个表达式
,可以赋给另一个变量当值来看待,所以才会有像var f = function(){ return 23 }
的这种写法。
要分辨何者是函数声明
又何者是函式表达式
,最简单的方式就是看语句的开头,以function
作为该语句开头的函数语句,应该就是函数声明
,函式表达式
不会以function开头,所以下面的几例都是函式表达式
:
var a = function() {
return 3;
}
var a = function bar() {
return 3;
}
(function sayHello() {
alert("hello!");
})();
而为何会有两种不同的函数语法样式,是这两种样式的用处不同。最明显的例子是函数声明
有特殊的提升(hoisting)特性,在同一作用域中的函数声明
会先被提升到此作用域的最上面,所以函数声明
可以写在代码文档的后面,但可以在代码文档的上面使用。此外,函数声明
只能在函数中块级或整个应用的全局区中使用,它没办法在其他的块级中使用,例如像if、for等的花括号({})中。而在某些情况下,当需要把函数整体作为一种值,用来当其他函数的传参或返回时,例如回调函数的语法结构,就是要使用函式表达式
的样式才可以达到。当然,基本上这两者看起来好像都是长得一样,实际上在执行阶段的运作并不相同。
不过,本题的重点是在于有名称的函数表达式,也就是所谓的"具名函数表达式"(Named function expressions,NFE),这个函数的识别名,它的作用域到底是在什么地方,答案是在函数的主体(FunctionBody)内部。原因当然它只是个原本就可有可无的"代理"函数名,真正的这函数识别名称是被赋值的那个变量识别名。
正常情况下,你只能在函数表述式中的主体中使用这个"代理函数名",这也是符合标准的规定,如下面的例子:
var f = function foo(){
return typeof foo;
};
typeof foo; // "undefined"
f(); // "function"
那么又为何要使用这个"代理函数名",不是可有可无的吗?
因为这个名称在调试时,可以明确地在呼叫堆叠中看到,如果是不加这名称,也就是"匿名函数表达式"在调试时是看不准是呼叫什么的。这使得调试时多了一些便利,所以它会被用在这个情况下。
话又说回上面所说的在IE8之前的版本,怎么又能用这个"代理函数名",像一般的函数声明
一样了?
因为以IE8来说,它里面的JS引擎并不是现在的标准ECMAScript规范,而是JScript 5.8。
IE8并没有设计这个封闭作用域,来界定出函数表达式的作用域,而且,在IE8中认为这种有"具名函数表达式",相等于函数声明
。最厉害的一点是,IE8还会认为这两个函数(被赋值的变量与这个代理名)是两个不同的函数物件,例如下面的例子:
var f = function foo(){
return 23;
}
alert(f === foo); //false
所以,本题的解答是因为具名函数表达式
的这个代理函数名,被限制在函数表达式内的作用域才能使用,所以会造成浏览器报错,但在IE8以下的IE浏览器则是可以正常运作。
以上的资料主要参考Named function expressions demystified与Function Declarations vs. Function Expressions
8 回答4.9k 阅读✓ 已解决
6 回答3.6k 阅读✓ 已解决
5 回答2.9k 阅读✓ 已解决
5 回答6.5k 阅读✓ 已解决
4 回答2.3k 阅读✓ 已解决
4 回答2.8k 阅读✓ 已解决
3 回答2.5k 阅读✓ 已解决
var x = function y(){//...};
这种形式,被《JavaScript忍者秘籍》叫做内联命名函数,它有个特点,就是这里的x是对外可见的,但y是被x“金屋藏娇”的,也就是说,y受限于x的作用域、对外不可见。所以建议改成:
(如果直接log
typeof f();
这样,控制台会打出个“function”,貌似意义不大……当然直接console.log(typeof f());
打个“number”也ok~)