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++) {
        ...
    }
}
posted @ 2019-01-09 17:29  xuejianbest  阅读(161)  评论(0编辑  收藏  举报