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

Не могли бы вы объяснить разницу между методами установки в конструкторе и через объект-прототип? В следующем коде показаны эти два способа настройки методов - оба 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();
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
18
0
4 299
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Значит, если бы у меня был BetterMessageClass.prototype = new MessageClass, унаследовал бы только say_hello?

snitko 08.01.2009 01:43

Я могу вызвать метод say_bye (который объявлен как this) из дочернего класса. Вот мой код: function Employee () {this.say_bye = function () {alert ('увидимся'); }; } function Manager () {} Manager.prototype = новый сотрудник; Manager.prototype.constructor = Менеджер; var manager = новый менеджер (); manager.say_bye ();

Raghav 20.09.2010 03:56

@foxxtrot Это неверно. Даже методы, объявленные в this внутри конструктора, доступны в дочернем классе. Рассмотрим код errorA.setPrivate('A') от Prestaul, который обращается к методу, объявленному на this родительским классом MessageClass.

Suneel 13.06.2015 23:26

Я также ошибочно думал, что разница заключается в наследовании, но это не так: function parentClass() { this.inheritedFunc = function() {return "Some Value"}; } function childClass() {}; childClass.prototype = new parentClass(); var childObj = new childClass(); console.info(childObj.inheritedFunc()); //successfully logs "Some Value"

Gilad Barner 03.05.2016 16:40

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

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

Что, если я сначала определю методы как функции, а затем скажу в конструкторе следующее: 'this.say_bye = MessageClass_sayhello;

snitko 08.01.2009 01:47

немного лучше, но все же не так эффективно, как прототипирование, и вы все еще не можете расширить это

annakata 08.01.2009 11:40

Вопрос о возможности расширения объекта будет во многом зависеть от того, какую js lib вы используете и используете ли вы ее. Если конструктор вызывается при расширении объекта, методы доступны. Я считаю, что большинство основных библиотек вызывают конструктор при расширении.

Prestaul 08.01.2009 17:09

Например, если я сам расширяю объект: Subclass.prototype = new Class (); тогда функции, назначенные в конструкторе класса, доступны в подклассе. Однако эти функции являются общими для экземпляров Subclass, что может привести к неожиданному поведению. Конечно, лучше их прототипировать.

Prestaul 08.01.2009 17:13
Ответ принят как подходящий

foxxtrot и annakata оба правильные, но я добавлю свои 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 не поддерживает классы (это не значит, что мы не можем делать хорошую объектно-ориентированную разработку), иначе мы не будем обсуждать этот вопрос.

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

Если я возьму 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.info(errorA.getPrivate()); // prints 'A'
console.info(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.info(errorA.getPrivate()); // prints 'B'

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

errorA.clickHandler();
console.info(errorA.someoneClickedMe); // prints 'true'
console.info(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.info(errorA.getPrivate()); // prints 'A'
console.info(errorB.getPrivate()); // prints 'B'

блин за ваше красноречие :) (хотя я не согласен, заметной разницы нет)

annakata 08.01.2009 11:39

Хотя, если вы используете this._private, переменная доступна извне.

Chris 02.06.2009 18:54

(технически говоря, вы можете отслеживать с помощью отладчика в любом случае, если не во всех, JS-средах)

Chris 02.06.2009 18:56

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