JavaScript:函数
定义函数:
function f(x) {
//函数体
}
如果没有return
语句,函数返回undefined
。
JavaScript的函数也是一个对象,实际上是一个函数对象,而函数名f
可以视为指向该函数的变量。
因此,第二种定义函数的方式如下:
var f= function (x) {
//函数体
};
上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;
,表示赋值语句结束。
由于JavaScript允许传入任意个参数,因此传入的参数比定义的参数多没有问题,虽然函数内部并不需要这些参数:
abs(10, 'blablabla'); // 返回10
abs(-9, 'haha', 'hehe', null); // 返回9
传入的参数比定义的少也没有问题:
abs(); // 返回NaN
此时abs(x)
函数的参数将收到undefined
,计算结果为NaN
。
要避免收到undefined
,可以对参数进行检查:
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
JavaScript还有一个关键字arguments
,它只在函数内部起作用,并且永远指向当前函数的所有参数。arguments
类似Array但它不是一个Array:
function foo(x) {
alert(x); // 10
for (var i=0; i<arguments.length; i++) {
alert(arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);
利用arguments
,可获得传入的所有参数。即使函数不定义任何参数,还是可以拿到参数的值:
ES6标准引入了...rest
参数:
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
由于JavaScript会自动判断补充行末的分号,如果把return
语句拆成两行:
function foo() {
return
{ name: 'foo' };
}
foo(); // undefined
正确的多行写法是:
function foo() {
return { // 这里不会自动加分号,因为{表示语句尚未结束
name: 'foo'
};
}
变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有声明的变量“提升”到函数顶部:
'use strict';
function foo() {
var x = 'Hello, ' + y;
alert(x);
var y = 'Bob';
}
foo();
虽然是strict
模式,但语句var x = 'Hello, ' + y;
并不报错,原因是变量y
在稍后声明了。但是alert
显示Hello, undefined,说明变量y
的值为undefined
。因为JavaScript引擎自动提升了变量y
的声明,但不会提升变量y
的赋值。
由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先声明所有变量”这一规则。最常见的做法是用一个var
申明函数内部用到的所有变量:
function foo() {
var
x = 1, // x初始化为1
i; // i为undefined
// 其他语句:
for (i=0; i<100; i++) {
...
}
}