Объектно-ориентированный JavaScript с прототипами против замыканий - PullRequest
62 голосов
/ 25 августа 2010

Мне любопытно, в чем разница между следующими методами ООП 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 ]

46 голосов
/ 25 августа 2010

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

12 голосов
/ 25 января 2017

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

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

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

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

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

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

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.Управление проектами

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

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

Я не большой поклонник сложной проверки GIT-репозитория / ветки / слияния / конфликта потока.Я предпочитаю простой.

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

11 голосов
/ 25 августа 2010

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

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

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

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

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

5 голосов
/ 06 июня 2013

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

0 голосов
/ 25 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...