Douglas Crockford 提倡过使用闭包而不是传统的 this
和 prototype
来实现面向对象封装(示例代码参见 http://mikehadlow.blogspot.hk/2010/12/javascript-defining-classes-with.html)。
但是业界大多数代码还是使用 this
和 prototype
来实现面向对象封装。那么有哪些使用闭包进行面向对象封装的优秀 JavaScript 代码?
由这个问题启发:有哪些必须一读的优秀开源 JS 代码
UPDATE:来这个答案下面黒 DC 而不回答问题的我也是醉了,一律 vote down。我不知道你们是什么思路会以为我是因为 DC 提倡过这么写而提出这个问题。我从来都是资深 DC 黒,反对他的大多数观点。我只是恰巧由于我自己的函数式编程背景,认为使用闭包而不是 this
更好而已。
我觉得你误解了 DC 的本意,或者说是你没有完全领会你读到的那个例子,所以才误解了 DC 的本意。最近一年,DC 在各 JS 会议中发表了关于他的 JavaScript: Good Parts 的续篇演讲:JavaScript: Better Parts,最早好像是在 YUI Conf 上吧,也是最完整最详细的一次,视频可以上 Youtube 找,很多版本都有。
在这次演讲里,他提到了自己:
但是他从头到尾都没有说过:
这就是我说你误解了 DC 的部分。而他本人也解释了不再用
this
的原因,其一是希望代码更安全(因为this
的动态绑定特性),其二则是追求代码更“函数式”化。另外他也谈到了很多关于 ES6 的部分,特别是他认为让 JavaScript Better 的部分,比如更多的函数式编程特性如尾调用等;还谈到一些让大家有些“担心”,觉得 JavaScript 不怎么好了的部分,比如
Class
的引入等。我个人很赞同他的观点,Class
的引入是标准委员会希望在语言层面能对那些从传统 OO 语言过渡到 JavaScript 的程序员更加友好,但是Class
的引入并没有改变 JavaScript 基于原型链的面向对象的本质,Class
只是一层语法糖,它实现的还是传统的构造器+原型的对象模型,只是在语法层面上更简单友好,且让一些经典的 OO 元素变得更便于实现和使用,比如私有成员,继承等等。因此不必对此“耿耿于怀”,尽管它算不上让 JavaScript 变得更好,却也不会让 JavaScript 变得更坏——只要你知道如何去用就好,当然你可以选择不用。回到你提供的范例代码,比如像这样来创建一个对象:
这的确是 DC 所说的不用
this
的构造器写法,但是坦白地说,就算用了this
,和animal
以及dog
这两个人工创造的对象又有多少不同?是的,我们不需要时刻谨记加上
new
了。是的,我们也能这样来封装隐藏私有成员了:
但是这就够了吗?如果我们要创建很多很多的
doggy
怎么办?每次都要重新定义一个bark
方法?这显然是不合理的。这个例子并没有延伸到原型扩展的范畴,它纯粹是为了展示不用this
创建对象的方法,但是却被误读为:“完全使用闭包封装,不使用this
和prototype
“了。另外,就算不使用
this
,DC 也没有把它列入到“推荐的最佳实践”这一范畴里去,这样做的确有好处,但是对于能够理解和正确使用this
的程序员来说,并非“只能这样做”的限制,而是“有时候这样做会更好”的选择。DC 在演讲中并没有单独那它作为一条“最佳实践”来讲,只是在“不使用 Object.create()“这一条里解释原因的时候提到了关于不再使用this
的。不问出处会害人呐!至于你问有没有项目里这样使用,稍微上点规模的项目从头到尾这样用的我是没见过(没必要),不过用到上面举例的方法的代码倒是有见过几次。究其原因可能就是我上面说的那些,欢迎补充或讨论。