JavaScript 函数
基本上所有的高级语言都支持函数,JavaScript也不例外。JavaScript 的函数不但是“头等公民”,而且可以像变量一样使用,具有非常强大的抽象能力。
借助抽象,我们才能不关心底层的具体计算过程,而直接在更高的层次上思考问题。写计算机程序也是一样,函数就是最基本的一种代码抽象的方式。
函数(function)的定义
在 JavaScript 中,定义函数的方式如下:
1 | function abs(x) { |
上述abs()函数的定义如下:
function指出这是一个函数定义;abs是函数的名称;(x)括号内列出函数的参数,多个参数以,分隔;{ ... }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
请注意,函数体内部的语句在执行时,一旦执行到 return 时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。
如果没有 return 语句,函数执行完毕后也会返回结果,只是结果为 undefined。
由于 JavaScript 的函数也是一个对象,上述定义的 abs() 函数实际上是一个函数对象,而函数名 abs 可以视为指向该函数的变量。
因此,第二种定义函数的方式如下:
1 | let abs = function (x) { |
在这种方式下,function (x) { ... }是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数。
上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。
函数的特点:
- 包含 0 或多个参数
- 存在或无返回值
调用函数
调用函数时,按顺序传入参数即可:
1 | abs(10); // 返回10 |
由于 JavaScript 允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数:
1 | abs(10, 'blablabla'); // 返回 10 |
传入的参数比定义的少也没有问题:
1 | abs(); // 返回 NaN |
此时abs(x)函数的参数 x 将收到undefined,计算结果为NaN。
要避免收到undefined,可以对参数进行检查:
1 | function abs(x) { |
arguments
JavaScript还有一个免费赠送的关键字 arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments 类似Array 但它不是一个 Array。
利用 arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:
1 | function abs() { |
rest 参数
由于 JavaScript 函数允许接收任意个参数,于是我们就不得不用 arguments 来获取所有参数:
1 | function foo(a, b) { |
为了获取除了已定义参数a、b之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的 rest 参数,有没有更好的方法?
ES6 标准引入了 rest 参数,上面的函数可以改写为:
1 | function foo(a, b, ...rest) { |
rest参数只能写在最后,前面用 ... 标识,从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest,所以,不再需要arguments 我们就获取了全部参数。
如果传入的参数连正常定义的参数都没填满,也不要紧,rest 参数会接收一个空数组(注意不是undefined)。
因为 rest 参数是ES6新标准,所以你需要测试一下浏览器是否支持。
小心你的 return 语句
前面我们讲到了 JavaScript 引擎有一个在行末自动添加分号的机制,这可能让你栽到 return 语句的一个大坑:
1 | function foo() { |
如果把return语句拆成两行:
1 | function foo() { |
要小心了,由于 JavaScript 引擎在行末自动添加分号的机制,上面的代码实际上变成了:
1 | function foo() { |
所以正确的多行写法是:
1 | function foo() { |
参考
简介 - JavaScript教程 - 廖雪峰的官方网站