js之深入理解闭包问题。
最近一段时间准备好好学习下机器学习,所以了解了很多机器学习方面的知识。抓紧补救了下自己曾经遗忘的理论知识(高数、统计学、概率论、微积分等),发现还有点吃力了,很多东西都快忘得差不多。不过,咱程序员,还是很擅长围魏救赵滴^_^。所以,我果断的选择边理论边着手老本行——编程。
选择语言问题,就是第一大难题。
目前流行的机器学习语言大抵是R语言和python了,熟悉了下R,发现简直就不该是程序员该用的,这简直就是为非专业编程人士准备的东西。大概了解了下,就放弃了。那现在选择就一个了,python。
初学python,感觉如鱼得水啊。这对把函数式编程当成工作的我来说,学起来简直游刃有余啊,瞬间被微积分概率论虐得生活不能理解的感觉一去不复返~额,貌似扯远了。前奏有点太长了,下面进入正题。
闭包?
当我进入python的闭包时,看见了这么一道题。
# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
这不就是曾经那个闭包吗?现在还记得第一次面试时,面试官问到我闭包时,我一番鬼扯然后用错误答案回答的尴尬。既然这样,我觉得有必要好好和大家分享下我心中的闭包。
闭包是什么呢?内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
闭包的特点是返回的函数还引用了外层函数的局部变量。定义听起来简单易懂,能正确应用才是关键。上个题的答案是
def count():
fs = []
for i in range(1, 4):
def f(i) :
def g() :
return i * i
return g
fs.append(f(i))
return fs
f1, f2, f3 = count()
print f1(), f2(), f3()
为什么会这样?下面我们用js的方式来处理下另外一个题目,相信能处理这个新题目,你正确处理这个题目也是很简单的事。
时间再一次回到第一次面试。面试官出了这么一道经典题目:请使用闭包输出1-100每隔一秒输出一次。额,这个问题怎么这么熟悉呢?貌似在哪里见过,一百道经典面试题还是你必须知道的十道js面试问题来着~,想了半天,就知道要用闭包,要用setTimeout。好吧,有这些就够了,既然一时想不出来,那就直接写吧!
function closure() {
for (var i = 0; i < 100; i ++) {
setTimeout(function() {
(function() {
console.log(i);
}) (i)
}, 1000)
}
}
貌似有什么不对。这个大概会输出一百个100的节奏啊~,可是哪里不对呢?找了半天,没发现,那推倒重来!既然是闭包,那不是要return函数么,那再来过。
function closure() {
for (var i = 0; i < 100; i ++) {
setTimeout(function() {
var foo = function(i) {
return function() {
console.log(i);
}
}
foo(i)
}, 1000)
}
}
这个么,好像没有输出值啊~,左思右想,重来。
for (var i = 0; i < 5; i++) {
var a = function(v){
return function(){
console.log(v)
}
}
setTimeout(a(i),1000)
}
这个像,嗯,不错,就是他了。然后愉快的将最终结果给面试官过目,面试官问了句,你确定这是我想要的结果?是的,我很确定!现在依旧记得当初的意气风发啊,年轻真好!
回来之后,把自己把程序在浏览器上跑了下,瞬间懵逼了。这不是我想要的结果啊,我想要的结果是100s!最后自己默默的在1000后面乘了个i,最终程序是这样的:
for (var i = 0; i < 5; i++) {
var a = function(v){
return function(){
console.log(v)
}
}
setTimeout(a(i),i * 1000)
}
但是,为什么是这样呢?首先setTimeout是一个定时器,一个异步的定时器。什么意思呢?就是必须主程序跑完了,才开始执行它!意思就是你的for循环跑完了,才会执行setTimeout。所以如果直接输出,很明显,i的值为100.所以你会得到100个100.怎样才能保留i,让i按照我们想要的循环一下输出一下呢?那就使用闭包吧,把i传进去。这样i的值就被保留下来了,一直被内部的函数引用。所以就能输出我们想要的结果。最后为什么要乘以i呢,因为是一秒执行一次,不是过了一秒全部执行!所以~
以上就是内容的全部,如果还有不懂,请留言。我会关注的,谢谢。
共同学习,写下你的评论
评论加载中...
作者其他优质文章