javascript_函数

本文深入探讨了ECMAScript中的函数概念,包括基本语法、参数处理、Function类及闭包等高级特性。揭示了如何利用这些特性进行高效编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数是一组可以随时随地运行的语句,它们是ECMAScript的核心。函数是由关键字function、函数名加一组参数以及置于括号中的要执行的代码声明的。函数的基本语法如下:
例如:
函数可以通过其名字加置于括号中的参数(如果有多个参数,中间用逗号分隔)调用。调用sayHi()函数的代码如下:
这段代码生成的警告窗口如图2-8所示。
图  2-8
函数sayHi()未声明返回值,不过不必专门声明它(如在Java中使用void)。同样的,即使函数确实有返回值,也不必明确地声明它。该函数只需要使用return运算符后跟要返回的值即可。
下面的代码把sum函数返回的值赋予一个变量:
另一个重要的概念是,与在Java中一样,函数在执行过return语句后停止执行代码。因此,return语句后的代码都不会被执行。例如,下面函数中的警告信息就不会显示:
一个函数中可以有多个return语句,如下所示:
上面的函数用于返回两个数字的差。要实现这一点,必须用较大的数减去较小的数,因此用if语句决定执行哪个return语句。
如果函数无返回值,那么可以调用没有参数的return运算符,随时退出函数。例如:
这段代码中,如果消息不等于字符串"bye",就永远都不会显示警告消息。
如果函数无明确的返回值,或调用了没有参数的return语句,那么它真正返回的值是undefined
2.11.1  无重载
ECMAScript中的函数不能重载。考虑到ECMAScript与其他支持重载的高级程序设计语言相似,所以它不支持重载的特点不免让人感到意外。可用相同的名字在同一个作用域中定义两个函数,而不会引发错误,但真正使用的是后一个函数。考虑下面的例子:
你认为这段代码会显示什么?警告将显示"20",因为第二个doAdd()函数的定义覆盖了第一个定义。虽然这让开发者有些头痛,不过可以使用arguments对象避开这种限制。
2.11.2  arguments对象
在函数代码中,使用特殊对象arguments,开发者无需明确指出参数名,就能访问它们。例如,在函数sayHi()中,第一个参数是message。用arguments[0]也可以访问这个值,即第一个参数的值(第一个参数位于位置0,第二个参数位于位置1,依此类推)。因此,无需明确命名参数,就可以重写函数:
还可用arguments对象检测传递给函数的参数个数,引用属性arguments.length即可。下面的代码将输出每次调用函数使用的参数个数:
这个代码段将依次显示"2""0""1"。有了arguments对象,开发者就要检查传递给函数的参数个数。
与其他程序设计语言不同,ECMAScript不会验证传递给函数的参数个数是否等于函数定义的参数个数。开发者定义的函数都可以接受任意个数的参数(根据Netscape的文档,最多能接受25个),而不会引发任何错误。任何遗漏的参数都会以undefined传递给函数,多余的参数将忽略。
arguments对象判断传递给函数的参数个数,即可模拟函数重载:
只有一个参数时,doAdd()函数才会给数字加10,如果有两个参数,只是把这两个数相加,返回它们的和。所以doAdd(10)输出的是"20",而doAdd(30,20)输出的是"50"。虽然不如重载那么好,不过已足可避开ECMAScript的这种限制。
2.11.3  Function
ECMAScript最令人感兴趣的可能莫过于函数实际上是功能完整的对象。Function类可以表示开发者定义的任何函数。用Function类直接创建函数的语法如下:
在这种形式中,每个argument都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。记得下面这个函数吗?
还可以如下定义它:
诚然,因为字符串的关系,这种形式写起来有些困难,但有助于理解函数只不过是一种引用类型,它们的行为与用Function类明确创建的函数行为相同。还记得下面的例子吗?
如你所知,第二个函数重载了第一个函数,使doAdd(10)输出了"20",而不是"110"。如果以下面的形式重写该代码块,这种概念就清楚了:
观察这段代码,很显然,doAdd的值被改成了指向不同对象的指针。函数名只是指向函数对象的引用值,行为就像其他指针一样。甚至可以使两个变量指向同一个函数:
这里,变量doAdd被定义为函数,然后alsoDoAdd被声明为指向同一个函数的指针。用这两个变量都可以执行该函数的代码,输出相同的结果——"20"。因此,如果函数名只是指向函数的变量,那么可以把函数作为参数传递给另一个函数吗?是的!
在这个例子中,callAnotherFunction()有两个参数——要调用的函数和传递给该函数的参数。该代码把doAdd()函数传递给callAnotherFnction()函数,参数为10,输出"20"
尽管可用Function构造函数创建函数,但最好不要使用它,因为用它定义函数比用传统方式要慢得多。不过,所有函数都应看作是Function类的实例。
因为函数是引用类型,所以它们也有属性和方法。ECMAScript定义的属性length声明了函数期望的参数个数。例如:
函数doAdd()定义了一个参数,因此它的length1sayHi()没有定义参数,所以length0。记住,无论定义了几个参数,ECMAScript函数可以接受任意多个参数(最多25个)。属性length只是为查看默认情况下预期的参数个数提供了一种简便的方式。
文本框:
图  2-9
Function对象也有与所有对象共享的标准valueOf()方法和toString()方法。这两个方法返回的都是函数的源代码,在调试时尤其有用。例如:
这段代码输出了doAdd()函数的文本(如图2-9所示)。
还有两个Function类的方法与对象的讨论相关,下一章将讨论它们。
2.11.4  闭包
ECMAScript最容易让人误解的一点是它支持闭包(closure)。所谓闭包,是指词法表示包括不必计算的变量的函数,也就是说,该函数能使用函数外定义的变量。在ECMAScript中使用全局变量是一个简单的闭包实例。考虑下面的代码:
在这段代码中,脚本被载入内存后,并未为函数sayHelloWorld()计算变量sMessage的值。该函数捕获sMessage的值只是为以后使用,也就是说,解释程序知道在调用该函数时要检查sMessage的值。sMessage将在函数调用sayHelloWorld()时(最后一行)被赋值,显示消息"Hello World!"
在一个函数中定义另一个函数会使闭包变得更复杂,如下所示:
var iBaseNum = 10;
 
function addNumbers(iNum1, iNum2) {
     function doAddition() {
          return iNum1 + iNum2 + iBaseNum;
     }
     return doAddition();
}
这里,函数addNumbers()包括函数doAddition()(闭包)。内部函数是个闭包,因为它将获取外部函数的参数iNum1iNum2以及全局变量iBaseNum的值。addNumbers()的最后一步调用了内部函数,把两个参数和全局变量相加,并返回它们的和。这里要掌握的重要概念是doAddition()函数根本不接受参数,它使用的值是从执行环境中获取的。
可以看到,闭包是ECMAScript中非常强大多用的一部分,可以用于执行复杂的计算。就像使用任何高级函数一样,在使用闭包时要当心,因为它们可能会变得非常复杂。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值