【问题标题】:How to structure a code/function with multi-level function layers如何构建具有多层功能层的代码/功能
【发布时间】:2018-11-19 20:36:44
【问题描述】:

我是编码初学者,我不知道如何处理“代码/函数结构问题”。因此,当您编写一个函数并且该函数开始具有更多从属函数时......我的意思是它开始成为一个多级函数,我不知道我应该如何构造我的代码以保持它的干净和可读性。

这是一个示例代码,它是 tic-tac-toe game 的一部分

function gameOver(gameWonObj) {

  if (gameWonObj === 'tie') {
    higlightAllFields();
    disableClickOnFields();
    declaireWinner('tie');
  } else {
    highlightWinningHits();
    disableClickOnFields();
    declaireWinner(gameWonObj.player);
  }

  function higlightAllFields() {
    allSquaresIds = ORIG_BOARD;

    for ([idOfSquare, currValue] of allSquaresIds.entries()) {
      currSquare = document.getElementById(idOfSquare);
      currSquare.style.backgroundColor = TIE_COLOR;
    }
  }

  function highlightWinningHits() {
    winningSquaresIds = WIN_COMBOS[gameWonObj.index];
    highlightColor = (gameWonObj.player === HU_PLAYERS_SIGN) ? WINNER_COLOR : LOOSER_COLOR;

    winningSquaresIds.forEach(currentId => {
      currentWinningSquare = document.getElementById(currentId);
      currentWinningSquare.style.backgroundColor = highlightColor;
    });
  }

  function disableClickOnFields() {
    CELLS.forEach(cell => {
      cell.removeEventListener('click', turnClick, false)
    })
  }

  function declaireWinner(player) {
    if (player === 'tie') {
      declaireWinnerOnModal('ITS A TIE GAME', 'blue')
    } else if (player === HU_PLAYERS_SIGN) {
      declaireWinnerOnModal('YOU WON', 'lightgreen')
    } else if (player === AI_PLAYERS_SIGN) {
      declaireWinnerOnModal('AI WON', 'red')
    }

    function declaireWinnerOnModal(message, textColor) {
      END_GAME_MODAL.style.display = 'block';
      END_GAME_MODAL.style.color = textColor;
      END_GAME_MODAL.innerHTML = `<p>${message}</p>`;
    }
  }

}

在这个例子中,我有一个主函数:gameOver,它的函数更深一层:declaireWinnerdisableClickOnFieldshiglightAllFieldsdeclaireWinnerOnModal

因此,当您在主函数中的一个子函数中添加一层函数时,代码真的变得难以阅读、太长且难以承受。

当我开始写入我的主 app.js 文件时,我在考虑应该是什么主控制器。然后我不会更深一层,我会导入我的第一级函数所需的所有必要函数。在这里,我将导入函数gameOver 所需的所有函数。

但是我应该将我在gameOver上方的词法声明的所有全局变量和所有其他变量传递给gameOver,然后函数定义和调用将非常长而且丑陋:gameOver(global1,global2,global3,global4,...)

我导入的函数无法访问父函数的变量对象,因此我应该再次将第二级函数以及从属函数需要的所有变量作为参数传递。

【问题讨论】:

  • 由于提供的代码有效并且原始发布者希望获得更多关于如何构建他的项目的指导,我相信这个问题属于 Stack Exchange 网络中的另一个站点:Code Review。这个问题可能会在这里结束,因为它要么过于主要基于意见,要么过于宽泛。我建议您在此处将其删除并在 Code Review 上发布相同的内容。
  • 感谢 Ivan 我做到了

标签: javascript function parameter-passing code-cleanup


【解决方案1】:

但是我应该将所有全局变量和所有其他变量都传递给“gameOver”,这些变量是我在 gameOver 上方的词法声明的,然后函数定义和调用将非常长且丑陋:(gameOver(global1,global2,global3, global4,....))

你可以引入一个包含所有全局变量的游戏“状态”:

const state = { global1, global2, global3, global4 };

然后您只需将该状态传递给函数:

gameOver(state);

如果函数只需要一个或两个全局变量,它也可以解构对象:

function gameOver({global1, global2 }) {
  console.log(global1);
}

因此,当您在主函数中的一个子函数中添加一层函数时,代码真的变得难以阅读、太长且不堪重负。

您不应该将函数嵌套得更深一层。其中一些函数可能是助手,它们只能访问外部函数的一两个变量,因此您可以将它们作为参数传递。所以例如你可以这样:

function disableClickOnFields() {
   CELLS.forEach(cell => { // Global?!
      cell.removeEventListener('click', turnClick, false) // another global?!
   })
}

进入:

/* Removes the listener on the specific event from all elements of thr collection */
function removeEventListener(collection, evt, listener) {
  for(const el of collection) {
    el.removeEventListener(evt, listener, false);
  }
}

然后可以在多个位置重复使用,并且可以轻松传递状态:

removeEventListener(state.cells, "click", handleClick);

【讨论】:

  • 感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多