面向对象的javascript与原型和闭包

时间:2010-08-25 08:56:40

标签: javascript oop

我很好奇以下OOP javascript技术之间的区别。他们似乎最终做了同样的事情但被认为比另一个更好?

function Book(title) {
    this.title = title;
}

Book.prototype.getTitle = function () {
    return this.title;
};

var myBook = new Book('War and Peace');
alert(myBook.getTitle())

VS

function Book(title) {
    var book = {
        title: title
    };
    book.getTitle = function () {
        return this.title;
    };
    return book;
}

var myBook = Book('War and Peace');
alert(myBook.getTitle())

5 个答案:

答案 0 :(得分:46)

第二个并不真正创建实例,它只返回一个对象。这意味着您无法利用instanceof等运营商。例如。在第一种情况下,您可以if (myBook instanceof Book)检查变量是否是Book的类型,而第二种情况则会失败。

如果要在构造函数中指定对象方法,这是正确的方法:

function Book(title) {
    this.title = title;

    this.getTitle = function () {
        return this.title;
    };
}

var myBook = new Book('War and Peace');
alert(myBook.getTitle())

虽然在这个例子中两者的行为方式完全相同,但存在差异。使用基于闭包的实现,您可以拥有私有变量和方法(只是不要在this对象中公开它们)。所以你可以做一些事情,比如:

function Book(title) {
    var title_;

    this.getTitle = function() {
        return title_;
    };

    this.setTitle = function(title) {
        title_ = title;
    };

    // should use the setter in case it does something else than just assign
    this.setTitle(title);
}

Book函数之外的代码不能直接访问成员变量,它们必须使用访问器。

其他最大的不同是表现;由于使用闭包包含一些开销,基于原型的分类通常要快得多。您可以在本文中了解性能差异:http://blogs.msdn.com/b/kristoffer/archive/2007/02/13/javascript-prototype-versus-closure-execution-speed.aspx

答案 1 :(得分:12)

哪个更好有时可以根据其使用情况来定义。

我在原型关闭编码方法之间做出选择的三个限制因素(我积极使用两者):

  1. 性能/资源
  2. 压缩要求
  3. 项目管理
  4. <强> 1。性能/资源

    对于对象的单个实例,任何一种方法都可以。任何速度优势都很可能是微不足道的。

    如果我要实例化其中的100,000个,比如建立一个图书馆,那么原型方法将是首选。所有.prototype。如果使用关闭方法,则只创建一次函数,而不是创建100,000次这些函数。资源不是无限的。

    <强> 2。压缩

    如果压缩效率很重要,请使用关闭方法(例如:大多数浏览器库/模块)。请参阅以下说明:

    压缩 - 原型方法

    function Book(title) {
        this.title = title;
    }
    
    Book.prototype.getTitle = function () {
      return this.title;
    };
    

    是否将YUI压缩为

    function Book(a){this.title=a}Book.prototype.getTitle=function(){return this.title};
    

    节省约18%(所有空格/制表符/退货)。此方法需要公开变量/函数(this.variable = value),因此每个原型函数都可以访问它们。因此,这些变量/函数无法在压缩中进行优化。

    压缩 - 关闭方法

    function Book(title) {
      var title = title; // use var instead of this.title to make this a local variable
    
    this.getTitle = function () {
      return title;
    };
    }
    

    是否将YUI压缩为

    function Book(a){var a=a;this.getTitle=function(){return a}};
    

    节省约33%。可以优化局部变量。在具有许多支持功能的大型模块中,这可以显着节省压缩。

    第3。项目管理

    在一个有多个开发人员的项目中,他们可以使用同一个模块,我更喜欢该模块的原型方法,如果不受性能或压缩的限制。

    对于浏览器开发,我可以覆盖我自己的“test.js”中的“production.js”中的producton.prototype.aFunction(后面的文字),以便进行测试或开发,而无需修改“生产” .js“,可能由不同的开发人员积极开发。

    我不是复杂的GIT存储库检出/分支/合并/冲突流的忠实粉丝。我更喜欢简单。

    此外,通过测试平台重新定义或“劫持”模块功能的能力可能是有益的,但是在这里解决起来太复杂了......

答案 2 :(得分:11)

前一种方法是如何使用JavaScript。后者是更现代的技术,部分由Douglas Crockford推广。这种技术更加灵活。

你也可以这样做:

function Book(title) {
    return {
        getTitle: function () {
            return title;
        }
    }
}

返回的对象只有一个名为getTitle的访问器,它将返回保存在闭包中的参数。

Crockford在Private Members in JavaScript上有一个很好的页面 - 绝对值得一读,看看不同的选项。

答案 3 :(得分:5)

还有一点关于引擎盖下的可重用性。在具有Function.prototype属性用法的第一个示例中,Book函数对象的所有实例将共享getTitle方法的相同副本。第二个片段将使Book函数执行创建并保留在堆“书架”中的本地可闭合 book对象的不同副本。

function Book(title) {
    var book = {
        title: title
    };
    book.getTitle = function () {
        return this.title += '#';
    };
    return book;
}

var myBook = Book('War and Peace');
var myAnotherBook = Book('Anna Karenina');
alert(myBook.getTitle()); // War and Peace#
alert(myBook.getTitle()); // War and Peace##
alert(myAnotherBook.getTitle()); // Anna Karenina#
alert(myBook.getTitle());// War and Peace###

另一方面,原型成员存在于对象的所有new实例的唯一副本中。所以这是他们之间的一个微妙的区别,由于闭合技巧,第一次叹息不是很明显。

答案 4 :(得分:0)

这是一篇文章about this 一般来说,从Book.prototype预订inharets。在第一个示例中,您将函数添加到getTitle Book.prototype

相关问题