Метод прототипа перезаписи JavaScript

#javascript #class #ecmascript-6 #prototype #es6-class

#javascript #класс #ecmascript-6 #прототип #es6-класс

Вопрос:

Рассмотрим следующий код:

 class X {
  pop() { return 'ORIGINAL'; }
}

const x = new X();

x.pop(); // 'ORIGINAL' via prototype lookup

x.pop = () => 'NEW'; // install a new pop()

x.pop(); // 'NEW' calls x's pop()

Object.getOwnPropertyDescriptors(x); // has NEW pop
Object.getOwnPropertyDescriptors(Object.getPrototypeOf(x)); // has ORIGINAL pop
 

При вызове pop prototype lookup находит ОРИГИНАЛ pop . Почему назначение не перезаписывает это вместо установки НОВОГО pop x ?

Это работает, если я делаю X.prototype.pop = () => 'NEW'; это явно.

Комментарии:

1. Потому x.pop = … что присваивает значение on x . Не знаю, почему вы ожидаете, что он сделает что-то еще.

Ответ №1:

Когда вы назначаете метод объекту, этот метод применяется именно к тому объекту, который вы указали в назначении. Итак, когда вы делаете:

 x.pop = () => 'NEW';
 

Вы присваиваете свойство экземпляру объекта x , значением которого является функция. Это назначение никак не влияет на прототип этого объекта.

Когда вы выполняете метод для объекта, интерпретатор имеет последовательность поиска, чтобы найти этот метод. Во-первых, он смотрит непосредственно на объект, чтобы увидеть, существует ли это свойство. Если он находит его, это то, что выполняется.

Итак, когда вы затем делаете:

 x.pop()
 

После предыдущего назначения интерпретатор находит метод, который был назначен фактическому объекту, и выполняет его.

До того, как вы выполнили это назначение метода, когда вы это сделали x.pop() , в фактическом экземпляре объекта не было найдено метода / свойства с таким именем, поэтому интерпретатор затем проверяет, существует ли прототип, и, если есть, затем выполняет поиск по цепочке прототипов. Вот где он нашел определение .pop() из class определения и выполнил его.

Это отдельные определения, хранящиеся в разных местах, и изменение одного из них не приводит к изменению другого определения. Хотя присвоение определения для определенного свойства самому экземпляру объекта имеет тенденцию «скрывать» определение в прототипе только потому, что единственный способ получить доступ к определению в прототипе после этого присвоения — это напрямую ссылаться на прототип, потому что любая ссылка на это свойство через сам экземпляр объекта будет просто сначала найдите тот, который находится в самом экземпляре объекта (таким образом, тот, который находится в прототипе, больше не будет найден автоматически).

Комментарии:

1. Я понимаю. Я думаю, что мое замешательство заключалось в том, что процесс поиска прототипа каким-то образом применялся и к назначениям. Спасибо вам за то, что прояснили этот вопрос

2. @jsinheritancewoes Проблемы с наследием: Я надеюсь, что это не смущает вас больше, но цепочка прототипов учитывается, если свойство является свойством «доступа», то есть у него есть установщик.

3. @FelixKling не могли бы вы привести пример того, что вы имеете в виду?

4. @jsinheritancewoes: var proto = {set prop(x) { console.log(x); } }; var obj = Object.create(proto); obj.prop = 42; вызовет установщик для прототипа, он не будет создан prop obj .