复制代码 代码如下: var name = "linjisong"; var person = {name:"oulinhai"}; function getName(){ return this.name; } function sum(){ var total = 0, l = arguments.length; for(; l; l--) { total += arguments[l-1]; } return total; }
希望好好理解一下上面这段话,反复理解一下。虽然我已经尽我所能描述的更易于理解一些,但是闭包的概念还是有些抽象,下面看一个例子,这个例子来自原书第7章: 复制代码 代码如下: function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(){ return i; }; } return result; }
var funcs = createFunctions(); for (var i=0,l=funcs.length; i < l; i++){ console.info(funcs[i]());//每一个函数都输出10 }
这里由于闭包带有的数据是createFunctions相应的活动对象的最终状态,而在createFunctions()代码执行完成之后,活动对象的属性i已经变成10,因此在下面的调用中每一个返回的函数都输出10了,要处理这种问题,可以采用匿名函数作用域来保存状态: 复制代码 代码如下: function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = (function(num){ return function(){ return num; }; })(i); } return result; }
这里添加的bind()方法中,主要技术也是创建一个闭包,保存绑定时的参数作为函数实际调用时的内部属性this。如果你不确定是浏览器本身就支持bind()还是我们这里的bind()起了作用,你可以把特性检测的条件判断去掉,然后换个方法名称试试。 C、上面对函数使用bind()方法时,只使用了第一个参数,如果调用bind()时传入多个参数并且将第2个参数开始作为函数实际调用时的参数,那我们就可以给函数绑定默认参数了。 复制代码 代码如下: if(!Function.prototype.bind){ Function.prototype.bind = function(scope){ var that = this;//调用bind()方法的函数对象 var args = Array.prototype.slice.call(arguments,1);//从第2个参数开始组成的参数数组 return function(){ var innerArgs = Array.prototype.slice.apply(arguments); that.apply(scope, args.concat(innerArgs));//使用apply方法,指定that函数对象的内部属性this,并且填充绑定时传入的参数 }; }; }
D、柯里化:在上面绑定时,第一个参数都是用来设置函数调用时的内部属性this,如果把所有绑定时的参数都作为预填的参数,则称之为函数柯里化。 复制代码 代码如下: if(!Function.prototype.curry){ Function.prototype.curry = function(){ var that = this;//调用curry()方法的函数对象 var args = Array.prototype.slice.call(arguments);//预填参数数组 return function(){ var innerArgs = Array.prototype.slice.apply(arguments);//实际调用时参数数组 that.apply(this, args.concat(innerArgs));//使用apply方法,并且加入预填的参数 }; }; }
(2)利用闭包缓存
还记得前面使用递归实现斐波那契数列的函数吗?使用闭包缓存来改写一下: 复制代码 代码如下: var fibonacci = (function(){//使用闭包缓存,递归 var cache = []; function f(n){ if(1 == n || 2 == n){ return 1; }else{ cache[n] = cache[n] || (f(n-1) + f(n-2)); return cache[n]; } } return f; })();
var f2 = function(n){//不使用闭包缓存,直接递归 if(1 == n || 2 == n){ return 1; }else{ return f2(n-1) + f2(n-2); } };
下面是测试代码以及我机器上的运行结果: 复制代码 代码如下: var test = function(n){ var start = new Date().getTime(); console.info(fibonacci(n)); console.info(new Date().getTime() - start);