6.7 函数结构
分支结构和循环结构都是在JavaScript执行期直接被运行的代码块,而函数体结构却是在预编译期就被处理的代码块,但是函数只有被调用时,JavaScript才会执行函数体内的代码,因此函数结构具有异步或延迟特性,利用这个特性可以设计用户交互行为。
6.7.1 function语句
function语句用来定义函数结构。具体用法如下:
function f([args]){ statements }
f是函数名,与变量名一样都是JavaScript合法的标识符,必须遵循JavaScript标识符命名约定。在函数名之后是一个由小括号运算符包含的参数列表,参数之间以逗号分隔,函数的参数是可选的。这些参数将作为函数体内的变量标识符被访问。调用函数时,用户可以通过函数参数来干预函数内部代码的运行。
在小括号之后是一个大括号分隔符,大括号内包含的语句就是函数体结构的主要内容。在函数体结构中,大括号是必不可少的,缺少了这个大括号,JavaScript将会抛出语法错误。
【示例1】function语句必须包含函数名称、小括号和大括号,其他的都可省略,因此最简单的函数体是一个空函数。
function f(){ //空函数 }
如果使用匿名函数,则可以省略函数名:
function(){ //匿名空函数 }
【示例2】与其他结构不同,function结构是静态的,不会立即执行,只有调用函数时,才能被执行。因此,一般把函数单独放在代码的顶部或尾部,很少在分支结构或循环结构中定义函数。
下面代码虽然不会引发语法错误,但是影响代码的后期维护和修改,一般不建议这样书写。
if(true) { function f() { } }
var语句和function语句都是变量声明语句,它们声明的变量都在JavaScript预编译时被解析。在预编译期,JavaScript解释器会把代码中的function语句定义为一个函数变量,同时解析函数体内部代码,把函数体内所有参数、私有变量、嵌套函数作为属性注册到函数调用对象上,以便在执行期调用函数时能够快速执行。
【示例3】当为var语句声明变量初始化时,这个初始化过程发生在执行期,而function语句声明的函数发生在预编译期。因此,当使用var语句和function语句定义同名变量时,就会发生冲突,且最终var语句声明的变量将覆盖function语句定义的同名函数。
f(); //调用函数,返回2 var f=1; //声明并初始化变量f function f(){ //声明函数变量f,并定义它的函数体结构 alert(2); } f(); //调用函数,返回语法错误,不存在该函数
上面示例被执行过程是这样的:
首先,在预编译期,JavaScript解释器会检索脚本中所有声明的变量,建立变量索引,如果发现同名变量,则后面声明的变量将覆盖前面的声明。因此,上面示例中的变量f在预编译期为一个对函数体结构的引用,而不是一个普通的数值。
然后,在执行期,JavaScript解释器会按顺序从上到下执行代码。当第一次调用函数时会弹出一个数字2。接着JavaScript重新为变量f赋值,因为变量初始化是发生在执行期,而不是预编译期。所以,当代码执行到第2行时,变量f不再指向一个函数体结构的引用,而代表是一个具体的数值。最终,导致当执行最后一行时,即为数值2调用函数时,引发语法错误。
6.7.2 return语句
函数结构是封闭的,对外界是不可见的。函数结构与外界交互方式:通过参数,接收外界信息;通过return语句,向外界传递信息。
return关键字后面可以跟随一个表达式,并把这个表达式的值作为函数的值返回。因此,return语句只能在函数体使用,否则JavaScript会抛出语法错误。
【示例1】在下面的代码中,使用return语句定义函数f的返回值为参数的平方。
function f(a){ return a*a; //返回参数的平方值 } alert(f(5)); //返回25
【示例2】在函数体内,return语句是可选项,如果省略return语句,函数返回值为undefined值。
function f(a){ } alert(f(5)); //返回undefined
return语句可以不带任何表达式或具体的值,此时函数将按默认状态返回undefined值。
【示例3】在下面代码中函数将返回一个空字符串。
function f(a){ return""; //返回空字符串 }
return语句除了能够为函数返回一个值外,它还有另外一个特殊功能:中止函数体运行。
【示例4】在下面代码中,利用return语句提前中止函数的进程。
function f(a){ if(a>10) return; return a*a; } alert(f(15)); //返回undefined alert(f(5)); //返回25