blockquote>
- Почему этот журнал
5
,undefined
,undefined
,6
вместоundefined
,6
,undefined
,6
?- Почему замена прототипа не меняет прототип всех экземпляров объекта, как это обычно бывает?
По сути, это сводится к тому, что ссылки на объекты - это значения, а скорее числа, которые указывают механизм JavaScript (V8 в вашем случае), где объект находится в памяти. Когда вы копируете значение, вы делаете именно это: вы копируете значение. Копирование ссылки на объект делает копию ссылки (а не объекта) и никоим образом не связывает место назначения этого значения с источником значения больше, чем это связывает
b
сa
:var a = 5; var b = a; a = 6; console.log(b, a); // 5, 6
Итак, ваш код регистрирует то, что он регистрирует, и не изменяет прототип
instance1
, по той же причине этот код записывает то же самое и не меняет значениеinstance1.p
:
var foo = {x: 5}; var instance1 = {p: foo}; foo = {y: 6}; var instance2 = {p: foo}; console.log(instance1.p.x, instance1.p.y, instance2.p.x, instance2.p.y);
Давайте набросим на него некоторое ASCII-искусство (ну, Unicode-art), которое также ответит:
blockquote>
- Что делает двигатель V8, шаг за шагом, в этом коде?
После запуска этого:
var obj = function() {}; obj.prototype.x = 5; var instance1 = new obj();
... у вас есть что-то примерно так в памяти (игнорируя некоторые детали):
+−−−−−−−−−−−−−−−−−−−−−+ | (function) | +−−−−−−−−−−−−−−−−−−−−−+ obj−−−>| prototype |−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−+ \ \ \ \ +−−−−−−−−−−+ +−>| (object) | / +−−−−−−−−−−+ / | x<5> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance1 −−>| [[Prototype]] |−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+ Поскольку ссылки на объекты являются значениями, а присваивание всегда копирует значения , когда V8 (или любой другой движок) создает
instance1
, он копирует значение изobj.prototype
(показано здесь концептуально как) на внутренний слот
instance1
[[Prototype]]
.Тогда, когда вы делаете
obj.prototype = {y: 6};
... вы меняете значение в
obj.prototype
(показано здесь как изменениена
), но это не влияет на значение (
]) в слоте
instance1
[[Prototype]]
:+−−−−−−−−−−−−−−−−−−−−−+ | (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ obj−−−>| prototype |−−−−−−−−−−−−−−−−−−>| (object) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ | y<6> | +−−−−−−−−−−+ +−−−−−−−−−−+ +−>| (object) | / +−−−−−−−−−−+ / | x<5> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance1 −−>| [[Prototype]] |−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+ ... и поэтому, когда вы делаете
var instance2 = new obj();
... у вас есть:
+−−−−−−−−−−−−−−−−−−−−−+ | (function) | +−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ obj−−−>| prototype |−−−−−−−−−−−−−−−−+−>| (object) | +−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ / | y<6> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance2 −−>| [[Prototype]] |−+ +−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+ +−>| (object) | / +−−−−−−−−−−+ / | x<5> | +−−−−−−−−−−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−+ | (object) | / +−−−−−−−−−−−−−−−−−−−−−−−−−+ / instance1 −−>| [[Prototype]] |−+ +−−−−−−−−−−−−−−−−−−−−−−−−−+ ... что объясняет результат
console.log
.blockquote>
- EDIT: Как мне пойти на смену прототипа всех экземпляров?
Если вы хотите фактически изменить какой объект, который они используют в качестве своего прототипа, вы можете сделать это только в том случае, если у вас есть ссылка на экземпляр (ы), который вы хотите изменить, и только на JavaScript-движке, поддерживающем функции ES2015, с помощью
Object.setPrototypeOf
или (в среде веб-браузера, и если объект в конечном итоге наследуется отObject.prototype
) через аксессуар__proto__
свойство (не рекомендуется):Object.setPrototypeOf(instance1, obj.prototype);
setPrototypeOf
изменяет значение внутреннего слота[[Prototype]]
в объекте (как и установка__proto__
, если объект имеет его) .Вы не можете этого сделать, если у вас нет ac
Я не думаю, что вы это делаете, учитывая этот вопрос, но если вы просто хотите изменить состояние объекта, который они используют в качестве своего прототипа (возможно, добавив
y
), вы можете, конечно, просто установить на нем свойства, а так как прототипное наследование JavaScript является «живым» (есть прямая ссылка на прототип из экземпляра), вы можете затем получить доступ к этим свойствам в любом экземпляре, который наследуется от прототипа, даже если они были созданы до того, как вы внесли изменение:var Example = function() { }; Example.prototype.x = 5; var instance1 = new Example(); console.log(instance1.x, instance1.y); // 5, undefined Example.prototype.y = 6; console.log(instance1.x, instance1.y); // 5, 6