具有原型与闭包的面向对象 javascript

IT技术 javascript oop
2021-03-02 23:40:14

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

对比

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个回答

第二个并没有真正创建一个实例,它只是返回一个对象。这意味着您不能利用像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

在 Chrome 53.0.2785 上,我看到原型要快得多(大约 10 倍操作/秒)。
2021-04-16 23:40:14
实际上,Chrome 现在显示闭包速度更快:jsperf.com/prototype-vs-closures/20
2021-04-28 23:40:14
另一个区别是,如果您使用 this.getTitle,每个实例都会有一个不同的函数 getTitle 来做同样的事情。如果您使用 Book.prototype.getTitle,它们将共享原型中相同的方法实现。
2021-04-30 23:40:14
@opensas,我不确定在实践中是否真的如此。我认为现代浏览器可能会编译一次闭包并重用它。它可以通过识别哪些变量属于函数外的作用域,并将这些变量用作函数的一种隐藏参数列表来实现。
2021-04-30 23:40:14
在现代浏览器中,基于原型的分类并没有那么快。您所引用的文章在您发布时已有 3 年历史,而现在已有 6 年历史,即完全无关紧要。这是一项性能测试,更相关 - jsperf.com/prototype-vs-closures/20
2021-05-11 23:40:14

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

我如何在PrototypeClosure编码方法之间进行选择的三个约束(我积极使用两者):

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

1. 性能/资源

对于对象的单个实例,任何一种方法都可以。任何速度优势很可能可以忽略不计。

如果我要实例化其中的 100,000 个,例如构建图书库,那么Prototype Method将是首选。所有的.prototype。函数只会被创建一次,如果使用Closure Method,这些函数不会被创建 100,000 次资源不是无限的。

2. 压缩

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

压缩 - 原型方法

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%。可以优化局部变量。在具有许多支持功能的大型module中,这可以显着节省压缩。

3. 项目管理

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

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

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

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

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

你也可以这样做:

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

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

Crockford在 JavaScript 中的私人成员上有一个很好的页面- 绝对值得一读以查看不同的选项。

这也是关于引擎盖下的可重用性在第一个使用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另一方面,原型成员存在于对象所有实例的唯一副本中所以这是它们之间的一个更微妙的区别,由于关闭技巧,从第一次叹息中并不是很明显。

这里有一篇关于这 方面的文章,一般来说 Book inharets 来自 Book.prototype。在第一个示例中,您将函数添加到 getTitle Book.prototype

链接失效了,请修改
2021-05-08 23:40:14