Javascript 如何使此函数递归/运行,直到不满足要求为止?
到目前为止,我只能在每个if语句之后硬编码相同的代码段,这只需要更改getAdjacentCells(id)的参数。我没办法重复这一部分。我认为这可以递归地完成,但我不知道怎么做 编辑:我最初键入isCellEmpty得到一个对象数组:[{topLeft:null},{topCenter:“cell-1-2”},{topRight:“cell-1-3”},{Middleft:null},{middleRight:“cell-2-3”},而实际上它是一个单独的对象:{topLeft:null,topCenter:“cell-1-2”,topRight:“cell-1-3”,Middleft:null,middleRight:“cell-2-3”}Javascript 如何使此函数递归/运行,直到不满足要求为止?,javascript,recursion,Javascript,Recursion,到目前为止,我只能在每个if语句之后硬编码相同的代码段,这只需要更改getAdjacentCells(id)的参数。我没办法重复这一部分。我认为这可以递归地完成,但我不知道怎么做 编辑:我最初键入isCellEmpty得到一个对象数组:[{topLeft:null},{topCenter:“cell-1-2”},{topRight:“cell-1-3”},{Middleft:null},{middleRight:“cell-2-3”},而实际上它是一个单独的对象:{topLeft:null,to
//获取一个如下所示的对象:{topLeft:null,topCenter:“cell-1-2”,topRight:“cell-1-3”,Middleft:null,middleRight:“cell-2-3”}
函数为空(邻接单元){
Object.values(邻接单元格).forEach(id=>{
//检查存储在对象值中的ID是否不等于null
如果(id!==null){
板[getBoardPosition(id)]。打开=真;
//getAdjacentCells()将返回类似于函数作为参数的对象数组或整数数组
//如果getAdjacentCells(id)返回一个数字,则使用该id向HTML元素添加一个div
if(typeof(getAdjacentCells(id))=“number”){
//删除所有其他div,以防止重复
$(“#”+id).empty();
//附加一个空div
$(“#”+id);
//从这里开始:如果getAdjacentCells(id)返回一个对象,则对其中的每个id执行与上面相同的操作
}else if(typeof(getAdjacentCells(id))=“object”){
Object.values(getAdjacentCells(id)).forEach(id2=>{
如果(id2!==null){
板[getBoardPosition(id2)]。打开=真;
if(typeof(getAdjacentCells(id2))=“number”){
$(“#”+id2).empty();
$(“#”+id2);
//这里重复:
}else if(typeof(getAdjacentCells(id2))=“对象”){
...
}
}
})
}
}
});
}
您可以使用从getAdjacentCells
获得的值进行递归调用。但是,请确保对同一id
只调用一次getAdjacentCells
。现在重复同一个电话效率很低
另请参见代码中的一些其他建议
function isCellEmpty(adjacentCells) {
// I would move this check here, although not necessary if you prefer it in the loop.
if (typeof adjacentCells === "number") {
$("#" + id).empty().append("<div>"); // You can chain jQuery...
return;
}
for (let id of adjacentCells) { // Just use a for..of loop
if (id === null) continue; // keep IF-ELSE nesting flat.
let cell = board[getBoardPosition(id)];
if (cell.opened) continue; // Add this to avoid circling around
cell.opened = true;
isCellEmpty(getAdjacentCells(id)); // recursive call
}
}
递归在这里应该工作得很好:最基本的方法是使用
id2
调用自己的方法。但是,假设getAdjacentCells
可能返回您已经访问过的单元格,那么最终将无限递归,除非您能够跟踪您已经访问过的ID并将其传入
function setCellState(id, visited) {
if(id === null) {
return;
}
if(visited === undefined) {
visited = new Set();
}
if(visited.has(id)) {
return;
}
visited.add(id);
board[getBoardPosition(id)].opened = true;
// getAdjacentCells() will return either an array of objects similar to the one the function takes as an argument or an integer
let adjacentCells = getAdjacentCells(id);
// if getAdjacentCells(id) returns a number, add a div to the HTML element with that id
if (typeof (adjacentCells) === "number") {
// Removes all other divs, this prevents repetition
$("#" + id).empty()
// Appends an empty div
.append("<div></div>");
} else if (typeof (adjacentCells) === "object") {
Object.values(adjacentCells).forEach(id2 => setCellState(id2, visited));
}
函数setCellState(id,已访问){
如果(id==null){
返回;
}
如果(已访问===未定义){
已访问=新集合();
}
如果(访问过。有(id)){
返回;
}
已访问。添加(id);
板[getBoardPosition(id)]。打开=真;
//getAdjacentCells()将返回类似于函数作为参数的对象数组或整数数组
设adjacentCells=getAdjacentCells(id);
//如果getAdjacentCells(id)返回一个数字,则使用该id向HTML元素添加一个div
if(类型(相邻单元格)=“数量”){
//删除所有其他div,以防止重复
$(“#”+id).empty()
//附加一个空div
.附加(“”);
}else if(typeof(邻接单元格)=“对象”){
forEach(id2=>setCellState(id2,已访问));
}
我随意更改了方法名称,使其更能代表方法的实际功能。我还将其更改为从单个单元格的ID开始,因为这简化了递归,并允许围绕
getAdjacentCells
的行为进行注释,以提供更好的上下文。函数名称似乎暗示它应该返回一个布尔值,但你没有真正返回任何东西?这是故意的吗?不,它唯一做的事情是将板中id的“opened”键设置为true,添加一个div并重复。感谢帮助,但当我尝试它时,我在编辑器(VSCode)和控制台上都出现语法错误。这是导致它的部分:else if(typeof)(邻接单元格))==“对象”)我刚才有太多的右括号。如果(typeof(邻接单元格)==“对象”),请将其更改为。谢谢,但我得到了“邻接单元格不适用”当我尝试时。但是您在代码注释中写道getAdjacentCells返回一个数组或整数。那么这是其他问题吗?为了避免此类问题,提供可以运行的代码会很有帮助,因此包括该函数的定义。请参阅我的答案的补充,并解释为什么会发生这种情况。嘿,谢谢您的时间。我实际上,在键入代码时犯了一个错误,我认为getAdjacentCells()的“object”数据类型返回的是一个包含单个键的对象数组,而实际上它是一个包含多个键的单个对象。不过,您猜对了,使用object.values解决了问题。再次感谢您,您的答案除了正确之外,还非常可读,我不知道如何使用递归,因为我以前从未这样做过,但我想我现在更了解它了。
function isCellEmpty(adjacentCells) {
// I would move this check here, although not necessary if you prefer it in the loop.
if (typeof adjacentCells === "number") {
$("#" + id).empty().append("<div>"); // You can chain jQuery...
return;
}
for (let id of Object.values(adjacentCells)) { // Just use a for..of loop
if (id === null) continue; // keep IF-ELSE nesting flat.
let cell = board[getBoardPosition(id)];
if (cell.opened) continue; // Add this to avoid circling around
cell.opened = true;
isCellEmpty(getAdjacentCells(id)); // recursive call
}
}
function setCellState(id, visited) {
if(id === null) {
return;
}
if(visited === undefined) {
visited = new Set();
}
if(visited.has(id)) {
return;
}
visited.add(id);
board[getBoardPosition(id)].opened = true;
// getAdjacentCells() will return either an array of objects similar to the one the function takes as an argument or an integer
let adjacentCells = getAdjacentCells(id);
// if getAdjacentCells(id) returns a number, add a div to the HTML element with that id
if (typeof (adjacentCells) === "number") {
// Removes all other divs, this prevents repetition
$("#" + id).empty()
// Appends an empty div
.append("<div></div>");
} else if (typeof (adjacentCells) === "object") {
Object.values(adjacentCells).forEach(id2 => setCellState(id2, visited));
}