JavaScriptの学習中に、論理演算の課題に取り組んだ際に「または」の表現で悩んだので備忘録も兼ねてまとめます。
具体的には値について「または」を使いたい場合の考え方です。
以下の記事を参考にさせていただきました。
https://wp-p.info/tpl_rep.php?cat=js-application&fl=r6
https://wp-p.info/tpl_rep.php?cat=js-biginner&fl=r19
#課題内容
ジャンケンで、自分が出したい手(user_hand)をpromptに入力し、
- グー・チョキ・パーが入力された際にはランダムに生成したJavaScript側の手(js_hand)との勝敗を出力
- グー・チョキ・パー以外の文字列が入力されたときは、「グー・チョキ・パーのいずれかを入力してください」とアラートを出し、もう一度入力させる。
- キャンセルボタンが押されたときは「またチャレンジしてね」を出力
別途、JavaScript側の手のランダム生成はgetJShand、勝敗の判定・出力はjudgeという関数を組んでいます。
#困ったこと
上記の条件2を記述する際に、「そういえばまたはの時には||が使えるんだったな」と思い出し以下の様に書いてみました。
var js_hand = getJShand();
//ループ処理の判定用。終わるときはflagを1にしてwhileループから抜ける。
var flag = 0;
while(flag == 0) {
var user_hand = prompt('ジャンケンの手をグー、チョキ、パーから選んでください。');
if(user_hand == null) {
alert("またチャレンジしてね");
flag = 1;
}else if(user_hand != "グー" || "チョキ" || "パー") {
alert("グー・チョキ・パーのいずれかを入力してください。");
}else{
var judge = winLose(user_hand, js_hand);
alert('あなたの選んだ手は' + user_hand + 'です。\nJavaScriptの選んだ手は' + js_hand + 'です。\n結果は' + judge + 'です。');
flag = 1;
}
}
・・・ご存知の方は「これはまずい書き方だ」と一瞬で気付かれるかと思いますが、これでは上手くいきませんでした。
具体的には、グー、チョキ、パーが入力されても「グー・チョキ・パーのいずれかを入力してください」とアラートが出て、もう一度入力を求めてきます。
つまり、上記の表記では文字を入力した場合はelse ifの箇所で必ずtrueが返ってしまっているということです。
#原因
上記の記事をごらんいただければ原因は記載されていますが、こちらでもまとめておきます。
原因は文字列(正確には特定の値)はtrueとして評価されてしまうことです。(上記2つ目の記事参照)
また、上記の1つ目の記事にもある通り、JavaScriptの||は他の言語と違った処理がなされます。
以下引用させていただきます。
つまり、『||』の場合は左側の式の評価が『true』扱いされるのであれば左側の式の評価結果が、左側の式の評価が『false』扱いされるのであれば全体の評価が『true』扱いになろうとも『false』扱いになろうとも常に右側の式の評価結果が返って来ます。
と言うことで、上記の記法では以下の様なことが起こっています。
- 入力した文字が「グー以外」だった場合
一番左のuser_hand != "グー"
がtrue
になるので、true確定。 - 入力した文字が「グー」だった場合
一番左のuser_hand != "グー"
はfalse
扱いになるので右側の式へ
→ 文字列"パー"はtrue
として評価されるのでtrue確定
となり、(特定の)値を入力した場合は全て最終的にtrueとなります。
ただ単に解決するのであれば、横着せずに||の左右全てを条件式にしてあげればOKです。
}else if(user_hand != "グー" || user_hand !="チョキ" || user_hand !="パー") {
alert("グー・チョキ・パーのいずれかを入力してください。");
#それでも横着がしたくて
さて、ようやく本題です。
今回の場合はジャンケンなので3パターンしかなくuser_hand != をそれぞれに書くのもそれほどの手間ではないのですが、より多くのことについて同様の記述をする際にはその手間も膨大になります。
なのでなんとか値について「または」を使う方法はないかと考えたところ、配列を活用する方法を思いつきました。
以下の通りです。
var js_hand = getJShand();
const hands = ["グー", "チョキ", "パー"]; //これに含まれているかどうかで判断
var flag = 0;
while(flag == 0) {
var user_hand = prompt('ジャンケンの手をグー、チョキ、パーから選んでください。');
if(user_hand == null) {
alert("またチャレンジしてね");
flag = 1;
}else if(!hands.includes(user_hand)) { //!を頭につけてuser_handがhandsに含まれて「いなければ」に変換
alert("グー・チョキ・パーのいずれかを入力してください。");
}else{
var judge = winLose(user_hand, js_hand);
alert('あなたの選んだ手は' + user_hand + 'です。\nJavaScriptの選んだ手は' + js_hand + 'です。\n結果は' + judge + 'です。');
flag = 1;
}
}
これで上手く行きました。(上記の通り、後の追加に対応するならpromptの中身の'ジャンケンの手をグー、チョキ、パーから選んでください。'
のグー、チョキ、パーの部分も配列から取れる様にした方が良いですね。)
#あとがき
詳しく調べてはいないので分かりませんが、上記の配列を使う、という方法はjavascriptに限らず他の言語でも使えるかも知れないので、他の言語で論理演算する場合はまず試してみようと思います。
また、横着したい、と言う気持ちが工夫を生み出すと思うので、プログラミングに関してはめんどくさがりの姿勢を今後も貫いていきたいです。
p.s.
自分は前職教育系の仕事をしていたので、数学でも横着な子の方が成長早かったなぁと思い出したりしました。
数学とプログラミングってなんだかんだ必要な考え方が似てるところ多いな、と思います。