Как структурировать код / ​​функцию с помощью многоуровневых функциональных слоев - PullRequest
0 голосов
/ 10 июня 2018

Я новичок в кодировании и не могу понять, как справиться с «проблемой структурирования кода / функции».Поэтому, когда вы пишете функцию, и функция начинает иметь больше подчиненных функций ... Я имею в виду, что она становится многоуровневой функцией, я не знаю, как мне структурировать свой код, чтобы он оставался чистым и читаемым.

Вот пример кода, который является частью игры в крестики-нолики

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, и она углубляется в функции: declaireWinner, disableClickOnFields, higlightAllFields,declaireWinnerOnModal.

Таким образом, когда у вас есть, скажем, дополнительный уровень функций в одной из подфункций в вашей главной функции, код действительно становится нечитаемым, слишком длинным и громоздким.

Когда я начал писать в свой основной файл app.js, я думал о том, каким должен быть главный контроллер.Тогда я бы не стал углубляться на один уровень и импортировал бы все необходимые функции, необходимые для функций первого уровня.Здесь я бы импортировал все функции, которые необходимы для функции gameOver.

Но тогда я должен передать в gameOver всю глобальную и все остальные переменные, которые я объявил лексически выше gameOver, и тогда определения функций и вызов будут очень длинными и безобразными: gameOver(global1,global2,global3,global4,...)

И функции, в которые я импортировал, не будут иметь доступа к объекту переменной родительской функции, поэтому я должен снова передать в качестве параметров все переменные, которые нужны второму уровню функции - и этим подчиненным функциям -.

1 Ответ

0 голосов
/ 10 июня 2018

Но тогда я должен передать в '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?!
   })
}

Into:

/* 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);
...