为什么创建一个新数组而不是清空旧数组会导致这里出现问题?

Why is creating a new array instead of emptying the old one causing a problem here?

我在 Javascript 做一个项目,遇到了一个我不明白的问题。
基本上我写了一个地图生成器,它从噪音中生成地图,那个位很好并且可以工作。
我希望最终用户能够通过放置我所谓的动作(基本上是影响底层噪声生成的形状)来编辑这张地图,而用于编辑这些动作的系统会导致问题。

我正在使用 Mithril JS 更新 UI 来编辑动作的属性,它大部分都在工作。我需要做的部分工作是单击一个操作并 select 它,这将在 UI 中显示它以允许您对其进行编辑。选择一个动作是有效的,deselecting 或 selecting 另一个动作也是如此,但如果我随后删除一个动作,它就不再显示在 UI 中。这是相关的代码片段:

var editModeElements = {
    actions: editedActions.actions,
    selectedAction: [],
    selectedPoint: null,
    update: function() {
        this.actions = editedActions;
        this.clearSelection();
        m.redraw();
    },
    deleteAction: function(action) {
        for( var i = 0; i < this.actions.actions.length; i++)
        { 
            if ( this.actions.actions[i] == action) 
            { 
                this.actions.actions.splice(i, 1); i--; 
            }
        }
        this.clearSelection();
        unsavedEdits = true;
    },
    selectAction: function(action) {
        this.selectedAction = new Array();
        this.selectedPoint = null;
        this.selectedAction.push(action);
        m.redraw();
        viewport.redraw();
    },
    clearSelection: function() {
        this.selectedAction = new Array();
        this.selectedPoint = null;
        m.redraw();
        viewport.redraw();
    },
    addAction: function(actionType) {
        var action = createBlankAction(actionType);
        this.actions.actions.push(action);
        this.selectAction(action);
        unsavedEdits = true;
    },
    oncreate: this.update,
    view: function() {
        return m(".action-dialog", [
                m(".action-editor-buttons", [
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.CIRCLE)}}, "Circle"),
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.RECTANGLE)}}, "Rectangle"),
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.POLYGON)}}, "Polygon"),
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.LINE)}}, "Line"),
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.COMPLEX_CIRCLE)}}, "Complex Circle"),
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.COMPLEX_RECTANGLE)}}, "Complex Rectangle"),
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.COMPLEX_POLYGON)}}, "Complex Polygon"),
                    m(".new-action", {onclick: function() {editModeElements.addAction(MASK_TYPE.COMPLEX_LINE)}}, "Complex Line"),
                ]),
                createActionEditorList(this.selectedAction, this),
        ]);
    }
}

希望这足以告诉我哪里出错了。问题与调用 clearSelection 时创建新数组有关。如果我从 deleteSelection 中删除该调用,问题就会消失(但删除的元素在 UI 中保留 selected,这是不可取的)或者如果我更改 [=11= 中的部分] 弹出元素而不是创建一个新的数组。

然而,这就是让我感到困惑的地方,clearSelection 工作正常(新数组或 pop 方法)当我用它来 deselect 通过点击一个动作之外我还创建了一个新的selectAction 中的数组不会导致任何问题。它只会在调用 deleteSelection 后停止工作。
deleteSelection 中删除元素的数组并没有特别连接到 selectedAction 数组,除了 selected 的操作来自它所以我看不到它会造成这些问题。我还将它从过滤器(这将创建一个新数组)更改为拼接(这没有)以查看是否有帮助,但没有改变。
操作在删除和更改颜色后仍然 select,它们也可以成功地拖动并保存所以问题显然是与 UI.

的连接

我认为此代码段之外的任何其他内容都不相关,因为它基本上是独立的,最后的函数 createActionEditorList 只是将操作转换为 [=41= 的 HTML 元素], 有效并且很长所以我没有包括它。

为什么创建新数组会破坏我的代码?

Mithril.js 现在建议您对有状态组件使用闭包。我建议迁移到那种风格,因为它更容易推断状态在哪里。

Mithril documentation outlining closure components:

In the above examples, each component is defined as a POJO (Plain Old JavaScript Object), which is used by Mithril internally as the prototype for that component's instances. It's possible to use component state with a POJO (as we'll discuss below), but it's not the cleanest or simplest approach.

关于您遇到的错误,经过一些测试后,我认为这与您在方法中使用的 thiseditModeElements 不同这一事实有关。据我了解,mithril 使用 POJO 作为方法中使用的 this 的原型。我想也许在削减您的代码时,某些部分已被更改,这使得我在尝试制作它时出现的错误略有不同 运行。问题的症结在于 this != editModeElements 并且它使代码非常混乱。有时您可能正在修改原型,有时您可能正在修改实例。

一些问题:

  1. 当你设置oncreate: this.update时,this不是editModeElements而是当前作用域的this。所以很可能 this.update 未定义并且 oncreate 设置为未定义并且从未调用过。
  2. 传递给 createActionEditorListthiseditModeElements.addAction 中使用的 editModeElements.addAction 不是同一个对象。
  3. 您有一些方法参考 actions.actionseditModeElements 被初始化为 actions: editedActions.actions.

如果没有您的其余代码,很难判断还发生了什么。起初我尝试将 POJO 用于状态,因为我认为这是必要的,但闭包更容易理解。如果您出于某种原因需要那种风格,也许您可​​以详细说明,因为它很难可靠地实现。

这是我认为您希望您的组件使用闭包样式重写的内容,我必须添加一些东西才能使其工作,:

// STUB
var MASK_TYPE = {
  CIRCLE: "CIRCLE",
  RECTANGLE: "RECTANGLE",
  POLYGON: "POLYGON",
  LINE: "LINE",
  COMPLEX_CIRCLE: "COMPLEX_CIRCLE",
  COMPLEX_RECTANGLE: "COMPLEX_RECTANGLE",
  COMPLEX_POLYGON: "COMPLEX_POLYGON",
  COMPLEX_LINE: "COMPLEX_LINE",
};

function createBlankAction(actionMask) {
  // STUB
  return {mask: actionMask};
}

var EditModeElements = function () {
  var actions = [],
      selectedAction = [],
      selectedPoint = null,
      unsavedEdits = false;
  function deleteAction(action) {
      for( var i = 0; i < actions.length; i++) { 
          if (actions[i] == action)  { 
              actions.splice(i, 1); i--; 
          }
      }
      clearSelection();
      unsavedEdits = true;
  }
  function selectAction(action) {
      selectedAction.length = 0;
      selectedPoint = null;
      selectedAction.push(action);
      //?viewport.redraw();
  }
  function clearSelection() {
      selectedAction.length = 0;
      selectedPoint = null;
      //?viewport.redraw();
  }
  function addAction(actionType) {
    var action = createBlankAction(actionType);
    actions.push(action);
    selectAction(action);
    unsavedEdits = true;
  }      
  return {
    view: function() {
        return m(".action-dialog", [
                m(".action-editor-buttons", [
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.CIRCLE)}}, "Circle"),
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.RECTANGLE)}}, "Rectangle"),
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.POLYGON)}}, "Polygon"),
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.LINE)}}, "Line"),
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.COMPLEX_CIRCLE)}}, "Complex Circle"),
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.COMPLEX_RECTANGLE)}}, "Complex Rectangle"),
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.COMPLEX_POLYGON)}}, "Complex Polygon"),
                    m(".new-action", {onclick: function() {addAction(MASK_TYPE.COMPLEX_LINE)}}, "Complex Line"),
                ]),
                m(ActionEditorList, {actions: actions, onDeleteAction: deleteAction}),
        ]);
    }
  };
}

function ActionEditorList() {
  return {
    view: function (vnode) {
      return m('', vnode.attrs.actions.map(function (a) {
        return m('b', {
          onclick: function () { 
            vnode.attrs.onDeleteAction(a);
          }
        }, a.mask);
      }));
    }
  }
}

m.mount(document.body, EditModeElements);