#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 = …
что присваивает значение onx
. Не знаю, почему вы ожидаете, что он сделает что-то еще.
Ответ №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
.