JavaScriptの変数、値、式、演算あたりを纏めました。
まだまだあると思いますが、とりあえず殴り書き。次回の記事では関数について纏めます。
変数と値
変数の宣言
var a;
let b;
const c;
このステートメントによってメモリ上にa,b,cという名前のついた領域が生成されます。
ここで「var」「let」「const」は変数を宣言するための宣言子と言います。
変数を宣言しただけの状態では、undefinedという値が入っています。
var a;
console.log(a); // undefined
変数にはイコール演算子を利用して値を代入できます。
宣言と同時に値を代入することもできます。(初期値の設定)
var a;
a = 2;
var b = 2;
複数の変数の宣言と初期値の設定をカンマ区切り(,)で記述することもできます。
var a =1, b = 2, c = 3;
変数宣言の省略
console.log(x); // これはエラーとなる
宣言されていない変数を読み出そうとすると参照エラーとなります。
しかし、これはエラーになりません。
a =1;
console.log(a) // 1
宣言しないで変数の値を代入すると、自動でグローバル変数として宣言されるからです。
これはグローバルスコープの汚染となるのでNG。
変数のスコープの編で詳しく説明します。
変数宣言の巻き上げ
JavaScriptは基本的にシングルスレッドであり、一つの処理が完了するまで次の処理が実行されないようになっています。
console.log(x);
var x;
最初の行は一見すると、変数xが宣言される前に読み出そうとしているのでエラーとなりそうですが、エラーとはなりません。
これは、変数宣言がプログラムの途中で行われても、あたかも先頭で先頭されたかのように
先立って生成されるからです。これを変数宣言の巻き上げ(ホイスティング)と言います。
ただし、初期化の部分は巻き上げられません。実際はこうなる。
console.log(x); // undefined
var x = "Hello";
console.log(x); // "Hello"
データ型
データの種類はプリミティブ型とオブジェクト型の2種類あります。
プリミティブ型 → 数値、文字列、論理値、null、undefined、シンボル
オブジェクト型 → プリミティブ型以外の全て
変数のスコープ
JavaScriptはプログラムの構文のみでスコープが決まります。(レキシカルスコープ)
スコープにはグローバルスコープとローカルスコープがあります。
グローバルスコープは関数の外側で宣言された変数です。有効範囲は全体です。
ローカルスコープは関数の中で宣言された変数です。有効範囲は宣言された関数内だけです。
var a = "global";
function hoge() {
var b = "local";
console.log(a); // "global"
return b
}
hoge();
console.log(b); // 参照エラー
変数が衝突したら、ローカル変数が有効となります。
なんでかは、スコープチェーンの説明をしないといけないのでここでは割愛します。
その辺(プロトタイプチェーンとかも)は別な記事で書きます。
今は、「より内側で宣言された変数を用いる」と覚えておいてください。
var a = "global";
function hoge() {
var a = "local";
console.log(a); // "local"
return a
}
hoge();
console.log(a); // "global"
式と演算子
a + b
// 「+」 → 演算子(オペレータ) 「a」「b」 → 被演算子(オペランド)
数値の演算
###算術二項演算子
演算子 | 意味 | 例 | 例の意味 |
---|---|---|---|
+ | 加算 | a + b | aとbを足した値 |
- | 減算 | a - b | aからbを引いた値 |
* | 乗算 | a * b | aとbをかけた値 |
/ | 除算 | a / b | aをbで割った値 |
% | 剰余算 | a % b | aをbで割った余りの値 |
+演算子はオペランドの一方が文字列の場合は、文字列の結合となる。
1 + 2 // 3
1 + "2" // "12" ←文字列
1 + "Hello" // "1Hello"
- 計算不能な場合はNaNとなる。
- 論理値のTrueは1、Falseは0に評価される。
- nullは0に評価される。
- undefinedはNaNとして評価される。
0 + 0 // NaN
1 * "2" // NaN
True + True // 2
1 + null // 1
1 + undefined // NaN
算術単項演算子
インクリメントはオペランドの値を1増やします。デクリメントはオペランドの値を1減らします。
演算子 | 意味 | 例 | 例の意味 |
---|---|---|---|
++ | インクリメント | ++a | aの値を1増やし、その後でaの値を評価する。 |
a++ | aの値を評価し、その後でaの値を1増やす | ||
-- | デクリメント | --a | aの値を1減らし、その後でaの値を評価する。 |
a-- | aの値を評価し、その後でaの値を1減らす |
算術代入演算子
代入演算子と算術二項演算子を組み合わせてショートカットです。
演算子 | 例 | 例の意味 |
---|---|---|
+= | a += b | a = a + b |
-= | a -= b | a = a - b |
*= | a *= b | a = a * b |
/= | a /= b | a = a / b |
%= | a %= b | a = a % b |
文字列の操作
文字列の連結は+演算子で行います。
"Hello " + "World!"; // "Hello World!"
"1" + "2"; // "12"
オペランドの一方が文字列または文字列に変換できるオブジェクトの場合は、一方のオペランドが文字列に変換されて結合されます。
10 + "str"; // "10str"
1 + {}; // "1[object Object]"
論理演算子と関係演算子
等価演算子(==)と同値演算子(===)
a == b // aとbが等しい時はtrue、それ以外はfalse
a === b // aとbの値が同一(型と値)が等しい時はtrue、それ以外はfalse
比べるデータがプリミティブ型かオブジェクト型で意味合いが異なリます。
プリミティブは値そのもの。オブジェクトの場合、値はオブジェクトへの参照。比べる時は参照先を比べます。
var a = [1,2,3,4,5];
var b = [1,2,3,4,5];
var c = a;
console.log(a == b); // false
console.log(a == c); // true
比較時の左右のオペランドの型が異なる場合は以下のように評価されます。
- undefinedとnullは等しい
- 一方が数値、もう一方が文字列の場合、文字列を数値に変換して比較
- 一方が論理値の場合、trueなら1に、falseなら0に変換して比較
- 一方がオブジェクトで、もう一方が数値か文字列の場合、オブジェクトをプリミティブ型に変換して比較
- 上記以外は全て「等しくない」
null == undefined // true
"1" == 1 // true
true == 1 // true
true == "1" // true
2 == [2] // true
同値演算子の場合は、型変換せずに評価するので型と値が両方等しい時に等しいと評価します。
ただしNaNは自分も含めすべての値と等しくないと評価されます。
NaN === NaN // false
先ほどの等価の例は同値ではすべてfalseとなります。
null === undefined // false
"1" === 1 // false
true === 1 // false
true === "1" // false
2 === [2] // false
論理演算子
&& → 論理積
|| → 論理和
! → 否定
a && b // aとbの両方がtrueの時はtrue、それ以外はfalse
a || b // aとbのいずれかがtrueの時はtrue、両方falseの時はfalse
!a // aがtrueの時はfalse、aがfalseの時はtrue
オペランドの評価
オペランドは論理値である必要はありません。論理値でない場合は、以下のように型変換されます。
0、-0、ブランク("")、NaN、null、undefinedはfalseに変換される。
0以外の数値、ブランク以外の文字列、オブジェクト、シンボルはtrueに変換される。
短絡評価
論理積と論理和は短絡評価を行います。
短絡評価とは、第一オペランドの値でその式の値が決まる時、第二のオペランドを評価しないこと。
また、評価後は論理値を返却するのではなく、最後に評価したオペランドの値を返します。
この特性を利用して以下のような使い方とかよく見ます。
var player = name || member.name || "Taro";
このステートメントの意味は、左から順にnameが定義されていればそれを利用。定義されていなければ、一つ右のmember.nameを利用。memberオブジェクトも定義されていなければ"Taro"を利用。です。
便利そうですが、falseと評価される値の場合は予期せぬ動きをするので注意。
以上。