Равенство объектов 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 изменение цели.

0 ответов

Другие вопросы по тегам