JavaScript 函数


函数是用于完成一个特定任务的一组有关联的语句。


函数也是对象,函数有属性和方法,例如apply方法。函数也可以做为其他函数的参数或返回值。

有三种方式定义函数:

  • 使用函数声明定义函数,function 函数名(参数列表) {函数体}
  • 使用函数表达式定义函数,var f = function 函数名(参数列表) {函数体}。函数可以是匿名的,即可以不写函数名。可以将函数表达式保存到一个变量,变量可以当作函数使用。
  • 使用Function构造器根据一个字符串创建一个函数,var f = new Function(参数列表, 函数体)

下面是函数定义的例子:

<!DOCTYPE html><html><body><pre>
<script type="text/javascript">
  function add(a, b) {
    return a + b;
  }
  document.writeln("add(1, 2) = " + add(1, 2)); // 3

  var f = function(a, b) { return a + b;}
  document.writeln("f(2, 3) = " + f(2, 3)); // 5

  var f2 = new Function("a", "b", "return a + b;");
  document.writeln("f2(3, 4) = " + f2(3, 4)); // 7
</script>
</pre></body></html>

调用函数

Javascript中有三种方式调用函数:

  • 函数名或函数变量后面跟括号,括号中是参数列表,参数之间使用逗号分隔。例如add(1, 2);
  • 通过函数的call方法调用函数,例如add.call(null, 1, 2)
  • 通过函数的apply方法调用函数,例如add.apply(null, [1, 2])

call方法和apply方法的区别是call方法的参数是列表,apply方法的参数是数组,两个方法的第一个参数都是this值。

下面是调用函数的例子:

<!DOCTYPE html><html><body><pre>
<script type="text/javascript">
  function add(a, b) {
    return a + b;
  }
  document.writeln("add(1, 2) = " + add(1, 2)); // 3
  document.writeln("add.call(null, 2, 3) = " + add.call(null, 2, 3));     // 5
  document.writeln("add.apply(null, 3, 4) = " + add.apply(null, [3, 4])); // 7

  document.writeln("Math.max.apply(null, [4, 5, 6]) = " + Math.max.apply(null, [4, 5, 6])); // 6
</script>
</pre></body></html>

使用call方法和apply方法调用函数主要是为了更改被调用函数的this值。

函数参数和返回值

如果调用函数时传入的参数个数多于函数定义中的参数个数,多出来的参数会被忽略。

如果调用函数时传入的参数个数少于函数定义中的参数个数,缺少的参数会设置为undefined。

函数中有一个内部对象arguments用来保存所有函数调用时传入的参数。

如果函数没有使用return语句,或return语句没有值,函数返回undefined。

下面是函数参数和返回值的例子:

<!DOCTYPE html><html><body><pre>
<script type="text/javascript">
  function add(a, b) {
    return a + b;
  }
  document.writeln("add(1, 2, 3) = " + add(1, 2, 3)); // 3
  document.writeln("add(2) = " + add(2)); // NaN

  function add2() {
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
  }
  document.writeln("add2(1, 2, 3) = " + add2(1, 2, 3)); // 6
</script>
</pre></body></html>

匿名函数

匿名函数指定义函数时不指定函数名的函数。

匿名函数主要应用场景:

  • 匿名函数作为其它函数的参数。
  • 匿名函数用作闭包。

下面是匿名函数的例子:

<!DOCTYPE html><html><body><pre>
<script type="text/javascript">
  function map(f, arr) {
    var result = [];
    for (var i = 0; i < arr.length; i++) {
      result[i] = f(arr[i]);
    }

    return result;
  }

  var f = function(x) {
    return x * x;
  }

  document.writeln("map(f, [1, 2, 3, 4]) = " + map(f, [1, 2, 3, 4])); // 1,4,9,16
</script>
</pre></body></html>

嵌套函数

嵌套函数(Nested function)是定义在其它函数中的函数。嵌套函数可以访问外部函数的变量。

如果函数nested_func只被函数out_func调用,可以将nested_func嵌套在out_func中,这样可以减少全局函数和全局变量的数量,易于代码的维护。

下面是嵌套函数的例子:

<!DOCTYPE html><html><body><pre>
<script type="text/javascript">
  function out_func() {
    out_arr = [1, 2];
    function nested_func() {
      out_arr.push(3);
    }

    nested_func();
    return out_arr;
  }
  document.writeln("out_func() = " + out_func()); // 1,2,3
</script>
</pre></body></html>

闭包

闭包(Closure)是嵌套函数。闭包被外部函数作为一个函数对象返回给调用方。即使外部函数执行完成,闭包仍然可以访问外部函数中的变量。函数是第一类对象(first-class object),函数可以做为函数的参数和返回值。

下面是闭包的例子:

<!DOCTYPE html><html><body><pre>
<script type="text/javascript">
  function out_func(out_arr) {
    function nested_func(nested_data) {
        out_arr.push(nested_data);
    }
    return nested_func;
  }
  var a = [1, 2];
  var closure = out_func(a);
  closure(3);
  document.writeln("a = " + a); // 1,2,3
</script>
</pre></body></html>