Настройка прототипа и производительности [дубликат]

Попробуйте следующее:

.glass:before {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  z-index: 1;
  background: rgba(0,0,0,0.8);

  display: block;
  width:100%;
  height: 100%;

  -webkit-filter: blur(30px);
  -moz-filter: blur(30px);
  -o-filter: blur(30px);
  -ms-filter: blur(30px);
  filter: blur(30px);
}
50
задан basarat 22 May 2014 в 15:39
поделиться

4 ответа

// This is bad: 
//foo.__proto__.bar = bar;

// But this is okay
Foo.prototype.bar = bar;

Нет. Оба делают то же самое (как foo.__proto__ === Foo.prototype), и оба прекрасны. Они только создают свойство bar на объекте Object.getPrototypeOf(foo).

То, о чем говорится в заявлении, это присвоение самому свойству __proto__:

function Employee() {}
var fred = new Employee();

// Assign a new object to __proto__
fred.__proto__ = Object.prototype;
// Or equally:
Object.setPrototypeOf(fred, Object.prototype);

предупреждение на странице Object.prototype более подробно:

Мутирование [[Prototype]] объекта по характеру, как оптимизируются современные JavaScript-движки доступ к ресурсам, очень медленная операция

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

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

Некоторые заметные цитаты:

  • Брендан Эйх (вы его знаете) сказал Writable __proto__ is гигантская боль для реализации (должна быть сериализована для проверки цикла) и создает всевозможные угрозы путаницы.
  • Брайан Хакетт (Mozilla) сказал : разрешая скриптам мутировать прототип практически любого объекта, затрудняет рассуждение о поведении скрипта и делает VM, JIT и реализация анализа более сложная и более сложная. Вывод типа имеет несколько ошибок из-за изменчивого __proto__ и не может поддерживать несколько желательных инвариантов из-за этой функции (т.е. «наборы типов содержат все возможные типы объектов, которые могут реализоваться для var / property» и «JSFunctions имеют типы, которые также являются функциями», ).
  • Джефф Уолден сказал : мутация прототипа после создания с его неустойчивой дестабилизацией производительности и воздействием на прокси и [[SetInheritance]]
  • Эрик Корри (Google) сказал, что : я не ожидаю, что большой прирост производительности приведет к тому, что proto не будет перезаписываться. В неоптимизированном коде вам нужно проверить цепочку прототипов, если объекты прототипа (а не их личность) были изменены. В случае оптимизированного кода вы можете вернуться к неоптимизированному коду, если кто-то пишет в proto. Таким образом, это не принесло бы такой большой разницы, по крайней мере, в V8-Crankshaft.
  • Эрик Фауст (Mozilla) сказал . Когда вы устанавливаете __proto__, вы не только разрушаете любые шансы, которые вы, возможно, имели для будущих оптимизаций от Ion на этом объекте, но также заставляете движок, чтобы обходить все остальные части вывода типа (информация о значениях возвращаемых функций или значений свойств, возможно), которые, по их мнению, знают об этом объекте и говорят им не делать много предположений, что предполагает дальнейшую деоптимизацию и, возможно, аннулирование существующего jitcode. Изменение прототипа объекта в середине исполнения на самом деле является неприятным кувалдой, и единственный способ, которым мы должны избегать неправильного, - это безопасно играть, но безопасный медленный.
52
ответ дан Bergi 26 August 2018 в 10:48
поделиться

__proto__ / setPrototypeOf не совпадают с назначением прототипа объекта. Например, когда у вас есть функция / объект с назначенными ей членами:

function Constructor(){
    if (!(this instanceof Constructor)){
        return new Constructor();
    } 
}

Constructor.data = 1;

Constructor.staticMember = function(){
    return this.data;
}

Constructor.prototype.instanceMember = function(){
    return this.constructor.data;
}

Constructor.prototype.constructor = Constructor;

// By doing the following, you are almost doing the same as assigning to 
// __proto__, but actually not the same :P
var newObj = Object.create(Constructor);// BUT newObj is now an object and not a 
// function like !!!Constructor!!! 
// (typeof newObj === 'object' !== typeof Constructor === 'function'), and you 
// lost the ability to instantiate it, "new newObj" returns not a constructor, 
// you have .prototype but can't use it. 
newObj = Object.create(Constructor.prototype); 
// now you have access to newObj.instanceMember 
// but staticMember is not available. newObj instanceof Constructor is true

// we can use a function like the original constructor to retain 
// functionality, like self invoking it newObj(), accessing static 
// members, etc, which isn't possible with Object.create
var newObj = function(){
    if (!(this instanceof newObj)){   
        return new newObj();
    }
}; 
newObj.__proto__ = Constructor;
newObj.prototype.__proto__ = Constructor.prototype;
newObj.data = 2;

(new newObj()).instanceMember(); //2
newObj().instanceMember(); // 2
newObj.staticMember(); // 2
newObj() instanceof Constructor; // is true
Constructor.staticMember(); // 1

Кажется, что все фокусируются только на прототипе и забывают, что функции могут иметь назначенные ему члены и создаваться после мутации , В настоящее время нет другого способа сделать это, не используя __proto__ / setPrototypeOf. Едва ли кто-либо использует конструктор без возможности наследования от родительской конструкторской функции, а Object.create не может служить.

И плюс, это два вызова Object.create, которые в настоящий момент являются нечестивыми медленными в V8 (оба браузера и Node), что делает __proto__ более жизнеспособным выбором

2
ответ дан pocesar 26 August 2018 в 10:48
поделиться

Да. prototype = так же плохо, поэтому формулировка «независимо от того, как это делается». prototype - псевдообъект для расширения функциональности на уровне класса. Его динамическая природа замедляет выполнение скриптов. С другой стороны, добавление функции на уровне экземпляра требует гораздо меньших затрат.

1
ответ дан Schien 26 August 2018 в 10:48
поделиться

Здесь приведен пример с использованием узла v6.11.1

NormalClass: нормальный класс с прототипом без редактирования

PrototypeEdited: класс с отредактированным прототипом (test() функция добавлена)

PrototypeReference: класс с добавленной функцией прототипа test(), который ссылается на внешнюю переменную

Результаты:

NormalClass x 71,743,432 ops/sec ±2.28% (75 runs sampled)
PrototypeEdited x 73,433,637 ops/sec ±1.44% (75 runs sampled)
PrototypeReference x 71,337,583 ops/sec ±1.91% (74 runs sampled)

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

Источник:

const Benchmark = require('benchmark')
class NormalClass {
  constructor () {
    this.cat = 0
  }
  test () {
    this.cat = 1
  }
}
class PrototypeEdited {
  constructor () {
    this.cat = 0
  }
}
PrototypeEdited.prototype.test = function () {
  this.cat = 0
}

class PrototypeReference {
  constructor () {
    this.cat = 0
  }
}
var catRef = 5
PrototypeReference.prototype.test = function () {
  this.cat = catRef
}
function normalClass () {
  var tmp = new NormalClass()
  tmp.test()
}
function prototypeEdited () {
  var tmp = new PrototypeEdited()
  tmp.test()
}
function prototypeReference () {
  var tmp = new PrototypeReference()
  tmp.test()
}
var suite = new Benchmark.Suite()
suite.add('NormalClass', normalClass)
.add('PrototypeEdited', prototypeEdited)
.add('PrototypeReference', prototypeReference)
.on('cycle', function (event) {
  console.log(String(event.target))
})
.run()
0
ответ дан Simon Et la famille 26 August 2018 в 10:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: