Равенство объектов JavaScript: вызов new с параметрами, взятыми из другого объекта, возвращает newObject === originalObject
Один из моих интерфейсов имеет несколько реализаций. Иногда я хочу перейти от более простой реализации к более сложной. Поскольку каждая реализация имеет toJSON()
и static revive(json)
функция, моя идея состояла в том, чтобы просто позвонить ComplexImplementation.revive(simpleInstance.toJSON())
вернуть экземпляр более мощной реализации с теми же значениями, что и у более простого оригинала, но с добавленными функциями, найденными в более сложной реализации. Кардинально newObject === originalObject
ожидается, что оно будет ложным, а типы newObject и originalObject будут разными.
Однако это не наблюдаемое поведение. При совместном вызове этих двух функций результат будет таким, как если бы я назначил некоторые свойства, присутствующие в сложной реализации, более простому экземпляру (это означает, что объект имеет больше свойств, чем определено в простой реализации, но не имеет ни одного из более сложные функции, и он также имеет тот же тип, что и исходный объект). Более того, два объекта фактически одинаковы (newObject === originalObject
) возвращает истину.
Вот код, который выполняет дублирование (пока он не очень чистый...):
public static copy(original: IVariant): Slide {
// casting is dirty but in this case we want to coerce this thing into
// eventually expanding into a full blown Slide so we need to do it.
const json = <ReturnType<Slide['toJSON']>> original.toJSON();
// in case it's not really a Slide JSON, we assign default values
const jsonX = Object.assign(json, {
index: json.index ? json.index : 0,
itemOffset: json.itemOffset ? json.itemOffset : 0,
renderPath: json.renderPath ? json.renderPath : undefined,
templateFields: json.templateFields ? json.templateFields : [],
});
const slide = Slide.revive(jsonX);
console.log(slide); // same as below
console.log(original); // same as above
console.log(slide === original); // true
return slide;
}
Я ожидаю, что какой-либо объект входит в качестве параметра, который не будет изменен, и я ожидаю, что функция вернет совершенно новый объект типа Slide (первое Slide.revive()
делает, чтобы позвонить new Slide()
). Я также проверил скомпилированную версию (es2016) кода, и он вышел практически нетронутым.
Это какая-то магия оптимизации происходит за кулисами, или я просто принципиально не понял, как что-то здесь работает?
Заранее спасибо за вашу помощь!
Изменить: код для Slide.revive()
и конструктор слайдов и решение
Спасибо за комментарии, через которые я наткнулся на решение: класс Slide наследует свой конструктор от класса Variant. Конструктор Variant вернет установленный экземпляр, если он существует с таким же идентификатором. Таким образом, это просто логично, что результирующий объект будет ===
оригинал. Смущающий недосмотр с моей стороны...
В классе Slide:
public static revive(duck: ReturnType<Slide['toJSON']>) {
const s = new Slide(duck.id, duck.path);
if (duck.name) s.name = duck.name;
if (duck.tags) s.tags = duck.tags;
// ... loads more assignments ...
return s;
}
В классе Variant (от которого наследуется Slide):
constructor(id: string, path: string) {
// check if there's already an instance with this ID established and return that if that's the case <= that's the problem
const existing = Variant._instances[id];
if ( existing ) return existing;
this.id = id;
this.path = path;
// add this fresh instance to this Variant's instance management list
Variant._instances[id] = this;
}
Итак, подведем итог: я забыл проверить конструктор родительского класса, в котором скрывалась проблема. Также спасибо за подсказку RE Object.assign
изменение цели.