函数function在Javascript中是一等公民,是一种特殊的对象,函数可以作为参数传给其他高阶函数,支持匿名函数,还支持强大的闭包特征,总之javascript的函数是非常精彩的。

函数定义

函数使用function关键字来定义:

函数参数

概念:

可选形参

实参对象的callee与caller属性

作为值的函数

函数不仅有定义和调用这样的语法特征;还是值,可以将函数赋值给变量,可以存储在对象的属性或数组中,还可以作为参数传递给另外的函数。
function square(x) { return x*x; }
这个定义创建了一个新的函数对象,并将其赋值给变量square;而函数的名字实际上时看不见,square仅仅是变量的名字。函数还可以赋值给其他变量:
var s = square;

函数也可以赋值给对象的属性:

var o = {
    square : function(x) { return x*x; }
};
var y = o.square(16); // 256

自定义函数属性

函数是特殊的对象,因此也可以拥有属性。

function factorial(n) {
    if(n > 0) {
        if ( !(n in factorial) ) {
            factorial[n] = n * factorial(n-1);
        }
        return factorial[n];        
    } else {
        return NaN;
    }
}
factorial[1] = 1;

factorial(5); // 120

作为名字空间

由于在函数中声明的变量在整个函数体内是可见的,但是在函数外部是不可见的。

惯用法:定义一个匿名函数,并直接在单个表达式中调用它

( function() {
    // 模块代码
    // return ...
}() );

闭包

函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前的作用域链。函数体内的变量都可以保存在函数作用域内,这种特征称为“闭包”;

var scope = "global";
function checkScope() {
    var scope = "local";
    return function() { return scope; }
}

checkScope()() // local

可以看到闭包的强大特征:闭包可以捕捉局部变量(和参数),并一直保存下来。

嵌套函数

函数可以嵌套在其他函数里:

function createUuid() {
    var uuid_ = 0;
    return function() { return uuid_++; }
}

var uuid = createUuid();
uuid(); // 0
uuid(); // 1

var uuid2 = ( function(){
    var uuid_ = 0;
    return function() { return uuid_++; };
}() );

uuid2(); // 0
uuid2(); // 1

嵌套函数的有趣之处是它的变量作用域规则:它们可以访问嵌套它们(或多重嵌套)的函数的参数或变量。

this与arguments

函数属性,方法与构造函数

function f( y ) { return this.x * y }
var o = { x : 5 };
f.call( o, 3 ); // 15
f.apply( o, [4] ); // 20

bind()函数

bind可以将部分的实参绑定给对象,然后返回一个新的函数。

var sum = function(x,y) { return x+y; };
var succ = sum.bind(null, 1);
succ(2); // 3

function f(y,z) { return this.x + y + z; };
var g = f.bind( {x:1}, 2 );
g(3); // 6

函数式编程

使用函数处理数组

var ary = [ 1,2,3,4,5 ];
ary.reduce( function(x,y){ return x+y; } ); // 15

高阶函数

高阶函数时操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数。

对函数取非

// not
function not(f) {
    return function() {
        var result = f.apply(this, arguments);
        return !result;
    }
}
var even = function(x) { return x%2 === 0; };

var odd = not(even);
[1,3,5].every( odd ); // true

组合函数f(g(x))

// compose(f,g)(x) -> f(g(x))
function compose(f, g) {
    return function() {
        var result = g.apply( this, arguments );
        return f.call( this, result );
    }
}

var square = function(x) { return x*x; };
var sum = function(x,y) { return x+y; };
var squareofsum = compose( square, sum );
squareofsum( 2,3 ); // 25

按右边绑定数据

// bindRight
function array(a, n) {
    return Array.prototype.slice.call( a, n||0 );
}

function bindRight( f ) {
    var right_args = arguments;
    return function() {
        var a = array( arguments );
        a = a.concat( array(right_args, 1) );
        return f.apply( this, a );
    }
}

function f(x,y,z) { return x * (y - z); }
f.bind( null, 5, 6 )( 3 ); // 15
bindRight(f, 6, 3)(5); // 15