Настройка методов через объект-прототип или в конструкторе, разница?[дубликат]

StackOverflow https://stackoverflow.com/questions/422476

Вопрос

На этот вопрос уже есть ответ здесь:

Не могли бы вы объяснить разницу между настройкой методов в конструкторе и через объект-прототип?Следующий код показывает эти два способа настройки методов - say_hello и say_bye оба работают нормально:

function MessageClass() {
  this.say_bye = function() { alert('see ya'); };
}

MessageClass.prototype.say_hello = function() { alert('hello'); };

x = new MessageClass();
x.say_hello();
x.say_bye();
Это было полезно?

Решение

фокстрот и аннаката оба верны, но я добавлю свои 2 цента.

Если вы используете прототип, то каждый экземпляр "MessageClass" действительно ссылается на одни и те же функции.Функции существуют в памяти только один раз и используются для всех экземпляров.Если вы объявляете методы в конструкторе (или иным образом добавляете его к определенному экземпляру), а не в прототипе, то для каждого экземпляра MessageClass создается новая функция.

При этом, вероятно, в большинстве случаев нет какой-либо заметной разницы в производительности, и маловероятно, что вы также увидите разницу в использовании памяти.Я бы выбрал метод прототипа, если только у вас нет веских причин поступить иначе.Единственная причина, по которой я могу предположить, что вы, возможно, захотите объявить метод в конструкторе, - это если вам нужно закрытие.Например, если у вас есть обработчики событий или вы хотите имитировать частные свойства с помощью методов получения / установки, вы могли бы сделать:

function MessageClass() {
    var self = this;
    this.clickHander = function(e) { self.someoneClickedMe = true; };

    var _private = 0;
    this.getPrivate = function() { return _private; };
    this.setPrivate = function(val) { _private = val; };
}

Редактировать: Поскольку было обсуждение того, как это влияет на объекты, расширенные другим объектом с функциями, назначенными в конструкторе, я добавляю немного больше деталей.Я мог бы использовать термин "класс", чтобы упростить обсуждение, но важно отметить, что js не поддерживает классы (это не значит, что мы не можем хорошо разрабатывать OO), иначе мы бы не обсуждали этот вопрос.

Большинство библиотек javascript вызывают конструктор для базового класса и подкласса.(например,Prototype.js 's Object.extend) Это означает, что методы, назначенные в конструкторе каждого из них, будут доступны для результирующих объектов.Однако, если вы сами расширяете объекты, могут возникнуть неожиданные последствия.

Если я возьму приведенный выше MessageClass и расширю его:

function ErrorMessageClass() {}
ErrorMessageClass.prototype = new MessageClass();

errorMsg = new ErrorMessageClass();

Тогда ErrorMsg будет иметь в себе методы GetPrivate и setPrivate, но они могут вести себя не так, как вы ожидали.Потому что эти функции были ограничены, когда они были назначены (т.е.в "ErrorMessageClass.prototype = new MessageClass()" используются не только методы get / setPrivate, переменная _private также становится общей для всех экземпляров ErrorMessageClass .По сути, это делает _private статическим свойством для ErrorMessageClass .Например:

var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'B'

Аналогично с функцией clickHandler и свойством someoneClickedMe:

errorA.clickHandler();
console.log(errorA.someoneClickedMe); // prints 'true'
console.log(errorB.someoneClickedMe); // prints 'true'

Однако измените определения этих функций, чтобы использовать this._private:

this.getPrivate = function() { return this._private; };
this.setPrivate = function(val) { this._private = val; };

и поведение экземпляров ErrorMessageClass становится больше похожим на то, что вы ожидаете:

errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'B'

Другие советы

Если вы привязываете методы с помощью prototype, JS должен сделать это только один раз и привязывается к объектному классу (что делает его приемлемым для расширений OO JS).

Если вы выполняете привязку внутри функции "класс", JS должен выполнять работу по созданию и назначению для каждого экземпляра.

Разница заключается в том, когда вы производите класс от класса Message .Только методы, объявленные в прототипе, будут доступны в дочерних классах Message.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top