入門書には載ってないJavaScriptの小技を紹介!
検索ワードに悩んでない?
プログラミングを初めて1、2年ぐらいだと、他の人が書いたコードでわからない箇所があったりしますよね。 「Google先生に聞きたいけど、名前わからへんぞ」 「検索ワードどないしょ・・・」 みたいな。
本記事では、そういった入門書には載っていないJavaScriptの書き方を紹介していきます。
三項演算子
三項演算子は、if文のショートカットとしてよく使われます。 恐らく、下記の例のように使われているのをみたことがあるんではないでしょうか。
var flag = true; var hoge = flag ? 'true-dayo' : 'false-dayo'; // true-dayo が代入される
三項演算子は、 条件式 ? 真式 : 偽式; という形式で記述します。 if文に書き換えた形をみるとわかりやすいかと思います。
var hoge, flag = true; if (flag) { hoge = 'true-dayo'; } else { hoge = 'false-dayo'; }
こうやってみると、三項演算子がなにをしているか一目瞭然ですね。 「三項演算子は一行で書けるのがスマートなんやな!」とすぐに理解しちゃいましたね?
そう!確かにそれはそう! それはそうなんですけど、三項演算子の魅力は値を返すという点なんですよ。
三項演算子は評価結果の値を返す
一行で書くというだけなら、if文のように、真式・偽式の中で代入するように書くということでもいいわけですよ。
var hoge, flag = true; flag ? hoge = 'true-dayo' : hoge = 'false-dayo';
ちょっと待ってください。 これは・・・。よくみてみると・・・。 「いや、もうそれ、if文を一行で書けばええやん」ってなりますよね?
var hoge, flag = true; if (flag) { hoge = 'true-dayo' } else { hoge = 'false-dayo'};
しかし、この書き方では、ただ可読性を下げただけになってしまいます。
そこで、初めの例にあったように、「三項演算子が返す値を代入する」、という形で書くことで、三項演算子が値を返すという性質を生かせるようになります。
var flag = true; var hoge = flag ? 'true-dayo' : 'false-dayo';
非常に当たり前のことを言ってしまいますが、三項演算子って名前に演算子ってついてますよね? 「演算子だから値を返してなんぼ」、という存在なんです。
ブラケット記法で三項演算子を使う
三項演算子を演算子らしく使う方法の一例として、ブラケット記法でメソッド切り替えをする方法を紹介します。
jQueryのメソッドを例に説明していきますね。
jQueryのshowメソッドをドット記法とブラケット記法で書くと下記のようになります。
$('.hoge').show(); // ドット記法 $('.hoge')['show'](); // ブラケット記法
よく、ブラケット記法はメソッド名を変数で可変にできると説明されます。
var methodName = 'show'; $('.hoge')[methodName]();
変数で可変にできるんだったら、三項演算子が返す値をメソッド名に使えないわけがありません。
var flag = true; $('.hoge')[flag ? 'show' : 'hide'](); // showメソッドが実行される
なんということでしょう。 一行でshowメソッドとhideメソッドの切り替えができています。
これをif文で書いた場合は下記のようになります。 三項演算子と比べると冗長に感じてしまいますね。
var flag = true; if (flag) { $('.hoge').show(); } else { $('.hoge').hide(); }
短絡評価(ショートサーキット)
変数の初期化処理などで、以下のような書き方をみたことがあるかと思います。
var hoge = undefined; var fuga = hoge || {}; // {} が代入される
これは、短絡評価という論理演算子の評価方法を利用した方法です。 if文の条件式で、左辺の式 論理演算子 右辺の式 という風に書きますよね? あれをif文の条件式としてではなく、代入演算子と組み合わせて使っています。
上記のコードで期待する挙動は、if文で書き換えてみると分かりやすいかと思います。
var hoge = undefined; if (hoge) { var fuga = hoge; } else { var fuga = {}; }
論理演算子も演算子なので、値を返しているということを理解していると、短絡評価の仕組みが分かりやすくなります。
短絡評価の処理の流れ
論理演算子には、論理AND演算子(&&)と論理OR演算子(||)があります。 JavaScriptの短絡評価は、最後に評価した式の値を返します。 最後に、ということは、短絡評価は場合によっては左辺の式までしか評価しない場合があるということです。 短絡評価の処理の流れを確認しましょう。
左辺が真 | 左辺が偽 | |
---|---|---|
論理AND演算子 | 右辺を評価する | 右辺を評価しない |
論理OR演算子 | 右辺を評価しない | 右辺を評価する |
true && '評価されるよ'; // 右辺の式を実行する false && '評価されないよ'; // 右辺の式を実行しない true || '評価されないよ'; // 右辺の式を実行しない false || '評価されるよ'; // 右辺の式を実行する
論理AND演算子の処理の流れ
左辺の式が真の場合、評価が未確定のため、右辺の式を実行する。 左辺の式が偽の場合、評価が偽であると確定しているため、右辺の式を実行しない。
論理OR演算子の処理の流れ
左辺の式が真の場合、評価が真であると確定しているため、右辺の式を実行しない。 左辺の式が偽の場合、評価が未確定のため、右辺の式を実行する。
短絡評価は最後に評価した値を返す
前述しましたが、JavaScriptの短絡評価は最後に評価した値を返します。 返される値は、必ずしもBoolean型ではありません。 というよりも、そのままの値が返ってきます。
Javaのような型付けが強い言語を使う人からすると、違和感があるかもしれませんが、これがJavaScriptのゆるふわ可愛い仕様というヤツです。
こういった仕組みを理解すると、初めの例のコードの流れが理解できます。
var hoge = undefined; var fuga = hoge || {}; // {} が代入される
左辺の変数hogeが偽と評価されるため、右辺の式が実行され、結果として空のオブジェクトが返された、というわけです。
短絡評価で関数を実行する
短絡評価は、式を実行した結果、値を返しているわけですが、式を実行するということは関数を使えるということを意味します。 そのため、値が返ってくることを期待しないで、「条件式がtrueの時だけ関数を実行する」ということにも利用ができます。
var flag = true; flag && alert('実行されるよ'); flag = false; flag && alert('実行されないよ');
個人的には「値が返ってくることを期待しないのであれば、if文で扱うべきでは?」と思わないでもないのですが、こういう書き方ができるというのは面白いですよね。
Booleanへの変換
JavaScriptは、null, undefined, NaN, 空文字をFalsy(偽とみなされる値)であると判定し、それ以外をTruthy(真とみなされる値)と判定します。
ある場面において、 「関数の戻り値を真偽値にしたい」 「条件式の値を真偽値にしたい」 ということが、ままあります。
要は、値をBoolean型に変換したいということです。 JavaScriptにはBoolean関数があるので、これで変換することができます。
Boolean(1); // true Boolean(0); // false Boolean("hoge"); // true Boolean(""); // false
論理NOT演算子で型変換
Boolean関数を使うというのは悪くはないのですが、もっと記述量を少なくする方法が、論理NOT演算子(!)を使う方法です。 論理NOT演算子は、if文の条件式で値の真偽を反転させる方法としてよく使われます。
var flag = false; if (!flag) { // true として扱われる }
論理NOT演算子の注目すべき働きは、返す値がBoolean型に変換されるという点です。 論理NOT演算子は、Truthyな値はfalseを返し、Falsyな値はtrueを返します。
!1; // false !0; // true !"hoge"; // false !""; // true
この性質を利用して、論理NOT演算子を2つ付けると、真偽値の反転が2回行われることになり、結果としてBoolean型への変換を行ったことになります。
!!1; // true !!0; // false !!"hoge"; // true !!""; // false
どうですか?Boolean関数を使うよりも、簡単に型変換ができますよね? 見比べてみると、どちらがより気軽に型変換ができるか、一目瞭然ですね。
Boolean(1); // true !!1; // true