Объектно-ориентированный javascript с прототипами против закрытия

Мне любопытно, какая разница между следующими методами 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())

Ответ 1

Второй не создает экземпляр, он просто возвращает объект. Это означает, что вы не можете воспользоваться такими операторами, как instanceof. Например. с первым случаем вы можете сделать if (myBook instanceof 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

Ответ 2

Первый метод - это то, как должен был использоваться JavaScript. Последнее является более современной техникой, популяризированной частично Дугласом Крокфордом. Этот метод гораздо более гибкий.

Вы также можете сделать:

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

В возвращаемом объекте будет только один аксессор, называемый getTitle, который вернет аргумент, содержащийся в закрытии.

У Crockford есть хорошая страница Частные члены в JavaScript - определенно стоит прочитать, чтобы увидеть различные варианты.

Ответ 3

Это также немного о возможности повторного использования под капотом. В первом примере с использованием свойства Function.prototype все экземпляры функции-функции Book будут иметь одну и ту же копию метода getTitle. В то время как второй фрагмент сделает выполнение функции Book create и сохранит в куче "книжную полку" разные копии локального закрываемого объекта 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

Которая лучше иногда может быть определена контекстом их использования.

Три ограничения того, как я выбираю методы Прототип и Закрытие кодирования (я активно использую оба):

  • Производительность/Ресурсы
  • Требования к сжатию
  • Управление проектами

1. Производительность/Ресурсы

Для одного экземпляра объекта, любой метод в порядке. Любые преимущества скорости, скорее всего, будут незначительными.

Если я создаю 100 000 из них, например, создавая библиотеку книг, предпочтительнее Прототип метода. Весь .prototype. функции будут создаваться только один раз, вместо того, чтобы эти функции создавались 100 000 раз, если использовать Closure Method. Ресурсы не бесконечны.

2. Сжатие

Используйте 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%. Локальные переменные могут быть оптимизированы. В большом модуле со многими вспомогательными функциями это может иметь значительную экономию при сжатии.

3. Управление проектами

В проекте с несколькими разработчиками, которые могут работать над одним и тем же модулем, я предпочитаю Prototype Method для этого модуля, если не ограничивается производительностью или сжатием.

Для разработки браузера я могу переопределить producton.prototype.aFunction из "production.js" в своем собственном "test.js" (читать в словах) для целей тестирования или разработки без необходимости модифицировать "производство".js ", который может быть в активной разработке другим разработчиком.

Я не большой поклонник сложного GIT репозитория checkout/branch/merge/conflict flow. Я предпочитаю просто.

Кроме того, возможность переопределения или "захвата" функции модуля тестовым узлом может быть полезна, но слишком сложна для адресации здесь...

Ответ 5

вот статья об этом в общем Книга книги из Book.prototype. В первом примере вы добавляете функцию в getTitle Book.prototype