登录

javascript - 有哪些值得一读的不使用 this 和原型,而使用闭包进行面向对象封装的 JS 项目

Douglas Crockford 提倡过使用闭包而不是传统的 thisprototype 来实现面向对象封装(示例代码参见 http://mikehadlow.blogspot.hk/2010/12/javascript-defining-classes-with.html)。

但是业界大多数代码还是使用 thisprototype 来实现面向对象封装。那么有哪些使用闭包进行面向对象封装的优秀 JavaScript 代码?

由这个问题启发:有哪些必须一读的优秀开源 JS 代码

UPDATE:来这个答案下面黒 DC 而不回答问题的我也是醉了,一律 vote down。我不知道你们是什么思路会以为我是因为 DC 提倡过这么写而提出这个问题。我从来都是资深 DC 黒,反对他的大多数观点。我只是恰巧由于我自己的函数式编程背景,认为使用闭包而不是 this 更好而已。

# JavaScript
巴扎黑巴扎黑2208 天前501 次浏览

全部回复(2) 我要回复

  • 迷茫

    迷茫2017-04-10 14:47:55

    我觉得你误解了 DC 的本意,或者说是你没有完全领会你读到的那个例子,所以才误解了 DC 的本意。

    可能不是误解,是我考虑不周,见答案之后的讨论。

    最近一年,DC 在各 JS 会议中发表了关于他的 JavaScript: Good Parts 的续篇演讲:JavaScript: Better Parts,最早好像是在 YUI Conf 上吧,也是最完整最详细的一次,视频可以上 Youtube 找,很多版本都有。

    在这次演讲里,他提到了自己:

    not to use this anymore

    但是他从头到尾都没有说过:

    not to use prototype anymore

    这就是我说你误解了 DC 的部分。而他本人也解释了不再用 this 的原因,其一是希望代码更安全(因为 this 的动态绑定特性),其二则是追求代码更“函数式”化。

    另外他也谈到了很多关于 ES6 的部分,特别是他认为让 JavaScript Better 的部分,比如更多的函数式编程特性如尾调用等;还谈到一些让大家有些“担心”,觉得 JavaScript 不怎么好了的部分,比如 Class 的引入等。我个人很赞同他的观点,Class 的引入是标准委员会希望在语言层面能对那些从传统 OO 语言过渡到 JavaScript 的程序员更加友好,但是 Class 的引入并没有改变 JavaScript 基于原型链的面向对象的本质,Class 只是一层语法糖,它实现的还是传统的构造器+原型的对象模型,只是在语法层面上更简单友好,且让一些经典的 OO 元素变得更便于实现和使用,比如私有成员,继承等等。因此不必对此“耿耿于怀”,尽管它算不上让 JavaScript 变得更好,却也不会让 JavaScript 变得更坏——只要你知道如何去用就好,当然你可以选择不用。

    回到你提供的范例代码,比如像这样来创建一个对象:

    var new_animal = function(name) {
        var animal = {};
    
        animal.sayHello = function() {
            return "Hello, my name is " + name;
        };
    
        return animal;
    };
    
    var new_dog = function(name) {
        var dog = new_animal(name);
    
        dog.bark = function() {
            return "woof";
        };
    
        return dog;
    };
    

    这的确是 DC 所说的不用 this 的构造器写法,但是坦白地说,就算用了 this,和 animal 以及 dog 这两个人工创造的对象又有多少不同?

    是的,我们不需要时刻谨记加上 new 了。
    是的,我们也能这样来封装隐藏私有成员了:

    var animalApp = function() {
        var new_animal = function(name) {
            //...
        };
    
        var new_dog = function(name) {
            //...
        };
    
        return {
            main: function() {
                var dog = newdog('doggy');
                console.log(dog.sayHello());
                console.log(dog.bark());
            }
        };
    };
    

    但是这就够了吗?如果我们要创建很多很多的 doggy 怎么办?每次都要重新定义一个 bark 方法?这显然是不合理的。这个例子并没有延伸到原型扩展的范畴,它纯粹是为了展示不用 this 创建对象的方法,但是却被误读为:“完全使用闭包封装,不使用 thisprototype“了。

    另外,就算不使用 this,DC 也没有把它列入到“推荐的最佳实践”这一范畴里去,这样做的确有好处,但是对于能够理解和正确使用 this 的程序员来说,并非“只能这样做”的限制,而是“有时候这样做会更好”的选择。DC 在演讲中并没有单独那它作为一条“最佳实践”来讲,只是在“不使用 Object.create()“这一条里解释原因的时候提到了关于不再使用 this 的。不问出处会害人呐!

    至于你问有没有项目里这样使用,稍微上点规模的项目从头到尾这样用的我是没见过(没必要),不过用到上面举例的方法的代码倒是有见过几次。究其原因可能就是我上面说的那些,欢迎补充或讨论。

    回复
    0
  • PHP中文网

    PHP中文网2017-04-10 14:47:55

    DC是我唯一忍不住要黑的外国程序员,虽然蝴蝶书是我非常喜欢的一本书(爱之深恨之切?)

    他的许可里面硬是加一句The Software shall be used for Good, not Evil.,一个人怒战整个社区,在GNU、Debian、Fedora、Red Hat等等所有社区全都留下Bad license的宣告。 简单地考古一下可以找到他的各种顽固言论,JSMin JSLint JSON等等各种伟大的项目都被这么个License糟蹋了


    介绍一下DC的傲娇本质,好像歪楼了

    我觉得最大的问题在于,JS已经是工程性很弱,很难被理解的一门语言了。这种完全构造,完全砍掉原型机制,把JS中最后一点点和“类”性质类似的部分也去掉的做法,只能让JS,让你的代码更加远离多数程序员的理解范围,让你的代码难以维护。如果你的项目只有一个人开发,只有一个人维护,自然没问题。但想在开源或者商业的实际项目中用,必然事倍功半。这种事倍功半的事,除非有着压倒性的其他优势(嗯,比如性能和硬件亲和性致胜的汇编,比如元编程能力致胜的FP),否则没有出路。

    Linus可以插着腰说“I'm always right”,DC道行还差了点,你我就差距更大了,还是先按着多数人能接受的路子来比较踏实一点

    回复
    0
  • 取消回复发送