Зачем объявлять свойство экземпляра в prototype вместо конструктора?

Я полностью понимаю, почему лучше использовать прототип вместо конструктора для определения класса метод (т. е. использование "прототипа" против "этого" в JavaScript?) однако, недавно я наткнулся на класс HashMap что определяет count свойства в прототипе и map свойства в конструкторе:

js_cols.HashMap = function(opt_map, var_args) {

    /**
     * Underlying JS object used to implement the map.
     * @type {!Object}
     * @private
     */
    this.map_ = {};

    /...
}

/**
 * The number of key value pairs in the map.
 * @private
 * @type {number}
 */
js_cols.HashMap.prototype.count_ = 0;

есть ли преимущества объявления экземпляра объекта типа count в прототип вместо того чтобы сказать this.count_ = 0; в конструкторе? А если так, то почему бы и нет?--5-->?

Edit: аналогичный вопрос был задан,зачем объявлять свойства на прототипе, например переменные в JavaScript, и "значения по умолчанию" были подняты как вариант использования, но это не было объяснено почему это более желательно, чем просто определение значения по умолчанию в конструкторе.

5 ответов


Я не думаю, что HashMap класс является лучшим примером преимуществ объявлении экземпляр свойства в прототипе. Рассмотрим вместо Response класс:

function Response() {
   this.headers = {};
}
Response.prototype.statusCode = 200;

все экземпляры Response поделиться statusCode of 200 - буквально один и тот же номер в памяти будет использоваться во всех экземплярах. Это имеет смысл, если вы ожидаете, что ваш сервер ответит кодом состояния 200 большую часть времени. Те Requests что нужны разные коды состояния могут перезаписывать их по умолчанию statusCode, который создает новый номер в память.

т. е. Если у вас есть 10 000 одновременных запросов, и 5 из них 404, вам сошло с рук только 6 чисел в памяти, чтобы представить все 10 000 statusCodes.

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

Примечание см. ответ Лукаса, почему свойство, которое является объектом (например,map или headers) не может быть в прототипе: все экземпляры будут делить одно и то же ссылка, таким образом, любое обновление этой ссылки обновит все экземпляры.


Это зависит от того, как он используется, Вы уверены, что count_ не определяет количество хэш-ведер, а не точное количество элементов в хэше? Определение переменных в прототипе хорошо, если вы ожидаете, что значение останется постоянным и глобальным для всех экземпляров класса, поскольку используется только память для одной переменной независимо от того, сколько экземпляров класса вы делаете.


он работает count_, но это не работает для map_.

count_ - Это целое число, а map_ - это ссылка на объект. Если a HashMap экземпляра обновления count_, Это, по сути, создать count_ свойство на собственном экземпляре.

но, если он вставляет что-то в map_, поскольку все экземпляры разделяют одно и то же map_ ссылка, все экземпляры будут иметь одинаковые значения на карте. Это не сработает, и именно поэтому каждый экземпляр get другой map_ ссылка в конструкторе.

что касается count_ свойство, оно объявлено в прототипе только по умолчанию. Это было бы то же самое, если бы он был создан в конструкторе. Я думаю, это просто вопрос стиля кодирования.


прототипирование-это способ расширения и наследования JavaScript OOP. Таким образом, это способ сделать код многоразовым. Вы можете быть программистом конструктора, но другие могут захотеть расширить ваши объекты, если они повторно используют ваш код. И вы можете не пожелать, чтобы они взломали ваш код.

хорошее описание здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model

поздравления

Аксель


класса клиент представление клиента банка, процентные ставки которого могут быть изменены. Для каждого клиента вы должны рассчитать проценты, которые были установлены в соответствии с политикой Банка. В этом сценарии есть переменная интерес чье значение одинаково для определенных клиентов, также изменение этой переменной должно быть распространено на всех клиентов. Давайте смоделируем его в JavaScript.

var Customer = function(name, amount) {
    this.name = name;
    this.amount = amount;
};

Customer.prototype.interest = 10; //default value. which changes later
Customer.prototype.computeInterest = function() {
    this.amount += this.amount * this.interest / 100; //assume they are savings account
};

var me = new Customer('Ajinkya', 100);
var you = new Customer('RKBWS47', 1000);
var somebody = new Customer('Jon Doe', 10000);

me.computeInterest();
you.computeInterest();
somebody.computeInterest();

console.log(me.amount); //110
console.log(you.amount); //1100
console.log(somebody.amount); //11000

Customer.prototype.interest = 20; //yay!

me.computeInterest();
you.computeInterest();
somebody.computeInterest();

console.log(me.amount); //132
console.log(you.amount); //1320
console.log(somebody.amount); //13200

Это верно и для методов. Они разделяются всеми экземплярами класса с помощью этой переменной значение вызывающего объекта или экземпляра. Вы также можете использовать свойства, определенные в функциях конструктора, для имитации статических методов или способов их запоминания, методов, вызываемых классами. Используя this.interest в нашем примере не позволили нам поделиться им через me, you и somebody.

EDIT: я ответил, предполагая, что пример HashMap используется для иллюстрации вашего вопрос.