第3章 基本文法

算術演算子

// 加算 (+)
let addition = 5 + 3;
console.log(addition);  // 8を出力

// 減算 (-)
let subtraction = 5 - 3;
console.log(subtraction);  // 2を出力

// 乗算 (*)
let multiplication = 5 * 3;
console.log(multiplication);  // 15を出力

// 除算 (/)
let division = 8 / 2;
console.log(division);  // 4を出力

// 剰余 (%)
let modulus = 7 % 3;
console.log(modulus);  // 1を出力

// 累乗 (**)
let exponentiation = 2 ** 3;
console.log(exponentiation);  // 8を出力

// 前置インクリメント (++)
let preIncrement = 5;
console.log(++preIncrement);  // 6を出力

// 後置インクリメント (++)
let postIncrement = 5;
console.log(postIncrement++);  // 5を出力
console.log(postIncrement);    // 6を出力

// 前置デクリメント (--)
let preDecrement = 5;
console.log(--preDecrement);  // 4を出力

// 後置デクリメント (--)
let postDecrement = 5;
console.log(postDecrement--);  // 5を出力
console.log(postDecrement);    // 4を出力

// 単項プラス (+)
let unaryPlus = +'3';
console.log(unaryPlus);  // 数値の3を出力

// 単項マイナス (-)
let unaryMinus = -'3';
console.log(unaryMinus);  // 数値の-3を出力


代入演算子

// 基本の代入演算子 (=)
let a = 5;
console.log(a);  // 5を出力

// 加算代入 (+=)
let b = 5;
b += 3;  // b = b + 3と同じ
console.log(b);  // 8を出力

// 減算代入 (-=)
let c = 5;
c -= 3;  // c = c - 3と同じ
console.log(c);  // 2を出力

// 乗算代入 (*=)
let d = 5;
d *= 3;  // d = d * 3と同じ
console.log(d);  // 15を出力

// 除算代入 (/=)
let e = 8;
e /= 2;  // e = e / 2と同じ
console.log(e);  // 4を出力

// 剰余代入 (%=)
let f = 7;
f %= 3;  // f = f % 3と同じ
console.log(f);  // 1を出力

// 左ビットシフト代入 (<<=)
let g = 5;  // 5は2進数で101
g <<= 2;   // g = g << 2と同じ
console.log(g);  // 20を出力、2進数で10100

// 右ビットシフト代入 (>>=)
let h = 16;  // 16は2進数で10000
h >>= 2;    // h = h >> 2と同じ
console.log(h);  // 4を出力、2進数で100

// 符号なし右ビットシフト代入 (>>>=)
let i = -16; 
i >>>= 2;
console.log(i);  // 大きな数値を出力、符号ビットを考慮せずにシフトした結果

// ビットごとのAND代入 (&=)
let j = 7;   // 7は2進数で0111
j &= 3;     // j = j & 3と同じ、3は2進数で0011
console.log(j);  // 3を出力、2進数で0011

// ビットごとのXOR代入 (^=)
let k = 7;  // 7は2進数で0111
k ^= 3;    // k = k ^ 3と同じ、3は2進数で0011
console.log(k);  // 4を出力、2進数で0100

// ビットごとのOR代入 (|=)
let l = 5;  // 5は2進数で0101
l |= 3;    // l = l | 3と同じ、3は2進数で0011
console.log(l);  // 7を出力、2進数で0111

// 累乗代入 (**=)
let m = 3;
m **= 2;  // m = m ** 2と同じ
console.log(m);  // 9を出力


比較演算子

// 等価 (==) - 値が等しいかどうかをチェック(型変換を伴います)
console.log(5 == '5');   // trueを出力
console.log(5 == 3);     // falseを出力

// 不等価 (!=) - 値が異なるかどうかをチェック(型変換を伴います)
console.log(5 != '5');   // falseを出力
console.log(5 != 3);     // trueを出力

// 厳格な等価 (===) - 値と型が等しいかどうかをチェック(型変換なし)
console.log(5 === '5');  // falseを出力
console.log(5 === 5);    // trueを出力

// 厳格な不等価 (!==) - 値と型が異なるかどうかをチェック(型変換なし)
console.log(5 !== '5');  // trueを出力
console.log(5 !== 5);    // falseを出力

// より大きい (>)
console.log(5 > 3);      // trueを出力
console.log(5 > 5);      // falseを出力

// より小さい (<)
console.log(5 < 3);      // falseを出力
console.log(5 < 5);      // falseを出力

// 以上 (>=)
console.log(5 >= 3);     // trueを出力
console.log(5 >= 5);     // trueを出力

// 以下 (<=)
console.log(5 <= 3);     // falseを出力
console.log(5 <= 5);     // trueを出力

// オブジェクトの同一性をチェックする場合(参照が同じかどうか)
let obj1 = { value: 10 };
let obj2 = { value: 10 };
let obj3 = obj1;

console.log(obj1 === obj2);  // falseを出力(異なる参照のため)
console.log(obj1 === obj3);  // trueを出力(同じ参照のため)


論理演算子

// 論理AND (&&) - 両方のオペランドが真の場合に真を返す
console.log(true && true);     // trueを出力
console.log(true && false);    // falseを出力
console.log(false && true);    // falseを出力
console.log(false && false);   // falseを出力

// 論理OR (||) - 少なくとも1つのオペランドが真の場合に真を返す
console.log(true || true);     // trueを出力
console.log(true || false);    // trueを出力
console.log(false || true);    // trueを出力
console.log(false || false);   // falseを出力

// 論理NOT (!) - オペランドの真偽を反転させる
console.log(!true);            // falseを出力
console.log(!false);           // trueを出力

// Nullish coalescing operator (??) - 左のオペランドがnullまたはundefinedの場合に右のオペランドを返す
let x = null;
let y = "デフォルト値";
console.log(x ?? y);           // "デフォルト値"を出力

let z = "有効な値";
console.log(z ?? y);           // "有効な値"を出力

// 実際の使い方
let userName = null;
let defaultName = "ゲスト";
let displayName = userName || defaultName;
console.log(displayName);      // "ゲスト"を出力


条件(三項)演算子

// 条件 (三項) 演算子
// 形式: 条件 ? 値1(真の場合) : 値2(偽の場合)

let age = 20;
let type = age >= 18 ? "成人" : "未成年";
console.log(type); // "成人"を出力

age = 15;
type = age >= 18 ? "成人" : "未成年";
console.log(type); // "未成年"を出力

// 数値を判定して文字列に変換する場合
let number = 5;
let result = number > 0 ? "正の数" : number < 0 ? "負の数" : "ゼロ";
console.log(result); // "正の数"を出力

number = -3;
result = number > 0 ? "正の数" : number < 0 ? "負の数" : "ゼロ";
console.log(result); // "負の数"を出力

number = 0;
result = number > 0 ? "正の数" : number < 0 ? "負の数" : "ゼロ";
console.log(result); // "ゼロ"を出力


型演算子

// 1. typeof - オペランドの型を文字列として返します。
console.log(typeof "文字列");   // "string"を出力
console.log(typeof 123);       // "number"を出力
console.log(typeof true);      // "boolean"を出力
console.log(typeof undefined); // "undefined"を出力
console.log(typeof null);      // "object"を出力 (これはJavaScriptの既知のバグ的な振る舞いです)
console.log(typeof {});        // "object"を出力
console.log(typeof []);        // "object"を出力
console.log(typeof function() {}); // "function"を出力

// 2. instanceof - オブジェクトが特定のコンストラクタのインスタンスかどうかをテストします。
function Person() {}

let person1 = new Person();
console.log(person1 instanceof Person);   // trueを出力
console.log(person1 instanceof Object);   // trueを出力(すべてのオブジェクトはObjectのインスタンスです)

let numbers = [1, 2, 3];
console.log(numbers instanceof Array);    // trueを出力
console.log(numbers instanceof Object);   // trueを出力
console.log(numbers instanceof RegExp);   // falseを出力


ビット演算子

// 1. ビットごとのAND (&)
console.log(5 & 1); // 0101 & 0001 => 0001 (1を出力)

// 2. ビットごとのOR (|)
console.log(5 | 2); // 0101 | 0010 => 0111 (7を出力)

// 3. ビットごとのXOR (^)
console.log(5 ^ 1); // 0101 ^ 0001 => 0100 (4を出力)

// 4. ビットごとのNOT (~)
console.log(~5);    // ~0101 => 1010 (-6を出力)

// 5. 左シフト (<<)
console.log(5 << 1); // 0101 << 1 => 1010 (10を出力)

// 6. 右シフト (>>)
console.log(5 >> 1); // 0101 >> 1 => 0010 (2を出力)

// 7. ゼロ埋め右シフト (>>>)
console.log(-5 >>> 1); // 負の数も正の結果になります。

// 例: フラグの操作
let flags = 5; // 0101
let mask = 3;  // 0011
console.log(flags & mask);  // フラグの共通部分: 0001 (1を出力)

mask = 2;       // 0010
console.log(flags | mask);  // フラグを設定/追加: 0111 (7を出力)


スプレッド演算子

// 配列での使用
let arr1 = [1, 2, 3];
let arr2 = [...arr1, 4, 5];
console.log(arr2); // [1, 2, 3, 4, 5]を出力

// オブジェクトでの使用
let obj1 = {a: 1, b: 2};
let obj2 = {...obj1, c: 3};
console.log(obj2); // {a: 1, b: 2, c: 3}を出力


レスト演算子

function sum(...numbers) {
    return numbers.reduce((acc, curr) => acc + curr, 0);
}

console.log(sum(1, 2, 3, 4)); // 10を出力

// デストラクチャリングとの組み合わせ
let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // 1を出力
console.log(rest);  // [2, 3, 4]を出力


演算子の優先順位

まず括弧()が優先されます。その他の演算子については下記の優先順位となります。

  • new (新しいインスタンスの作成)
  • !, ~, +, -, ++, --, typeof, void, delete (単項演算子)
  • *, /, % (乗算、除算、余りの計算)
  • +, - (加算、減算)
  • <<, >>, >>> (ビットシフト)
  • <, <=, >, >=, in, instanceof (関係)
  • ==, !=, ===, !== (等価性)
  • & (ビットごとのAND)
  • ^ (ビットごとのXOR)
  • | (ビットごとのOR)
  • && (論理AND)
  • || (論理OR)
  • ... ? ... : ... (条件 (三項) 演算子)
  • =, +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, ^=, |=, **= (代入)
  • , (コンマ)


練習問題1.

以下の式の結果は何になるでしょうか?

let result = (10 + 5) * 3 / 2 - 4;


練習問題2.

以下の条件式の結果はtrueかfalseか?

let age = 25;
let isStudent = false;

let check = age > 20 && (age < 30 || isStudent);


練習問題3.

次のコードで、配列arrの中にある数字の平均を計算する関数averageを完成させてください。

function average(...) {
    // この部分を完成させる
}

let arr = [10, 20, 30, 40];
console.log(average(...arr)); // この行が25を出力するように関数を完成させてください。