杨__羊羊
我们从规范出发,看看EcmaScript的上下文无关文法。参考《ECMA-262, 3rd edition, December 1999》。ES3简单一些,ES6同理。Program :SourceElementsSouceElements :SouceElementSouceElements SourceElementSouceElement :StatementFunctionDeclarationStatement :BlockVariableStatementEmptyStatementExpressionStatementIfStatementIterationStatementContinueStatementBreakStatementReturnStatementWithStatementLabelledStatementSwitchStatementThrowStatementTryStatementExpressionStatement :[lookahead ∉ {{, function}] Expression ;FunctionDeclaration :function Identifier ( FormalParameterList[opt] ) { FunctionBody }这几个产生式表明了以Program为根的语法树结构。- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(1)首先,“function(){}()”无法归约为CallExpression。CallExpression<- LeftHandSideExpression<- PostfixExpression<- UnaryExpression<- MultiplicativeExpression<- AdditiveExpression<- ShiftExpression<- RelationalExpression<- EqualityExpression<- BitwiseANDExpression<- BitwiseXORExpression<- BitwiseORExpression<- LogicalANDExpression<- LogicalORExpression<- ConditionalExpression<- AssignmentExpression<- Expression[失败了] <- ExpressionStatement<- Statement<- SourceElement<- SourceElements<- Program失败的原因是,Expression要想归约为ExpressionStatement,就不能以左大括号“{”或“function”开头。(2)那么,我们只能认为“function(){}()”是由两部分构成的了。program-> SourceElements-> SourceElements SourceElement-> SourceElement SourceElement把“funtion(){}”和“()”都分别向SourceElement归约。然而,这又不行。(3)“funtion(){}”无法归约为SourceElement。因为,无论是先归约为Statement,还先归约为FunctionDeclaration都不行。归约为Statement要求不能以function开头,(与上面的失败原因相同)归约为FunctionDeclaration要求必须指定函数名。(4)然而,我们又没有其他归约方法了,只能失败了。- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -而加上符号以后,例如“!function(){}()”,并不是以“function开头”的,所以通过了Expression到ExpressionStatement的归约。!function(){}()<- ! function Identifier[opt] ( FormalParameterList[opt] ) { FunctionBody } Arguments<- ! FunctionExpression Arguments<- ! MemberExpression Arguments<- ! CallExpression<- ! LeftHandSideExpression<- ! PostfixExpression<- ! UnaryExpression<- UnaryExpression<- MultiplicativeExpression<- AdditiveExpression<- ShiftExpression<- RelationalExpression<- EqualityExpression<- BitwiseANDExpression<- BitwiseXORExpression<- BitwiseORExpression<- LogicalANDExpression<- LogicalORExpression<- ConditionalExpression<- AssignmentExpression<- Expression<- ExpressionStatement<- Statement<- SourceElement<- SourceElements<- Program同理可以推导(function(){}()),(function(){})()- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -值得指出的是,“function(){}()”就算指定了函数名,也不行。因为后面的“()”同样不能归约为SourceElement。而“function f(){}(1)”就是合法的,“function f(){}”归约为FunctionDeclaration,而“(1)”可以归约为Expression,视为括号运算符,或称为分组运算符。(Expression)<- PrimaryExpression<- MemberExpression<- NewExpression<- LeftHandSideExpression<- PostfixExpression<- UnaryExpression<- MultiplicativeExpression<- AdditiveExpression<- ShiftExpression<- RelationalExpression<- EqualityExpression<- BitwiseANDExpression<- BitwiseXORExpression<- BitwiseORExpression<- LogicalANDExpression<- LogicalORExpression<- ConditionalExpression<- AssignmentExpression<- Expression