Есть ли лучший (более чистый) способ написать этот JS-код с использованием троичных операторов (без повторения кода)?

#javascript #reactjs #if-statement #ecmascript-6 #ternary-operator

#javascript #reactjs #if-оператор #ecmascript-6 #ternary-operator

Вопрос:

Итак, я пишу простой React.js приложение и просто вопрос о настройке состояния, можно ли это сделать чище?

 const enemy = this.state.enemy;
        if (this.state.isRock) {
            enemy === "rock"
                ? this.setState({ result: "Draw!" })
                : enemy === "paper"
                ? this.setState({ result: "You lose!" })
                : enemy === "scissors"
                ? this.setState({ result: "You win!" })
                : this.setState({ result: null });
        } else if (this.state.isPaper) {
            enemy === "rock"
                ? this.setState({ result: "You win!" })
                : enemy === "paper"
                ? this.setState({ result: "Draw!" })
                : enemy === "scissors"
                ? this.setState({ result: "You lose!" })
                : this.setState({ result: null });
        } else if (this.state.isScissors) {
            enemy === "rock"
                ? this.setState({ result: "You lose!" })
                : enemy === "paper"
                ? this.setState({ result: "You win!" })
                : enemy === "scissors"
                ? this.setState({ result: "Draw!" })
                : this.setState({ result: null });
        }
  

Комментарии:

1. Посмотрите на использование инструкции switch…

Ответ №1:

Учитывая, что существует только три возможных состояния (выигрыш, проигрыш, ничья), нам нужно проверить только два из них. Draw легко проверить, поэтому нам нужно только состояние win или lose. Вот пример:

 const enemy = this.state.enemy;
let wins = {
    "rock"     : "scissors",
    "paper"    : "rock" ,
    "scissors" : "paper",
}
let play = (this.state.isRock ? "rock" : (
  this.state.isPaper ? "paper" : (
    this.state.isScissors ? "scissors" : null
    )
  )
)

if (!wins[play]) {
    this.setState({ result: null })
} else if (enemy == play) {
    this.setState({ result: "Draw!" })
} else if (wins[play] == enemy) {
    this.setState({ result: "You win!" })
} else {
    this.setState({ result: "You lose!" })
}
  

Комментарии:

1. Да, и это могло бы быть даже намного проще, если сохранить состояние проигрывателя в виде строки, а не этих логических значений isXXX: jsfiddle.net/5tfyqj6k

Ответ №2:

Вы можете использовать условия как часть map, поскольку условие никогда не меняется, и установить состояние.

 const condition = {
  "rock": {
    "paper": "You lose!",
    "sccissors": "You win!",
    "rock": "Draw!"
  },
  "paper": {
    "rock": "You win!",
    "sccissors": "You lose!",
    "paper": "Draw!"
  },
  "sccissors": {
    "rock": "You lose!",
    "paper": "You win!",
    "sccissors": "Draw!"
  }
};

function getResult(enemy, isRock, isScissors, isPaper) {
  let result = null;
  
  if (isRock) {
    result = condition['rock'][enemy];
  } else if (isPaper) {
    result = condition['paper'][enemy];
  } else if (isScissors) {
    result = condition['scissors'][enemy];
  }
  
  return resu<
}

const {
  isRock, 
  isScissors,
  isPaper,
  enemy
} = this.state;


this.setState({
  result: getResult(enemy, isRock, isScissors, isPaper)
})  

Ответ №3:

У меня есть интересный подход, который вы можете попробовать, который использует цикл for в цикле и только один оператор if.

Вы могли бы использовать объектные литералы для установки значений каждого состояния:

 const stateConditions = {
    "isRock": {
      "paper": "You lose!",
      "scissors": "You win!",
      "rock": "Draw!"
    },
    "isPaper": {
      "rock": "You win!",
      "scissors": "You lose!",
      "paper": "Draw!"
    },
    "isScissors": {
      "rock": "You lose!",
      "paper": "You win!",
      "scissors": "Draw!"
    }
  };
  

В приведенном выше объекте, если бы вы выполнили state = stateConditions[‘isRock’], вы бы получили соответствующие условия для rock

В javascript this.state[‘isRock’] совпадает с this.state.isRock. И вы можете использовать свойство для перебора каждого свойства в объекте с помощью forin, таким образом, вы можете сделать следующее, чтобы найти текущее состояние. Таким образом, вы можете перебрать все возможные состояния и посмотреть, верно ли this.state[‘somestate’]:

 for (let state in stateConditions) {
    if (this.state[state] === true) {
        // you found which state was true!
    }
}
  

Окончательный код:

 const conditions = {
    "isRock": {
      "paper": "You lose!",
      "scissors": "You win!",
      "rock": "Draw!"
    },
    "isPaper": {
      "rock": "You win!",
      "scissors": "You lose!",
      "paper": "Draw!"
    },
    "isScissors": {
      "rock": "You lose!",
      "paper": "You win!",
      "scissors": "Draw!"
    }
  };

  for (const state in conditions) {
      // check if this is the state
      if (this.state[state]) {
          this.setState({ result: condition[state][this.state.enemy] });
          break;
      }
  }
  

Вот интересная статья о замене операторов switch объектными литералами

Ответ №4:

Изменим один из текущих ответов, чтобы уменьшить повторяемость:

 const condition = {
  rock: {
    paper: -1,
    scissors: 1,
    rock: 0
  },
  paper: {
    paper: 0,
    scissors: -1,
    rock: 1
  },
  scissors: {
    paper: 1,
    scissors: 0,
    rock: -1
  }
};

function getResult({enemy, isRock, isScissors, isPaper}) {
  let result = null;

  if (isRock) {
    result = condition.rock[enemy];
  } else if (isPaper) {
    result = condition.paper[enemy];
  } else if (isScissors) {
    result = condition.scissors[enemy];
  }

  return result === -1 ? "You loose!" : result === 1 ? "You win!" : result === 0 ? "Draw!" : null;
}

this.setState({
  result: getResult(this.state)
});