闭包问题 let实现

来源:互联网 发布:老男孩网络上课方式 编辑:程序博客网 时间:2024/05/26 14:08

之前有了解过很多闭包知识,还算清楚概念。
闭包就是能够读取其他函数内部变量的函数。
通常情况下,js函数的外部是无法读取函数内部的变量,但是函数内部可以读取函数外部的变量。而有时候,我们会需要得到函数内部的局部变量,就需要用到闭包。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
简单的说,Javascript允许使用内部函数—即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

这里有这样一个题目:
题目描述
实现函数 makeClosures,调用之后满足如下条件:
1、返回一个函数数组 result,长度与 arr 相同
2、运行 result 中第 i 个函数,即 resulti,结果与 fn(arr[i]) 相同
输入例子:
var arr = [1, 2, 3];
var square = function (x) {
return x * x;
};
var funcs = makeClosures(arr, square);
funcs1;

输出例子:
4

答案很多,具体如下

//参考《JavaScript高级程序设计》的典型方法function makeClosures(arr, fn) {    var result = new Array();    for(var i=0;i<arr.length;i++){        result[i] = function(num){            return function(){                return fn(num);            }        }(arr[i]);    }    return result;}
//使用ES5的bind()方法function makeClosures(arr, fn) {    var result = new Array();    for(var i=0;i<arr.length;i++){        result[i] = fn.bind(null,arr[i]);    }    return result;}
//使用forEach()function makeClosures(arr, fn) {    var result = new Array();    arr.forEach(function(curr){        result.push(function(){return fn(curr)});    })    return result;}

这三种,我自己想到的是第二种,其他都是找的,然后网上有一种es6的写法如下:

function makeClosures(arr, fn) {       var result = new Array();    for(let i=0;i<arr.length;i++){        result[i] = function(){            return fn(arr[i]); //let声明的变量只在let所在代码块内有效,因此每次循环的i都是一个新的变量                   };    }    return result;}

当时看到这个解释有点懵逼,就去找let与var的区别,然而,还是不理解,因为我知道let是块级作用的,但是还是不懂此处为什么就可以这么用。
后来还是看到阮一峰老师的《ECMAScript 6 入门》这本书上给我解疑了,所以说,人丑就得多读书啊。我建议是买一本,翻翻,我也是新手,准备最近将这本书搞完。

书上这么说的

变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

因为var声明的变量,在for循环之外还是可以访问的,导致了i变量变到最终的值的时候,fn(arr[i])虽然是闭包访问的,但是是同一个i,所以i就是统一值。
而let则相当于每次都是不同的i,我之前的疑惑是为什么每次都是新建的i却能自增,书中的那句话解释了。
JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
所以这种答案也是可以的。
注意:
JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算.这句话只针对for循环有效。正常代码中,如果这么声明会报错。

let i=0;i++;console.log(i);let i=0;i++;console.log(i);

直接报错,i已经存在,无法重新声明。

let i=0;i++;console.log(i); i=0;i++;console.log(i);

这样的话,结果是1,1所以是无效的。
其他循环没测试过, 一时想不起怎么设计。希望有人能研究研究。

0 0
原创粉丝点击