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