Свойства объекта настройки Javascript со значением типа в прототипе?

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

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

var o = function () {

};

o.prototype.x = 0;

o.prototype.setX = function(x) {
    this.x = x;
};

var obj = new o();
obj.setX(1);
console.log(obj);

// o {x: 1, x: 0, setX: function}

Итак, мой вопрос: знаете ли вы, что значение свойства прототипа, вероятно, изменится, есть ли какой-либо реальный выигрыш в его установке в прототипе и извлечь выгоду из того, что он не должен быть инициализирован при создании объекта?

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

Он говорит разработчикам Google, что это способ сделать это, но я не уверен.

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

Ответ 1

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

Итак, если вы определяете свои объекты следующим образом:

var Class = function() {};
Class.prototype.p1 = 1;
Class.prototype.p2 = 1;
Class.prototype.p3 = 1;

Вы избегаете удара производительности во время создания экземпляра, копируя свойства для каждого объекта. Но. Эта производительность показывает свою голову, когда эти свойства доступны или изменены. И если вам придётся получить доступ к этим свойствам без их модификации, вы получаете хитов производительности при прохождении цепи прототипов каждый раз, когда вы обращаетесь к ним (потому что они никогда не копируются в локальный экземпляр). Но, если у вас есть много свойств и только доступ к небольшой части из них для каждого экземпляра, это, вероятно, идеально.

for (var i = 0; i < 100000; i++) {
  var x = new Class();
  console.log(x.p1);
  // ignore p2-p99. we don't need them right now.
}

На другом конце спектра, если вам нужно многократно перебирать свойства в небольшом количестве экземпляров, вам лучше избегать попадания в цепочку прототипов.

var Class = function() {
  this.p1 = 1;
  this.p2 = 1;
  this.p3 = 1;
}

Каждый экземпляр получает свою собственную копию p1, p2 и p3 во время создания. С цепочкой прототипов не нужно проконсультироваться, когда мы обращаемся к любому из них.

var instances = [
  new Class(), new Class(), new Class()
];

for (var i = 0; i < 1000000; i++) {
  console.log(instances[i % instances.length].p1);
  console.log(instances[i % instances.length].p2);
  console.log(instances[i % instances.length].p3);
}

Если у меня будет время позже, я проверю это позже, чтобы проверить. До тех пор все, что я могу вам дать, это теория!

ДОПОЛНЕНИЕ

Для использования прототипа существуют две возможности, не связанные с производительностью.

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

Два, прототип позволяет назначать функции и свойства всем существующим экземплярам класса. Чтобы выполнить тот же навык с свойствами уровня экземпляра, вам нужно найти и повторить.

ОРИЕНТИРЫ

Per мои последние тесты, которые я запускал только в последних версиях FF и Chrome для OS X, я использовал следующий синтаксис для однослойного ( не наследуемых):

прототип. *

function Class() {}
Class.prototype.a = 1;
Class.prototype.b = 2;
Class.prototype.c = 3;

это. *

function Class() {
  this.a = 1;
  this.b = 2;
  this.c = 3;
}

Между двумя вышеупомянутыми синтаксисами синтаксис this.* работает примерно на 10,5% быстрее всего.

Добавив уровень наследования, я использовал следующее:

прототип. *

function Base() {}
Base.prototype.a = 1;
Base.prototype.b = 2;
Base.prototype.c = 3;

function Class() {}
Class.prototype = new Base();

это. *

function Base() {
  this.a = 1;
  this.b = 2;
  this.c = 3;
}

function Class() {
  Base.apply(this);
}

И в этом случае я нашел синтаксис prototype.* примерно на 38,5% быстрее всего. Синтаксис this.* все еще немного ускорялся между браузерами для доступа к члену; но преимущество не было столь же заметным, как преимущество создания.

Я также сравнивал гибридный подход к наследованию:

function Base() {
  this.a = 1;
  this.b = 2;
  this.c = 3;
}

function Class() {
}
Class.prototype = new Base();

В целом, он работал примерно на 0,5% быстрее, чем синтаксис prototype.* (возможно, незначительный). Тем не менее, это было интересно примерно на 1% медленнее во время создания экземпляра, но на 2% быстрее во время доступа к члену, чем синтаксис prototype.*. Опять же, не очень важно, но я не могу не спросить, будут ли эти выигрыши масштабироваться по мере увеличения глубины наследования.

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

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

Например, изменение цвета фона,

document.body.style.backgroundColor = 'blue';

... примерно на 70% медленнее, чем создание экземпляра худшего исполнителя, который я тестировал.

Ответ 2

Нет никакой пользы для хранения значения свойства в prototype, если это значение свойства всегда (или большую часть времени) будет изменено при инициализации объекта. У вас будет только преимущество при совместном использовании значения для нескольких экземпляров, что в этом случае приведет к уменьшению использования памяти, но не обязательно даст лучшие результаты. Ходьба прототипа цепочки должна быть более дорогой, который выполняет поиск свойств непосредственно на object.