显然 var f = function g(){ return 23; }; 是一段语句,而非函数声明。具体来说,是一段变量语句 (VariableStatement) 。等号右侧被解释为赋值语句 (AssignmentExpression) ,再经过一系列的解释后,被确定为函数表达式。等号左侧变量将被赋值为右侧函数表达式解释执行后的引用。
因此问题的关键在于函数表达式是如何解释执行的。
再看函数表达式的语法,函数名是一个可选项。而函数名的有无,函数表达式的解释执行步骤有着巨大的差异。
function ( FormalParameterListopt ) { FunctionBody }
这种形式叫做命名的函数表达式,它的名字g只在函数体内可见。在函数外部不可见,所以报错。
你在函数体内
console.log(g)
试一下。详情参考ECMAScript。
var f = function g(){ return 23; };
运行后,g就没有了。
上述代码等同于
而如果是
那么g还是存在的。
typeof 引用
这种问题也跑来问?看下错误具体信息就知道是函数 g 没定义,为什么没定义呢?肯定是定义的部分出错了嘛,动动脑子啊,哥们儿。
强行回答一个~ 补充一下@manxisuo 的答案。
(以下截图均来自ES5标准文档,内容是本人阅读后的理解)
首先,我们知道函数的定义有两种方式:
函数声明 (FunctionDeclaration)
函数表达式 (FunctionExpression)
函数声明在程序 (Program) 中有着非比寻常的优先级:
一段ES程序就是由语句 (Statement) 和函数声明组成的。
显然 var f = function g(){ return 23; }; 是一段语句,而非函数声明。具体来说,是一段变量语句 (VariableStatement) 。等号右侧被解释为赋值语句 (AssignmentExpression) ,再经过一系列的解释后,被确定为函数表达式。等号左侧变量将被赋值为右侧函数表达式解释执行后的引用。
因此问题的关键在于函数表达式是如何解释执行的。
再看函数表达式的语法,函数名是一个可选项。而函数名的有无,函数表达式的解释执行步骤有着巨大的差异。
function ( FormalParameterListopt ) { FunctionBody }
当没有函数名时,函数表达式的解释执行与函数声明相似,作用域即为当前执行的词法环境。后者,函数声明会执行一个抽象方法CreateMutableBinding,在环境记录项中创建一个新的可变绑定(即变量)。从这里可以知道,新创建的变量就在当前的作用域内。
function Identifier ( FormalParameterListopt ) { FunctionBody }
重点来了,指定了函数名的函数表达式,会首先执行一个抽象方法NewDeclarativeEnvironment,该方法创建一个空的新词法环境,并把 当前的执行环境 引用为 新的词法环境的外部词法环境。然后以新的词法环境为作用域,执行了接下来的步骤,并最后将函数的引用交给左侧的变量。因此这里的函数名,是绑定在新的词法环境中的,外部环境也就无法找到函数名,抛出了ReferenceError。
另外@manxisuo 所说,也同样可以解释了。
以上。
Reference
ECMA-262标准文档
ES5/函数定义 - HTML5 Chinese Interest Group Wiki