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

Dav*_*vid 62 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())
Run Code Online (Sandbox Code Playgroud)

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())
Run Code Online (Sandbox Code Playgroud)

rek*_*o_t 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())
Run Code Online (Sandbox Code Playgroud)

虽然在这个例子中两者的行为方式完全相同,但存在差异.使用基于闭包的实现,您可以拥有私有变量和方法(只是不要在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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 在现代浏览器中,基于原型的分类并不快.您所引用的文章在您发布时已有三年,现在已经六年了,即完全无关紧要.这是一个性能测试,更相关 - http://jsperf.com/prototype-vs-closures/20. (10认同)
  • 另一个区别是,如果你使用this.getTitle,每个实例都会有不同的函数getTitle做同样的事情.如果您使用Book.prototype.getTitle,它们将从原型共享相同的方法实现. (4认同)
  • 实际上,Chrome现在显示关闭速度更快:http://jsperf.com/prototype-vs-closures/20 (2认同)
  • 在Chrome 53.0.2785上,我看到原型速度更快(大约10倍操作/秒). (2认同)

小智 12

哪个更好有时可以通过其使用的上下文来定义.

我如何在PrototypeClosure编码方法之间做出选择的三个约束条件(我主动使用两者):

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

1.业绩/资源

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

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

2.压缩

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

压缩 - 原型方法

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

Book.prototype.getTitle = function () {
  return this.title;
};
Run Code Online (Sandbox Code Playgroud)

是YUI压缩到

function Book(a){this.title=a}Book.prototype.getTitle=function(){return this.title};
Run Code Online (Sandbox Code Playgroud)

节省约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;
};
}
Run Code Online (Sandbox Code Playgroud)

是YUI压缩到

function Book(a){var a=a;this.getTitle=function(){return a}};
Run Code Online (Sandbox Code Playgroud)

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

3.项目管理

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

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

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

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


Ski*_*ick 11

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

你也可以这样做:

function Book(title) {
    return {
        getTitle: function () {
            return title;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

返回的对象只有一个被调用的访问器getTitle,它将返回在闭包中保存的参数.

Crockford 在JavaScript中有一个很好的私人会员页面- 绝对值得一读,看看不同的选项.


Arm*_*ian 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###
Run Code Online (Sandbox Code Playgroud)

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