计数器
起首,从一个计数器最先。
var counter = 0;
function increment() {
counter = counter + 1;
console.log("Number of events: " + counter);
}
increment(); // Number of events: 1
increment(); // Number of events: 2
increment(); // Number of events: 3
多个计数器
上面的代码简朴粗犷,然则我们很快会碰到下一个题目:假如想要再建立一个计数器怎么办呢。固然我们能够建立两个变量,两个函数,但如许是否是太low了:
var counter1 = 0;
function incrementCounter1() {
counter1 = counter1 + 1;
console.log("Number of events: " + counter1);
}
var counter2 = 0;
function incrementCounter2() {
counter2 = counter2 + 1;
console.log("Number of events: " + counter2);
}
incrementCounter1(); // Number of events: 1
incrementCounter2(); // Number of events: 1
incrementCounter1(); // Number of events: 2
而且当须要更多的计数器时,就更不能够用这类要领了。
引入闭包
上面的那段代码,我们更想做的是封装成一个函数,去除冗余代码。下面我们就开端尝试一下闭包:
function createCounter() {
var counter = 0;
function increment() {
counter = counter + 1;
console.log("Number of events: " + counter);
}
return increment;
}
如今来看一下发生了什么。我们将会建立两个计数器,而且运用它们来跟踪两个自力的事宜:
var counter1 = createCounter();
var counter2 = createCounter();
counter1(); // Number of events: 1
counter1(); // Number of events: 2
counter2(); // Number of events: 1
counter1(); // Number of events: 3
额,看起来有点庞杂。。但实际上很简朴。我们只须要剖析一下完成的逻辑。
起首,建立了一个部分变量counter
然后,建立了一个部分函数increment
,能够增添counter
的值。
实在这个createCounter()
的完成险些跟最最先谁人计数器一样。唯一差别的就是它被函数包裹起来了。因而,这类构造就被称作闭包。
然后就到了最主要的处所:
createCounter()
里的末了一步 返回了 increment
部分函数 ,注重,这里返回的不是函数的挪用效果,而是函数自身。
这也就是说,当我们运用下面的语句建立计数器,我们实际上是天生了一个新的函数。
// fancyNewCounter is a function in this scope
var fancyNewCounter = createCounter();
这就是闭包壮大的处所。每一个经由过程createCounter()
天生的函数都坚持追踪它们本身发生的counter
的值。也就是说,这个返回的函数会记着他被建立时的环境。
能够看到的主要的一点就是内部的counter变量都是相互自力的。建立了两个计数器,它们会各自由闭包中分派一个新的counter变量。我们能够看到:
每一个计数器都从1最先计数:
var counter1 = createCounter();
counter1(); // Number of events: 1
counter1(); // Number of events: 2
var counter2 = createCounter();
counter2(); // Number of events: 1
第二个计数器没有收到第一个计数器的值的影响。
counter1(); // Number of events: 3
定名我们的计数器
“Number of events: x”这类音讯是能够的,然则假如信息能够形貌我们正在计数的事宜的范例,会不会更好。比方,假如我们能够在我们的计数器内里加一个名字:
var catCounter = createCounter("cats");
var dogCounter = createCounter("dogs");
catCounter(); // Number of cats: 1
catCounter(); // Number of cats: 2
dogCounter(); // Number of dogs: 1
我们能够往闭包里传一个参数
function createCounter(counterName) {
var counter = 0;
function increment() {
counter = counter + 1;
console.log("Number of " + counterName + ": " + counter);
}
return increment;
}
能够看出来,createCounter在完成过程当中不仅能记着部分变量counter,也记着了传进来的变量。
优化大众接口
上面的写法有个题目就是,当我们在实行计数器的时刻,很难直观的看出来这个计数器是个将要盘算增量的函数,下面的写法会更简约:
var dogCounter = createCounter("dogs");
dogCounter.increment(); // Number of dogs: 1
function createCounter(counterName) {
var counter = 0;
function increment() {
counter = counter + 1;
console.log("Number of " + counterName + ": " + counter);
};
return { increment : increment };
}
在上面的代码中,我们返回了一个包括闭包中所有函数的对象。从某种意义上来讲,我们正在定义我们的闭包能够相应的一系列音讯
增加递减
如今我们能够异常简朴的将递减的函数加入到计数器中。
function createCounter(counterName) {
var counter = 0;
function increment() {
counter = counter + 1;
console.log("Number of " + counterName + ": " + counter);
};
function decrement() {
counter = counter - 1;
console.log("Number of " + counterName + ": " + counter);
};
return {
increment : increment,
decrement : decrement
};
}
var dogsCounter = createCounter("dogs");
dogsCounter.increment(); // Number of dogs: 1
dogsCounter.increment(); // Number of dogs: 2
dogsCounter.decrement(); // Number of dogs: 1
隐蔽计数行动
上面的代码的console.log反复了两次。应当明白的建立一个函数来显现计数器的值。
function createCounter(counterName) {
var counter = 0;
function display() {
console.log("Number of " + counterName + ": " + counter);
}
function increment() {
counter = counter + 1;
display();
};
function decrement() {
counter = counter - 1;
display();
};
return {
increment : increment,
decrement : decrement
};
}
var dogsCounter = createCounter("dogs");
dogsCounter.increment(); // Number of dogs: 1
dogsCounter.increment(); // Number of dogs: 2
dogsCounter.decrement(); // Number of dogs: 1
display
函数看起来和increment()
和decrement()
很像的模样,但实际上是异常差别的。我们没有在对象的效果中返回这个函数,也就是说下面的语句会报错:
var dogsCounter = createCounter("dogs");
dogsCounter.display(); // ERROR !!!
我们让display()
函数从表面的天下隐蔽了,它只供createCounter()
内部接见
抽象数据范例
让我们运用闭包来完成栈操纵
function createStack() {
var elements = [];
return {
push: function(el) { elements.unshift(el); },
pop: function() { return elements.shift(); }
};
}
var stack = createStack();
stack.push(3);
stack.push(4);
stack.pop(); // 4
注重:在Javascript中,闭包能够并非完成栈数据范例的最好完成体式格局,Prototypes能够会更好一些
闭包和OOP
假如你做过面向对象编程,你能够会注重到,上面的构造特别像类啊对象啊实例变量和公有/私有要领。
按:好久没翻译了,这篇文章翻译的有些智障,然则不延误看代码,看完照样很有收成的!