React(TypeScript)、「!」とか「?」とか「&」とか記号多すぎて訳わからんのだが!!
というところからこの記事を書くに至りました。
記号ってただでさえググりづらいし、TS/JS関連だとOptional Chainingとか、Nullish Coalescingとか名前もいちいち覚えづらい…
ので自分用のメモとしても残しておきたいな、と。
-
対象読者
-
ReactとかTypeScript/JavaScriptを触り始めた人
-
業務で上記言語のソースコード読むのに苦労してる人
-
いちいち演算子/記号ググるのだるい人
-
記事の内容
-
||演算子と&&演算子の短絡評価
-
&&演算子
-
!(非nullアサーション演算子)
-
?. (Optional Chaining)
-
三項演算子
-
== と=== (等価演算子)
etc…
初心者ゆえにざっくりとした理解に重きを置いてますので悪しからず。。
1. ||演算子と&&演算子の短絡評価 (ショートサーキット評価)
AND演算子(&&)、OR演算子(||)自体はどの言語でもあるかと思いますが、
Reactだとこれらの短絡評価をよく見かけます。(で、これが正直読みづらい…)
ナウい書き方らしいので頑張りましょう。
短絡評価(ショートサーキット評価)とは
左辺を評価した時点で結果が確定した時は、右辺が評価されない
という特性のこと。
以下で||演算子と、 &&演算子でそれぞれ見てみる。
###① ||演算子 (OR) の場合
論理演算子||の左側がtrueであれば左側の値、そうでなけれな右側を返す。
(反対に、左側がfalseなら右側を返す)
簡潔に書くと
左辺がtrue/truthyなら左辺を返す
左辺がfalse/falsyなら右辺を返す
(左辺がfalseだったら、右辺も見にいくみたいな感覚でいます。)
ややこしいのが、ショートサーキット評価では、bool値以外の値(普通の文字列とか数値とか)である場合は、暗黙に型変換して評価している、ということ。
(値がtruthy/falsyか、という評価観点)
例えば…数値だと0がfalsy、文字列だと””空文字がfalsyとして評価されます。
つまり、 falsy として定義された値 (つまり、false, 0, -0, 0n, “”, null, undefined, NaN)はfalse判定、それ以外は全てture判定。
実際の処理を見るとなんとなく分かってくる…かもしれません。
10 || false; // 10
10 || true; // 10
10 || 20; // 10
false || 20; // 20
0 || "zero"; // "zero" 「0」はfalsyなので、"zero"を返す
"Cat" || "Dog"; // "Cat"
"Cat" || false; // "Cat"
false || "Cat"; // "Cat"
"" || "Cat"; // "Cat" 「""」はfalsyなので、"Cat"を返す
なるほど、だんだん分かってきた気がする。
これを活用すると、条件分岐のif/elseを省略して書くことができて、実務だと下記のような使われ方をしてます。
(後ほど書く??演算子も同様)
// 変数「name」の値がtruthyなら「name」, そうでなければ文字列'名無し'が変数userに代入される
// 条件分岐省略前(if文形式)
let user;
if (name) {
user = name;
} else{
user = '名無し';
}
// 条件分岐省略後(短絡評価)
let user = name || '名無し'; //「name」が存在する(truthy)なら「name」を、なければ'名無し'を代入
・参考
Truthy - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
JavaScript 論理演算子OR「||」の特殊な用法 | プログラミングアカデミー ゼロプラスワン
② &&演算子 (AND) の場合
A AND B
という論理式があったとして、
Aがfalseの時点で式全体の結果はfalseで確定するので、Bがどうであるかについてはチェックしない
というのがショートサーキット評価の考え方です。
簡潔に書くと、
左辺がtrue/truthyなら右辺を返す
左辺がfalse/falsyなら左辺を返す
(左辺がtrueだったら、右辺に行ける、みたいな感覚ですね。)
true && true; // true
true && false; // false
false && true; // false
"Cat" && "Dog"; // "Dog" "Cat"はtrutyだから左辺を返す
false && "Cat"; // false
"Cat" && false; // false
"" && "Cat"; // "" 「""(空文字)」はfalsyだから左辺を返す
0 && 10; // 0 「0」はfalsyだから左辺を返す
Reactでは結構下記のような感じで使われてます。
list && list.forEach(item) => {処理}
listがfalsyだったらReactは描画せず、trutyだったら処理を行って描画する、といった感じでしょうか。
可読性の観点で下記記事では見事にクソコードと罵られていますが、、笑
JavaScript 論理演算子AND「&&」の特殊な用法(Reactでよく見る記法) | プログラミングアカデミー ゼロプラスワン
||演算子と&&演算子まとめ
とりあえず、
||演算子は左辺がfalseだったら右辺を見に行く(返す)!
&&演算子は左辺がtrueだったら右辺を見に行く(返す)!
というのが重要になりそうです。
・参考
JavaScriptの「&&」「||」について盛大に勘違いをしていた件 - Qiita
2. ??演算子 ~ Null合体演算子 / Nullish Coalescing ~
左辺が 「nullishな値の時だけ」、右辺が評価される 。
(上記のOR演算子|| と似てるけどちょっと違う。)
違いを明確に…
• ??演算子:左辺がnullish(=nullまたはundefined)のときだけ、右辺が評価
• || 演算子:左辺がfalsy(false, 0, -0, 0n, “”, null, undefined, NaN)のときに、右辺が評価
console.log(0 || 1); // 1
console.log(0 ?? 1); // 0
console.log('' || '空文字'); // 空文字
console.log('' ?? '空文字'); // (何も表示されない)
要は、??演算子の方がより厳密に undefined や null を判定してくれるものと覚えておけば良さそう。
3. 「?.」でアクセス ~ Optional Chaining ~
obj?.foo
Rubyのぼっち演算子的な役割。(やったぜ)
プロパティのアクセス先が「nullishな値(null または undefined)」の場合、
通常の.
でアクセスすると落ちるが、?.
だとundefinedが返るので回避できる。
?.
でプロパティアクセスしていって、上記の??演算子
と組み合わせると、nullishだったら、〜〜(処理)みたいに書けて便利らしい。
・参考
そろそろJavaScriptに採用されそうなOptional Chainingを今さら徹底解説 - Qiita
4. プロパティ/変数アクセスの「!」 ~ 非nullアサーション演算子/ Non-null assertion operator ~
item.color!.toUpperCase()
ここでのcolor!
みたいなやつです。
!
をつけることで、対象プロパティ/変数がnon-nullであるということをコンパイラに明示するもの。
…要は、『こいつは絶対に null も undefined も入らないよ!』とコンパイラを強引に黙らせ、コンパイルエラーを回避します。
最初これをぼっち演算子(&.)と似たものと思ったのですが、これはあくまでコンパイラを黙らせるだけで、実際にNullがきたら落ちるので注意。
(ちなみに『りあクト!』では極力使うな、と書いてありましたが、現PJでは結構見かける。。)
・参考
TypeScriptのコードレビューを依頼された人のための!と?の解説 | Developers.IO
strictNullChecks - TypeScript Deep Dive 日本語版
5. 条件演算子 (三項演算子)
If~else文の省略バージョン。
普通にRubyでも書けるけど、なぜかRailsのPJより多く使ってる印象。
// 変数 = 条件式 ? trueの時の値/処理 : falseの時の値/処理;
let age = 28
let value = (age >= 30) ? "over thirty" : "under thirty"
6. 「==」 と 「===」 ~ 等価演算子と厳密等価演算子 ~
① 「==」 等価演算子
ご存知の通り、「A == B」でAとBが等しいかどうか、という意味ですが、
等価演算子では暗黙な型変換が行われます。
1 == "1" // true 文字列を数値に変換後、比較
true == 1 // true 真偽値を数値に変換後、比較
"" == 0 // true 文字列を数値に変換後、比較
null == undefined // true
等価演算子は両辺の型を解釈し、異なる型の場合に同じ型に変換をしてくれる。
② 「===」 厳密等価演算子
そして厳密等価演算子はと言うと、型も含めて厳密に比較します。
1 == "1" // false
true == 1 // false
"" == 0 // false
null == undefined // false
名前通り、===のほうが厳密に比較してくれるってことですね。
7. if(hoge) ~ 比較演算子の無いif文 ~
if(hoge) {処理}
という具合で、条件式が無いif文を結構見かけて、最初驚きました。
これ自体は記事に載せるかちょっと迷ったものの、これもtruthy/falsy絡みでもあるので。
if(hoge)
のとき
→ hogeがfalsyな値(null, undefined, 0, 空文字(''), false)以外の時
は、true判定
要はちゃんと値があればtrue判定
if(!hoge)
のとき
→ hogeがfalsyな値(null, undefined, 0, 空文字(''), false)の時
はtrue判定
簡潔に言うと「存在チェック」、という認識。
8. 「|」 (パイプライン一本) ~ ユニオン型 ~
これはユニオン型(union type)を定義するときに使うもの。
|
で並べることで、複合的な型を定義できる。
// idは数値でも文字列でもOK
let id: number | string
// nullも許すstring型
type nullableString = string | null;
TypeScriptのはなし : ユニオン型がけっこうイイね - 檜山正幸のキマイラ飼育記 (はてなBlog)
以上です。
あくまで初心者による初心者向けの内容なので、より深い知識をお求めの際は参考記事等々読んでくださいませ。
そもそも理解間違ってる、という部分あればなんなりとご指摘ください!