4.1 创建function
在JS中创建function的常用方法有两种:函数声明和函数表达式(还有一种使用Function创建的方法,一般很少用,本书就不介绍了)。
4.1.1 函数声明
函数声明的结构如下。
function函数名(参数) {函数体}
函数一共由4部分组成,第一部分是function关键字,这个是固定不变的;第二部分是函数名;第三部分是一对圆括号,里面存放函数的参数,可以为空,也可以有多个,如果有多个,则使用逗号分隔;第四部分是用花括号包含的函数体,它是函数的具体内容。例如下面的语句可以定义一个log函数。
function log(s) { console.log(s); }
这个函数的函数名为log,有一个s参数,函数体的内容是将参数打印到控制台。使用这个函数来打印日志比直接调用console.log(msg)的书写更为简单,而且如果都调用此函数来打印日志的话还可以很容易地修改打印方式。
4.1.2 函数表达式
函数表达式的结构与函数声明相比,是将函数声明中的函数名去掉,然后将创建的结果赋值给一个变量,例如前面的log函数可以使用下面的函数表达式来创建。
var log = function(s) { console.log(s); }
这样创建出来的log函数和前面通过函数声明创建出来的log函数基本没有区别。
4.1.3 两种创建方式的关系
在JS中所有的数据只有两种存在形式,要么是对象的属性,要么是变量(后面将详细讲解这两种形式的区别),函数也不例外,无论是对象的属性还是变量都是名值对的结构,因此函数也应该是这种名值对的结构,由函数表达式可以很容易看明白这一点。其实,通过函数声明方式创建函数时,JS在背后自动帮用户做了这件事情,它首先创建了函数对象,然后又创建了跟函数名同名的变量,并将创建出来的函数赋值给了这个变量。所以,前面通过函数声明创建的log函数等价于下面的语句。
var log = function log(s) { console.log(s); }
这一点使用FireBug可以清楚地看到。先在FireBug中执行下面的代码。
function F(a){} var f = F;
然后可以在FireBug的DOM选项卡中看到如图4-1所示的结构。
图4-1 FireBug中的DOM选项卡
从图4-1中可以看出,函数声明语句首先创建了名为F的函数,然后将其值赋给同名的F变量,在定义f变量的语句中f也指向了创建的F函数对象。此时内存中的结构如图4-2所示。
图4-2 f变量和F函数在内存中的结构
可以将F设置为null,然后使用f调用F函数对象。因为设置的F只是自动创建出来的变量,所以并不会影响F函数对象本身,也就不会影响f的调用,可以将上面的代码修改为如下代码。
function F(a){ console.log(a); } var f = F; F = null; f("hello function"); //输出hello function
此时的内存结构如图4-3所示。
图4-3 f变量在内存中的结构
上面讲的是通过函数声明创建的function对象。通过函数表达式来创建其实道理也差不多,不同之处在于它会创建一个匿名函数,然后再赋值给定义的变量。例如,在FireBug中执行如下代码。
var anonymous = function (b) {} var anony = anonymous;
此时,FireBug中的结构如图4-4所示。
图4-4 FireBug中的结构
此时,anonymous和anony两个变量都指向一个匿名函数,内存结构如图4-5所示。
图4-5 anonymous和anony两个变量都指向一个匿名函数的内存结构