对象已创建但似乎正在共享引用

时间:2016-08-29 02:27:57

标签: javascript typescript

我正在构建一个编辑器,当你按下播放时它会将一堆对象转换为Prefab(这会向我的引擎解释如何构建一个对象)。当我停止它们时,我想再次重建Prefab,它应该恢复到原始状态(在按下游戏之前)。我遇到的问题是,当stop被按下时,项目不会回到原来的状态。当他们停下来时,他们似乎处于他们所处的状态。

以下是我用来来回转换Prefabs的课程:

class Prefab {

    public name: string;
    public components: PrefabComponent[] = [];

    public static create(gameObject: GameObject): Prefab {
        let prefab = new Prefab;
        prefab.name = gameObject.name;
        gameObject.components.forEach(comp => {
            let prefabComp = new PrefabComponent;
            prefabComp.name = comp.name;
            for (let c in comp) {
                let prefabProp = new PrefabProperty;
                prefabProp.name = c;
                if (typeof comp[c] == 'object') {
                    prefabProp.value = Object.create(comp[c]);
                } else {
                    prefabProp.value = comp[c];
                }
                prefabComp.properties.push(prefabProp);
            }
            prefab.components.push(prefabComp);
        });
        return prefab;
    }

    public static toObject(prefab: Prefab): GameObject {
        let gameObject = new GameObject(prefab.name);
        prefab.components.forEach(comp => {
            let newComp;
            if (comp.name.toLowerCase() != 'transform') {
                newComp = gameObject.addComponent(comp.name);
            }
            if (!newComp) {
                newComp = gameObject.getComponent(comp.name);
            }
            comp.properties.forEach(prop => {
                if (prop.value instanceof Sprite) {
                    newComp[prop.name] = Sprite.create(prop.value.path);
                } else if (typeof prop.value == 'object') {
                    newComp[prop.name] = Object.create(prop.value);
                } else {
                    newComp[prop.name] = prop.value;
                }
            });
        });
        return gameObject;
    }

}

class PrefabComponent {

    public name: string;
    public properties: PrefabProperty[] = [];

}

class PrefabProperty {

    public name: string;
    public value: any;

}

以下是我开始和停止游戏的方式:

play.addEventListener('click', (event) => {
    event.preventDefault();
    // Game has started
    // Stop was pressed
    if (game instanceof SpyNginMain) {
        game.stopGame();
        game = null;
        play.classList.remove('active');
        pause.classList.remove('active');
        // Reset the editor
        EditorObjectManager.clear();
        prefabs.forEach(prefab => {
            EditorObjectManager.addItem(Prefab.toObject(prefab));
        });
        updateScene();
    }
    // Game has not started
    // Play was pressed
    else {
        game = new SpyNginMain();
        prefabs = [];
        EditorObjectManager.items.forEach(item => {
            prefabs.push(Prefab.create(item));
        });
        game.init(scene, prefabs);
        game.startGame();
        play.classList.add('active');
    }
});

问题似乎是当我尝试使用PrefabProperty类转换Object时。我认为它不是创建一个实例,而是创建一个对原始的引用,但我不确定...

2 个答案:

答案 0 :(得分:1)

由于以下代码,您的create方法肯定会保留对原始对象的引用:

    if (typeof comp[c] == 'object') {
        prefabProp.value = Object.create(comp[c]);
    } else {
        prefabProp.value = comp[c];
    }

Object.create调用创建一个以原始对象为原型的新对象,因此如果随后在原始对象中添加/修改/删除属性,则更改也将出现在新创建的对象中。 / p>

我认为你在这里要做的是克隆原始对象?克隆有许多现有的实现(例如lodash的cloneDeep)。

我会用一次clone(comp[c])调用替换上面引用的所有五行,因为您的typeof检查在其他方面也不可靠(例如typeof null == 'object'为真,{{1}是的,等等。)

答案 1 :(得分:0)

这可能只是一个打字稿的东西,但看到这个没有括号看起来不正确:

let prefabComp = new PrefabComponent;

我认为应该是:

let prefabComp = new PrefabComponent();

此处此行:newComp[prop.name] = prop.value;如果prop.value是一个对象,那么该组件将从旧组件中引用。

查看对象是否相同的好方法是===

const a = {'a': 'hello'};
console.log(a === a); // true
const b = {'a': 'hello'};
console.log(a === b); // false