理论是自信的基础,结合理论的实践才能让咱们走的更远。javascript
前两个系列,我记录了闭包的学习,如何利用闭包解决实际问题了?其实,不少东西你我都知道,不是一蹴而就的,不是你今天学了就会了,还须要屡次练习,反复练习。相信终究一天你我会运用自如。java
下面就经过3个小例子,来运用闭包解决实际问题吧。面试
在面试题中经常会遇到一个与循环、闭包有关的问题,以下:设计模式
//利用闭包的知识修改这段代码,让代码的执行结果为隔秒输出1,2,3,4,5
for (var i = 1; i<=5; i++) {
setTimeout(timer=()=>{
console.log(i)
},i*1000)
}复制代码
首先来分析一下若是直接运行这个例子会输出什么结果。(涉及到定时器线程的相关知识还须要自行学习)bash
前面咱们已经知道,for循环的大括号并不会造成本身的做用域,所以这个时候确定是没有闭包产生的,而i值做为全局的一个变量,会随着循环的过程递增。所以循环结束以后,i变成了6。微信
而每个循环中,setTimerout的第二个参数访问的都是当前的i值,所以第二个i值分别是1,2,3,4,5。而第一个参数timer函数中虽然访问的是同一个i值,可是因为延迟的缘由,当timer函数被setTimerout运行时,循环已经结束,即i已经变为6了。闭包
所以这段代码执行结果是隔秒输出6.框架
而咱们想要的是隔秒输出1,2,3,4,5,所以须要借助闭包的特性,将每个i值都用一个闭包保护起来。每一轮循环,都把当前的i值保存在一个闭包中,当setTimerout中定义的操做执行时,访问对应闭包便可。模块化
这个时候咱们回想一下闭包造成的条件,简单来讲,就是一个函数中定义了一个子函数,子函数内部访问了函数的变量对象。所以咱们只须要建立一个这样的环境便可。函数
for (var i = 1; i<=5; i++) {
(function(i) {
setTimeout(timer=()=>{ console.log(i)
},i*1000) })(i)
}复制代码
定义一个匿名函数,称做A,并将其看成闭包环境。而timer函数则做为A的内部函数,当A执行时,只需访问A的变量对象便可。所以将i值做为参数传入,这样也就知足了闭包的条件,并将i值保存在了A中。
一样的道理也能够在timer函数里作文章。还有更多方法,这里就不一一赘述。
好,我继续个人笔记。
在javascript中有许多解决特定问题的编码思惟(设计模式,Alloy Team出的那本我的以为很棒),例如工厂模式、发布订阅模式、装饰者模式、单例模式等。其中,单例模式是早期开发最经常使用的模式之一,而它的实现,与闭包戚戚相关。
所谓单例模式,就是只有一个实例。
1. 最简单的单例模式
对象字面量的方法就是最简单的单例模式,咱们能够将属性与方法依次放在字面量里。
var person = {
name: 'pan',
age: '18',
getName: function() {
return this.name
},
getAge: function() {
return this.age
}
}复制代码
可是这样的单例模式有一个严重的问题,即它的属性能够被外不修改。所以在许多场景中,这样的写法并不符合咱们的需求,咱们更指望对象可以有本身的私有方法与属性。
PS:我的以为不论学习什么,都应该回顾它的历史,以便更利于当下的学习。理论性知识发展到目前,不是偶然,总有那么一个阶段性的过渡。司徒正美在他的做品《javascript框架设计》前言中就说到了这么一个事“当初,我阅读jQuery源码,最初看的是1.4.3版本,看得一头雾水,一气之下,从最初的1.0版本开始看。看完全部版本,了解其迭代过程,才明白”。
2. 有私有方法/属性的单例模式
经过前面所学的知识咱们很容易就能想到,想要一个对象拥有本身私有的方法属性,那么只须要建立一个单独的做用域将对象与外界隔离起来就好了。这里咱们借助匿名函数自执行的方式便可。
var person = (function() {
var name = 'pan';
var age = 18;
return{
function getName() { return name
};
function getAge() {
return age
} }
})();
person.getName();复制代码
私有变量的好处在于,外界对于私有变量可以进行什么样的操做是能够控制的。咱们能够提供一个getName方法让外界能够访问名字,也能够额外提供一个setName方法,来修改它的名字。对外提供什么样的能力,彻底由咱们本身决定。
如今咱们正走在模块化的道路上....
3. 调用时才初始化的单例模式
有的时候(使用频次较少)咱们但愿本身的实例仅仅只是在调用的时候才被初始化,而不像上面两个例子那样,即便没有调用person,person的实例在函数自执行的时候就返回了。
那么咱们就须要在上面例子的基础上作一点小小的改动了。
var person = (function(){
//定义一个变量,用来保存实例
var instance = null;
var name = 'pan';
var age = 18;
//初始化方法
function init() {
return{
getName: function() { return name;},
getAge: function() { return age;}
}
}
return {
getInstance: function() {
if(!instance){
instance = init()
}
return instance
}
}
})();
//只在使用时获取实例
var p1 = person.getInstance();复制代码
在这个例子中,咱们对匿名函数中定义了一个instance变量用来保存实例。在getInstance方法中判断了是否对他进行从新赋值。因为这个判断的存在,所以变量instance仅仅只在第一次调用getInstance方法时赋值了。
在写一个系列,我将持续更新我闭包相关应用。感谢阳波大神。
这些都是我以往的学习笔记。若是您看到此笔记,但愿您能指出个人错误。有这么一个群,里面的小伙伴互相监督,坚持天天输出本身的学习心得,不输出就出局。但愿您能加入,咱们一块儿终身学习。欢迎添加个人我的微信号:Pan1005919589