面向对象的JavaScript与原型vs闭包

我很好奇以下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()) 

第二个不是真的创build一个实例,它只是返回一个对象。 这意味着你不能利用像instanceof这样的操作符。 例如。 与第一种情况,你可以做, if (myBook instanceof Book)来检查variables是否是一种types的书,而与第二个例子,这将失败。

如果你想在构造函数中指定你的对象方法,这是做到这一点的正确方法:

 function Book(title) { this.title = title; this.getTitle = function () { return this.title; }; } var myBook = new Book('War and Peace'); alert(myBook.getTitle()) 

在这个例子中,两者的行为方式完全相同,但存在差异。 在基于闭包的实现中,可以使用私有variables和方法(只是不要将它们公开在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函数之外的代码不能直接访问成员variables,他们必须使用访问器。

其他很大的区别是performance; 基于原型的分类通常要快得多,这是由于使用闭包的一些开销。 您可以阅读本文中的性能差异: http : //blogs.msdn.com/b/kristoffer/archive/2007/02/13/javascript-prototype-versus-closure-execution-speed.aspx

前一种方法是如何使用JavaScript。 后者是更现代的技术,部分由道格拉斯·克罗克福德(Douglas Crockford)推广。 这种技术更加灵活。

你也可以这样做:

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

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

Crockford在私人会员的JavaScript上有一个很好的页面 – 绝对值得一读,看看不同的select。

这也是关于可重用性的一点点。 在Function.prototype属性用法的第一个示例中,Book函数对象的所有实例将共享getTitle方法的相同副本。 虽然第二个代码片段将使Bookfunction执行创build并保留在本地可closures的 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实例的唯一副本中。 所以这是他们之间的一个更细微的差别,从第一次叹息来看并不是很明显,因为这个closures技巧。

有时可以根据用法的上下文来定义哪一个更好

我如何selectPrototypeClosure编码方法(我主动使用两种方法)的三个约束:

  1. 性能/资源
  2. 压缩要求
  3. 项目pipe理

1.性能/资源

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

如果我实例化了其中的10万个,比如build立一个图书库,那么原型方法将是首选。 所有的原型。 函数只能创build一次,而不是使用Closure方法创build这些函数100,000次。 资源不是无限的。

2.压缩

如果压缩效率很重要(例如:大多数浏览器库/模块),请使用Closure方法 。 请参阅下面的解释:

压缩 – 原型方法

 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%(所有空间/标签/退货)。 这个方法需要暴露variables/函数(this.variable = value),所以每个原型函数都可以访问它们。 因此,这些variables/函数不能在压缩中被优化。

压缩 – closures方法

 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%。 局部variables可以被优化。 在具有许多支持function的大型模块中,这可以显着节省压缩。

3.项目pipe理

在一个包含多个开发人员的项目中,如果不受性能或压缩限制,我更喜欢该模块的原型方法

对于浏览器的开发,为了testing或者开发的目的,我可以从我自己的“test.js”(后缀中的)中的“production.js”覆盖producton.prototype.aFunction,而不必修改“production.js” ,这可能正在由另一个开发人员积极开发。

我不是一个复杂的GIT库检查/分支/合并/冲突stream的大粉丝。 我更喜欢简单。

此外,通过testing台重新定义或“劫持”模块function的能力是有益的,但是在这里解决起来太复杂了。

这里有一篇关于这个从Book.prototype的一般书籍inharets。 在第一个示例中,您将函数添加到getTitle Book.prototype