为什么创建一个新数组而不是清空旧数组会导致这里出现问题?
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.
关于您遇到的错误,经过一些测试后,我认为这与您在方法中使用的 this
与 editModeElements
不同这一事实有关。据我了解,mithril 使用 POJO 作为方法中使用的 this
的原型。我想也许在削减您的代码时,某些部分已被更改,这使得我在尝试制作它时出现的错误略有不同 运行。问题的症结在于 this
!= editModeElements
并且它使代码非常混乱。有时您可能正在修改原型,有时您可能正在修改实例。
一些问题:
- 当你设置
oncreate: this.update
时,this
不是editModeElements
而是当前作用域的this。所以很可能 this.update
未定义并且 oncreate 设置为未定义并且从未调用过。
- 传递给
createActionEditorList
的 this
与 editModeElements.addAction
中使用的 editModeElements.addAction
不是同一个对象。
- 您有一些方法参考
actions.actions
但 editModeElements
被初始化为 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);
我在 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.
关于您遇到的错误,经过一些测试后,我认为这与您在方法中使用的 this
与 editModeElements
不同这一事实有关。据我了解,mithril 使用 POJO 作为方法中使用的 this
的原型。我想也许在削减您的代码时,某些部分已被更改,这使得我在尝试制作它时出现的错误略有不同 运行。问题的症结在于 this
!= editModeElements
并且它使代码非常混乱。有时您可能正在修改原型,有时您可能正在修改实例。
一些问题:
- 当你设置
oncreate: this.update
时,this
不是editModeElements
而是当前作用域的this。所以很可能this.update
未定义并且 oncreate 设置为未定义并且从未调用过。 - 传递给
createActionEditorList
的this
与editModeElements.addAction
中使用的editModeElements.addAction
不是同一个对象。 - 您有一些方法参考
actions.actions
但editModeElements
被初始化为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);