02函数-03-闭包

1、闭包的概念

闭包是一种特殊的程序结构,即 函数A中定义了另一个函数a,内部函数a引用了外部函数A的参数和局部变量,最终A会返回一个保存了相关参数和变量的函数a

简洁地说,外层函数将保存了信息的可执行内层函数作为结果返回

来看个例子:
//求和功能  
function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    }
    return sum;
}
//当调用该函数时不会直接返回结果,而是返回函数 --e.g.--> // var f = lazy_sum([1, 2, 3, 4, 5]); --> 得到 function sum()
//调用函数时,才得到真正的结果 --e.g.--> // f(); --> 得到 15
//另,即使传入相同参数的两个函数A,返回的函数a也是不同的

2、闭包的小坑

闭包的返回函数,是没有立刻执行的,直到调用该函数才会执行,这意味着,如果是引用了循环变量,会变成如下情况:
function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push(function () {
            return i * i;
        });
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

//然而f1(),f2(),f2()的结果并不是1,4,9,而全部是16

原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了4,因此最终结果为16。

如果一定要引用循环变量,需要再创建一个函数,用该函数的参数绑定当前循环变量的值:
function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push((function (n) {
            return function () {
                return n * n;
            }
        })(i));
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

f1(); // 1
f2(); // 4
f3(); // 9
这里用到了一个语法 “创建一个匿名函数并立即执行”:
(function (x) {
    return x * x;
})(3); // 9
//由于JavaScript语法解析的问题,会报SyntaxError错误,因此需要用括号把整个函数定义括起来

3、闭包的意义

上面我们讲到,闭包相当于把传参后的函数进行了保存但是并不会立刻执行,你要调用返回的这个函数才会执行,所以说闭包的意义只是在于延迟执行函数吗?当然不完全是这样,还有其他很多功能。

在例如Java中,我们要封装一个私有变量,只需要加上private关键字就可以了,可是在JS中,我们也想要封装一个私有变量,怎么办?利用闭包。
//e.g.创建一个计数器
function create_counter(initial) {
    var x = initial || 0;
    return {
        inc: function () {
            x += 1;
            return x;
        }
    }
}

闭包中携带了局部变量x,但是当你使用该函数时,你实际上是无法访问到变量x的,即实际上这个函数的状态完全被隐藏了:
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13

闭包还可以创建新函数,例如把多参数的函数变成单参数的函数。例如,要计算x的y次方可以用Math.pow(x, y)函数,不过考虑到经常计算x平方或x立方,我们可以利用闭包创建新的函数pow2和pow3:
function make_pow(n) {
    return function (x) {
        return Math.pow(x, n);
    }
}

// 创建两个新函数:
var pow2 = make_pow(2);
var pow3 = make_pow(3);

pow2(5); // 25
pow3(7); // 343


posted @ 2017-03-26 13:54  Dulk  阅读(276)  评论(0编辑  收藏  举报