1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# 闭包(Closure) function count() { var arr = []; for(var i = 1; i < 4; i++) { arr.push(function(){ return i * i; }); } return arr; } // 输出全部都是16 因为返回的函数引用了变量i,但它并没有立即执行,最后i变成了4 var f = count(); alert(f[0]()); //16 alert(f[1]()); //16 alert(f[2]()); //16 // 可以使用let关键字 此时会输出 1 4 9 // 或者再创建一个函数,用该函数的参数绑定循环变量当前的值 // 无论循环变量后续如何更改,已绑定到函数参数的值不变 function count() { var arr = []; for (var i = 1; i < 4; i++) { arr.push((function(n) { return function () { return n * n; } })(i)); } return arr; } // 上面其实用了创建一个匿名函数并立即执行的语法 (function(n){ // 因为当前的i已经被执行了,所以无论i怎么变都无所谓了 // 但是这里还是返回了个匿名函数, })(i); // js中没有class 所有没有办法使用private修饰一个成员变量,可以用闭包模拟 // 这里的x就类似于返回的对象的私有属性,因为在返回的对象中无法直接操作x function create_counter(initial) { var x = initial || 0; return { inc:function() { x += 1; return 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 // 我们经常会用的平方和立方,可以借助闭包"继承"Math.pow function make_pow(n) { return function (x) { return Math.pow(x, n); } } var pow2 = make_pow(2); var pow3 = make_pow(3); pow2(2); //4 pow3(2); //8 // 匿名函数递归 'use strict'; // 传入匿名函数A,返回匿名函数B,如果执行匿名函数B,会执行匿名函数A,并返回执行结果 var one = function (f) { return function (x) { return f(x); } }; // 传入类one的匿名函数两个,返回匿名函数B,如果执行匿名函数B,会返回一个匿名函数C function add(n, m) { return function (f) { return function (x) { // 其实这步,可以分拆成如下(以one为例) // var y = n(f)(x); => (n(f))(x); => (one(func()))(x); // return m(f)(y); => (m(f))(y); => (one(func()))(y); return m(f)(n(f)(x)); } } } /* 我们把它拆开来看,下面这步,其实是返回了一个匿名函数, 它的参数是我们传入的print 1 times的匿名函数 (one(function () { alert('print 1 times'); })) 然后它后面还跟了个() 所以执行了这个匿名函数,然后就执行了传入的匿名函数输出了print 1 times */ (one(function () { alert('print 1 times'); }))(); // 执行add函数,返回一个结构和one类似的匿名函数,但最内层的执行不同 var two = add(one, one); /* 还是把它拆开来看,下面这步,其实同样返回了一个匿名函数 它的参数是我们传入的print 2 times的匿名函数 (two(function () { alert('print 2 times'); })) 然后它后面跟了(),执行了这个匿名函数 接着会执行m(f),m就是add的时候传入的one,而它的参数f,就是我们传入的print 2 times的匿名函数 相当于下面这个式子 (one(function () { alert('print 2 times'); })) 跟上面一样,它返回一个匿名函数,匿名函数的参数是print 2 times 然后这次后面跟的不是()了,而是有参数的 (n(f)(x)) 但是不管有没有参数,都不会影响匿名函数f,就是我们传入的print 2 times的匿名函数的执行 虽说是不影响print 2 times的匿名函数的执行,但在执行之前,我们应该先执行参数中的n(f)(x) 先执行它的参数前半段n(f),跟m(f)一样,n是add传入的one,f是print 2 times 然后后面跟着(x),就执行了print 2 times,x是undefined (two(..))(这里没有传入x的值) 所以,最终输出了2次print 2 times */ (two(function () { alert('print 2 times'); }))(); var three = add(one, two); // three的话,其实就是执行了一次(one())() 和一次 (two())() 依此类推 (three(function () { alert('print 3 times'); }))(); |