Factory模式和它的名字一样,是一个可以像工厂那样用来批量生产对象的函数。其实在JS中类似用途的方法有许多,比如ES5中就已经有的constructor,还有ES6中还添加了class。那为什么还要大费周章地发明factory呢?
让我们先来看看ES6的class方法:
class Dog {
constructor() {
this.sound = 'woof'
}
talk() {
console.log(this.sound)
}
}
const sniffles = new Dog()
sniffles.talke() // woof
看起来好像一切很美好,但是事情总不会那么顺利。我们都知道,JS中的this指的并不是对象本身,而是该方法的实际调用者。于是在某些情况下,sniffles.talke中的this.sound会因为this的问题而出错:
$('button.myButton).click(sniffles.talk)
这里的this其实是myButton,所以无法正确取得this.sound成员。当然了,我们可以用bind、apply来绑定this,但非常不自然。使用factory模式就可以很好地解决这个问题,而且代码页更清晰简洁:
const dog = () => {
const sound = 'woof'
return {
talk: () => console.log(sound)
}
}
const sniffles = dog()
sniffles.talk() //woof
这样一来,我们的代码$('button.myButton).click(sniffles.talk)
就不会有问题了,因为在factory中根本没有使用this。此外,sound处于closure中,等同于一个私有对象,只有dog内部成员能访问它。于是我们又借此实现了encapsulation。
Factory模式使用更少、更简洁的代码实现了同样的功能,那它是否是class或constructor的完美替代者呢?实际上class由于内建语法支持,更容易得到编译器的优化,使其创建效率比factory要高。在本地电脑商测试,factory创建对象耗时约为0.0004ms,而class耗时约为0.0002ms,class要快50%!
我个人认为,如果你需要在单一场景中创建大量的对象(上千个对象),或是追求执行效率的场景(游戏、图像处理等),还是采用class吧。但对大多数应用来说,factory更简洁优雅,同时也避免了许多不易察觉的问题,就放心使用吧!