論理演算子の &&
、||
、!
は、論理演算を行います。2つの関係演算式を組み合わせて複雑な式を作成するのに使われます。これらの演算子については、これから項を分けて説明していきます。この論理演算子を完全に理解したなら、「論理値」で紹介した「 true
と評価されるもの」と「 false
と評価されるもの」という概念について見直してみてもよいでしょう。
&&
) &&
演算子を理解するには、3つのレベルがあります。最も単純なレベルでは、論理積演算子( &&
)は、前のオペランドと後ろのオペランドの両方が true
の場合に true
になる、という理解です。オペランドの一方もしくは両方が false
であれば、結果も false
になります。
&&
は、2つの関係式を組み合わせるときによく使われます。例を示します。
x == 0 && y == 0
// x と y の両方が 0 のときのみ true になる。
関係式は常に true
または false
になるので、このような使い方をすると、&&
演算子自身も true
または false
を返します。関係演算子は、&&
や ||
よりも優先順位が高いので、先ほどの式に括弧を記述する必要はありません。
しかしながら、&&
のオペランドは論理値以外であっても問題ありません。JavaScript では、すべての値は「 true
に評価される」か「 false
に評価される」ものです(詳しくは「論理値」を参照してください。「 false
に評価されるもの」は、false
と null
、undefined
、0
、-0
、NaN
、""
です。ほかの値は、すべてのオブジェクトも含めて、true
に評価されます)。
&&
の次のレベルは、true
に評価されるものと、false
に評価されるものに対する論理積演算子だ、という理解です。両方のオペランドが true
に評価されるものであれば、この演算子は true
に評価されるものを返します。それ以外の場合、つまり、どちらか、または両方のオペランドが false
に評価されるものであれば、この演算子は false
に評価されるものを返します。JavaScript では、論理値が必要な式や文であれば、true
に評価される値や、false
に評価される値に対しても問題なく動作しますので、&&
演算子が true
や false
以外の値を返したとしても、特に問題が生じたりはしません。
先ほどの説明で、&&
演算子が「 true
に評価される値」や「 false
に評価される値」を返すと説明しましたが、実際にどういう値が返されるのかは明らかにしていません。この点を理解したら、&&
演算子については免許皆伝です。&&
演算子は、左側の式をまず評価します。左側の式の値が false
に評価される値の場合は、式全体の値も false
に評価される値になります。そこで、&&
演算子は単純に、左側の式の値だけを返します。右側の式については評価すらしません。
逆に、左側の式の値が true
に評価される値の場合、式全体の値は右側の式の値に依存します。右側の式が true
に評価される値であれば、式全体の値は true
に評価される値になります。逆に、右側の式が false
に評価される値であれば、式全体の値は false
に評価される値になります。したがって、左側の式の値が true
に評価される値であれば、&&
演算子は右側の式を評価し、この値を返します。次に例を示します。
var o = { x : 1 };
var p = null;
o && o.x
// => 1: o は true と評価されるので、戻り値は o.x になる。
p && p.x
// => null: p は false と評価されるので、それを返す。p.x は評価されない。
&&
演算子が、右側のオペランドをどのような場合に評価して、どのような場合に評価しないのかを理解しておくことは重要です。前述したコードでは、変数 p
に null
が設定されているので、p.x
という式が評価されてしまうと、TypeError が発生します。しかし、このコードでは、&&
をうまく使うことで、p
が null
や undefined
ではなく、true
に評価される場合にのみ、p.x
が評価されるようにしています。
&&
のこの振る舞いは、短縮表記と呼ばれることがあります。この振る舞いを意図的に使って、条件付きで実行するようなコードを見かけることと思います。例えば、次のコードを見てください。
if (a == b) stop();
// a==b の場合のみ stop() を呼び出す。
(a == b) && stop();
// 上の文と同じ処理。
一般的に、&&
の右側で、副作用(代入、インクリメント、デクリメント、関数呼び出し)を持つような式を記述するときは注意が必要です。これらの副作用が生じるかどうかは、左側の値によるからです。
このように論理積演算子( &&
)の振る舞いは少し複雑ですが、普通は単純に論理演算のためだけに使用します。
論理和演算子( ||
)は、オペランドの一方または両方が true
に変換される値の場合は、true
に変換できる値を返します。これ以外の場合、すなわち両方のオペランドが false
に変換される場合は、false
を返します。
論理和演算子( ||
)を単なる論理 OR 演算子のつもりで使用する人が多いのですが、論理積演算子( &&
)と同じように複雑な振る舞いをするので注意が必要です。まず、演算子( ||
)の左側のオペランド(式)を評価します。この式の値が true
に変換できる場合は、左側の式の値をそのまま変換せずに返します。
論理和演算子を使った以下のような慣用句がよく使われます。このような慣用句は、使用する値にいくつか候補があり、その候補の中から定義されていて null
ではない値(つまりは true
に評価される値)を使いたい場合に使用します。
// max_width 変数が定義されている場合は、この変数の値を使用する。定義されていない
// 場合は、preferences オブジェクトのプロパティを使用する。このプロパティも定義
// されていない場合は、プログラムに直接記述した定数( 500 )を使用する。
var max = max_width || preferences.max_width || 500;
この慣用句は、引数のデフォルト値を指定するために、関数本体中でよく使われます。
// o のプロパティを p にコピーして、p を返す。
function copy(o, p){
p = p || {};
// p にオブジェクトが渡されない場合、新たにオブジェクトを生成する。
// ここに関数を記述する。
}
論理否定演算子( !
)は単項演算子です。オペランドは 1つしかありません。!
をオペランドの前に置くと、そのオペランドの論理値を反転させます。例えば、変数 x の値が true
と評価される値であれば、!x
は false
になります。x が false
と評価される値であれば、!x
は true
になります。
&&
演算子や !!
演算子とは異なり、論理否定演算子( !
)は、「 型、値、変数 」で紹介した規則を使ってオペランドを論理値に変換した後、論理を反転させます。つまり、!
演算子が返す値は、true
か false
だけです。したがって、変数 x
に対して、!!x
のように 2つの論理否定演算子を前置すると、x
に格納された任意の型の値を、対応する論理値に変換することができます(「型の変換」を参照)。
単項演算子として、!
演算子は高い優先順位を持ちます。したがって、p && q
のような式の値を反転したい場合は、括弧を使って、!(p && q)
のように記述しなければなりません。なお、ここで論理学の 2つの定理を JavaScript の文法で記述しておきます。
// 任意の p と q の値に対して、以下の 2つの等号が成り立ちます。
!(p && q) === !p || !q
!(p || q) === !p && !q