javascriptの論理演算子&&は、左辺が偽であれば右辺を評価せず、||は、左辺が真であれば右辺を評価しません。
これを遅延評価と呼ぶそうですが、遅延という単語で思い浮かぶのは、「遅れる」こと「長引かせる」ことです。
全くつながりが見出せませんが、何が遅延しているから右辺を評価しないのでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答6件
14
プログラミングの世界には評価戦略という概念があります。&&
や||
で言われている「遅延」と言う言葉は評価戦略での遅延評価のことを言っています。ただし、&&
や||
は遅延評価の中でも特殊なパターンと位置づけて、短絡評価と言う場合の方が多いです。
遅延評価の反対は正格評価です。評価戦略はこの二つの何れかにわかれます。そう、正格評価に対して、何かが遅れる(遅延する)から遅延評価と呼ばれるのです。ですので、まずは正格評価とは何かと言うことを理解する必要があります。
与えられた引数を単純に足すplus
関数があるとして、次のような式を考えます。
JavaScript
1var plus = function(a, b) { return a + b; }; 2plus(1 + 2, 3 * 4);
ほとんどのプログラミング言語では、0個以上の式を引数として、関数を呼び出し、一つの式になります。さて、この式について、関数を評価する前に、引数として割り当てられている各式を評価する必要はありますでしょうか?上の例では、plus
を評価する前に1 + 2
や3 * 4
を評価し、その結果を求める必要があるかどうかと言うことです。普通はあると答えることでしょう。何を当たり前な事を…と思ったかも知れませんが、一見、この当たり前な評価の仕方を正格評価といいます。つまり、正格評価とは、ある関数の式について、その引数にあたる式全てを評価した後に関数自体を評価することです。
実は、上のことは全てのプログラミング言語においてそうであるとは言えません。例えば、Haskellの場合、
Haskell
1plus a b = a + b 2plus (1 + 2) (3 * 4)
上の式では、始めにplus
自体が評価されて、+
の演算であると解釈されます。1 + 2
や3 * 4
が評価されるのはその後です。何言っているの?と思っているかも知れません。例えば下記のような式では、
Haskell
1plus' _ _ = 1 2plus' (1 + 2) (3 * 4)
これも同じくplus'
が始めに評価されます。そして、そこで値は1
と確定してしまいます。つまり、この式では1 + 2
や3 * 4
が評価されることはありません。このように、引数が遅れて評価される(場合によっては評価すらされない)ため、遅延評価と言われます。つまり、遅延評価とは、正格評価の反対で、その引数にあたる式の一部、または、全てを評価せずに関数自体を評価することです。
なんとなくわかってきました?さて、関数の話でしたが、演算子も一種の関数と引数の組み合わせと捉えることができます。
JavaScript
1(+)(1 + 2, 3 * 4);
JavaScriptでは上のように書けませんが、Lispなどでは(+ (+ 1 2) (* 3 4))
と書いたりします。そう、同じ事です。演算子であっても、左辺と右辺は二つの引数と考えられます。正格評価であれば、それらは演算子の評価の前に、それぞれの式は評価されます。実際に足し算が行われるのはその後です。
ですが、&&
と||
だけはその正格評価の規則に従いません。
JavaScript
1(||)(1 + 2, 3 * 4);
引き続き架空の書き方ですが、本来の関数と考えれば、両方の式が評価された後に、||
の処理があると考えるべきです。ですが、JavaScriptの&&
と||
は例外的に遅延評価の一種である短絡評価を採用しています。1番目の式(つまり左辺)を評価した後に、&&
や||
での処理を行い、その後に2番目の式(つまり右辺)が評価されます。しかも、1番目の式の結果次第では、&&
や||
での処理によって、2番目の式(つまり右辺)は評価されない場合があります。どうしても右辺の式は&&
や||
自体の処理(評価)よりも評価することが遅れるため、他にあるような正格評価と比べて評価するタイミングが遅延しているとなるのです。
JavaScirptで他に遅延評価になるのは三項条件演算子(?:
)だけです。まとめると、**演算子自体の評価よりも、中にある式の評価が遅れる(場合によっては評価されない)**というころが遅延評価と言われるゆえんとなります。
※ 遅延評価に興味があれば、Haskellなど遅延評価のある言語を学ぶと良いでしょう。
※ &&
や||
、または、同様の意味を持つand
やor
が短絡評価であるかどうかは言語によります。これらが短絡評価ではない言語も存在します。
投稿2016/07/21 14:01
編集2016/07/21 15:39総合スコア21741
5
ベストアンサー
比較のために、JavaScriptで関数を呼び出してみましょう。
javascript
1function and_and(cond1, cond2){ 2 return cond1 && cond2; 3} 4 5var x = func(1) && func(2); 6var y = and_and(func(1), func(2));
ここで、y
を計算するときの関数呼び出しでは、たとえ関数の中で使おうが使うまいが、引数はすべて評価してから関数を呼び出すことになります。
その一方で、x
を計算する際には、
func(1)
を評価する。- 1.の値が真なら、
func(2)
評価する
という流れになっています。つまり、必要かどうかがわかるまで、func(2)
の評価は遅延されています。
投稿2016/07/21 11:13
総合スコア146544
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

1
参考情報
...
通常、関数の引数は関数に渡されるときに計算されるが、遅延評価では関数に渡した後、実際に計算が必要になるまで評価されない。無限リストがこの利点を説明するためによく引き合いに出される。無限リストを評価するということは、無限リストの「全ての」要素を計算するということであるが、これは当然無限個の処理が終わるはずはないのでエラーになる。しかし、遅延評価では、無限リストは定義されたり、関数に渡されたりした時にはエラーにならず、関数内で請求された要素の値を返して特に問題なく動作する。
...
- ECMAScript 6 でジェネレータを作ったり、遅延評価してみる https://blog.ymyzk.com/2015/04/ecmascript-6-generator-lazy/
投稿2016/07/21 23:27
総合スコア22328
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
1
||の本来の意味、論理ORに従うと
左辺右辺共に評価し、片方、もしくは両方が真である場合に真を返すべきです。
しかし、左辺が真になった時点で結果は間違いなく真になるので
右辺は計算する必要がありません。
その際に右辺を評価しないことが遅延でなく
左辺を評価し、右辺の評価が必要になるまで評価を留めるため、遅延ということになります。
偽になった際に右辺を評価しないというのはどちらかというと副作用のようなものです。
&&に関しても同様です。
投稿2016/07/21 11:12
編集2016/07/21 11:15総合スコア53
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/22 00:55 編集
2016/07/22 12:30

0
たとえば
Javascript
1<script> 2if(typeof myvar=="undefined" || myvar == 0){ 3 console.log("error"); 4}else{ 5 console.log("ok"); 6} 7</script>
変数myvarが未設定(もしくは設定したけど削除された)かどうかわからない時
if(myvar==0)的な処理を行うとundefinedなものを評価することになるので
そこでプログラムが止まってしまいます。
myvarを評価する前に、typeofでmyvarがundefinedを評価し、未設定であれば
myvarを評価しない必要があります。
投稿2016/07/21 12:19
総合スコア117652
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/22 05:21
2016/07/22 09:42
2016/07/22 11:29
2016/07/22 12:03
2016/07/22 15:11 編集
2016/07/22 17:23
2016/07/23 04:11
2016/07/23 06:37
2016/07/24 00:53