3.2 函数
当某一段代码需要重复使用,或者需要对批量数据执行相同操作时,就可使用函数来完成。
了解函数的用途
3.2.1 定义函数
定义函数
1. 函数的语句定义方法
JavaScript用function关键字来声明函数,基本语法格式如下。
function 函数名([参数1 , 参数2 , …]){ 代码块 [return 返回值] }
在当前脚本中,函数名应该是唯一的。函数参数是可选的。多个参数之间用逗号分隔。大括号中的代码块称为函数体。在函数体中或在函数末尾,可使用return语句指定函数返回值。返回值可以是任意的常量、变量或者表达式。
例如,下面的函数用于计算两个数的和。
function sum(a, b) { return a + b }
2. 在表达式中定义函数
JavaScript允许在表达式中定义函数。例如,在表达式中定义求和函数。
var sum2 = function (a, b) { return a + b }
3. 使用Function构造函数
在JavaScript中,函数也是一种对象。函数对象的构造函数为Function,可用它来定义函数,其基本语法格式如下。
var 变量 = new Function( "参数1" , "参数2" ,…, "函数体")
例如:
var sum3 = new Function("a" , "b" , "return a+b")
提示
function关键字定义了一个函数对象,这与Function构造函数一致。在语句定义方法中,函数名用于引用定义的函数对象。在表达式或使用Function构造函数定义函数时,赋值语句左侧的变量用于引用定义的函数对象。
3.2.2 调用函数
调用函数
函数调用的基本语法格式如下。
函数名(参数)
如果是在表达式中或使用Function构造函数定义的函数,则用变量名作为函数名。
使用function关键字在语句中定义函数时,函数的定义可以放在当前页面中的脚本的任意位置,即允许函数的调用出现在函数定义之前。在表达式中或使用Function构造函数定义函数时,只能在定义之后通过变量名来调用函数。
函数可以在脚本中调用,也可以作为HTML的事件处理程序或URL。
【例3-17】 在脚本中调用函数。源文件:03\test3-17.html。
… <body> <script> document.write('1 + 2 = ' + sum(1, 2)) //在函数sum的定义之前调用函数 function sum(a, b) { return a + b } var sum2 = function (a, b) { return a + b } var sum3 = new Function("a", "b", "return a+b") document.write('<br>3 + 4 = '+ sum2(3, 4)) //调用表达式中定义的函数 document.write('<br>5 + 6 = '+ sum3(6, 5)) //调用构造函数定义的函数 document.write('<br>7 + 8 = '+ sum(7, 8)) //调用语句中定义的函数 </script> </body> </html>
浏览器中的运行结果如图3-17所示。
图3-17 在脚本中调用函数
【例3-18】 将函数作为HTML的事件处理程序。源文件:03\test3-18.html。
… <body> <script> function test() { document.write("<br>调用了test()函数") } </script> <button onclick="test()">调用test()函数</button> </body> </html>
在浏览器中单击“调用test()函数”按钮时,会打开提示对话框,如图3-18所示。
图3-18 将函数作为HTML的事件处理程序
【例3-19】 将函数作为URL。源文件:03\test3-19.html。
… <body> <script> function test() { alert("调用了test()函数") } </script> <a href="javascript:test()">调用test()函数</a> </body> </html>
在浏览器中单击“调用test()函数”链接时,会打开提示对话框,如图3-19所示。
图3-19 将函数作为URL
3.2.3 带参数的函数
函数在定义时指定的参数称为形式参数,简称形参。调用函数时指定的参数称为实际参数,简称实参。在调用函数时,实参的值按先后顺序、一一对应地传递给形参。
带参数的函数
JavaScript是弱类型的,形参不需要指定数据类型。JavaScript不会检查形参和实参的数据类型,也不会检查形参和实参的个数。
1. 关于函数的参数个数
函数的length属性返回形参的个数。在函数内部,arguments数组保存调用函数时传递的实参。
【例3-20】 使用arguments数组获取实际参数。源文件:03\test3-20.html。
… <body> <script> function getMax(a, b) { var max = Number.MIN_VALUE var len = arguments.length //获得实际参数个数 if (len == 0) { document.write("<br>没有传递实际参数!") return } document.write("<br>实际参数:") for (var i = 0; i < len; i++) { document.write(arguments[i] +" ") if (arguments[i] > max) max = arguments[i] } document.write("最大值为:" + max) } document.write("函数getMax形参个数为:" + getMax.length) getMax() getMax(10, 5) getMax(10, 5, 20) </script> </body> </html>
在浏览器中的运行结果如图3-20所示。
图3-20 使用arguments数组获取实际参数
2. 数组作为参数
在使用表达式或变量作为实参时,形参接收实参的值,所以在函数中形参的值改变,不会影响到实参。在使用数组作为实参时,形参接收的是数组的内存地址,即形参和实参引用了同一个数组。这种情况下,改变形参数组元素的值,通过实参数组对应元素获得的是改变后的值。
【例3-21】 使用数组作为参数。源文件:03\test3-21.html。
… <body> <script> function test(x,y) { x[0] = "abc" y = 100 document.write("<p>函数内:<br>形参x = " + x) document.write("<br>形参y = " + y) } var a = [1, 2], b = 10 document.write("调用函数前:<br>实参a = " + a) document.write("实参b = " + b) test(a, b) document.write("<p>调用函数后:<br>实参a = " + a) document.write("<br>实参b = " + b) </script> </body> </html>
在浏览器中的运行结果如图3-21所示。
图3-21 使用数组作为实际参数
3. 对象作为参数
对象也可作为函数参数(对象的详细内容将在后面的章节中进行介绍)。与数组类似,形参和实参引用的是同一个对象。如果在函数中修改了形参对象属性值,实参对象也会反应属性值的变化。
【例3-22】 使用对象作为参数。源文件:03\test322.html。
… <body> <script> function test(args) { document.write("<p>函数内:<br>args.name = " + args.name) document.write("<br>args.age = " + args.age) args.name = 'Java' args.age=15 document.write("<br>修改后:<br>args.name = " + args.name) document.write("<br>args.age = " + args.age) } var a = { name: 'JavaScript', age: 25 } document.write("调用函数前:<br>a.name = " + a.name) document.write("<br>a.age = " + a.age) test(a) document.write("<p>调用函数后:<br>a.name = " + a.name) document.write("<br>a.age = " + a.age) </script> </body> </html>
在浏览器中的运行结果如图3-22所示。
图3-22 使用对象作为实际参数
3.2.4 函数的嵌套
JavaScript允许在函数内部嵌套函数的定义。嵌套定义的函数只能在当前函数内部使用。
【例3-23】 使用嵌套定义函数,实现两个数组的加法运算(对应元素相加)。源文件:03\test3-23.html。
… <body> <script> function addArray(a, b) { function getMax(x, y) { return x > y ? 0 : 1 } //返回长度较大的数组的序号 var alen = a.length var blen = b.length var index = getMax(alen, blen) var temp = new Array() //创建一个空数组 for (var i = 0, len = arguments[index].length; i < len; i++) //将较长的数组复制到临时数组中 temp[i] = arguments[index][i] for (var i = 0, len = arguments[1-index].length; i < len; i++) //将较短的数组与临时数组做加法 temp[i] += arguments[1 - index][i] //做加法 return temp } var a = [1, 3, 5] var b = [2, 4, 6, 8, 10] var c = addArray(a, b) document.write('数组a = '+ a) document.write('<br>数组b = '+ b) document.write('<br>数组a + b = '+ c) </script> </body> </html>
在浏览器中的运行结果如图3-23所示。
图3-23 嵌套定义函数
3.2.5 递归函数
递归函数是指在函数的内部调用函数自身,形成递归调用。使用递归函数必须注意递归调用的结束条件。若递归调用无法停止,则会导致运行脚本的浏览器崩溃。
【例3-24】 使用递归函数计算阶乘。源文件:03\test3-24.html。
… <body> <script> function fact(n) { if (n <= 1) return 1 //递归调用结束 return n * fact(n - 1) } for (var i = 0; i <= 10; i++){ document.write('<br>'+i + '! = '+ fact(i)) } </script> </body> </html>
在浏览器中的运行结果如图3-24所示。
图3-24 使用递归函数计算正整数阶乘