var a = 10;
console.log(a); // 出力: 10

var b;
console.log(b); // 出力: undefined
let a = 10;
console.log(a); // 出力: 10

let b;
console.log(b); // 出力: undefined
const age = 30;
const age; // Uncaught SyntaxError: Missing initializer in const declaration
if () { // ifブロック
    // ...
} else { // elseブロック
    // ...
}

function exampleFn() { // 関数ブロック
    // ...
}

{ // 任意の独立したブロック(通常あまり使用されません)
    let temp = 10; // tempはこのブロック内でのみ有効
}

for () {  // forブロック
    // ...
}
/* グローバル(全域)スコープ */
var globalVar = "グローバル変数"; // コード全体で有効な変数

function exampleFunction() {
    /* 関数スコープ */
    var functionVar = "関数内変数"; // 関数内全体で有効な変数

    if (true) {
        var blockVar = "ブロック内変数"; // if文のブロック({})内で宣言されたが、関数内全体で有効
        console.log(functionVar); // 出力: "関数内変数"
        console.log(blockVar); // 出力: "ブロック内変数"
    }

    // if文のブロック({})内で宣言されたが、関数内全体で有効か確認
    console.log(blockVar); // 出力: "ブロック内変数"
}

exampleFunction();
console.log(globalVar); // 出力: "グローバル変数"
console.log(functionVar); // ReferenceError発生(関数外では有効でない、functionVar is not defined)
/* グローバル(全域)スコープ */
let globalVar = "グローバル変数"; // このファイル(またはスクリプト)の最上位ブロック全体で有効

function exampleFunction() {
    /* 関数ブロックスコープ */
    let functionVar = "関数ブロック変数"; // 関数全体のブロックで有効

    if (true) {
        let innerBlockVar = "ifブロック変数"; 
        console.log(functionVar);   // 出力: "関数ブロック変数"
        console.log(innerBlockVar); // 出力: "ifブロック変数"
    }

    // ifブロックスコープの外なので参照不可
    // console.log(innerBlockVar); // ReferenceError (innerBlockVar is not defined)
}

if (true) {
    let ifBlockVar = "ifブロック変数";
    console.log(ifBlockVar); // 出力: "ifブロック変数"
}

exampleFunction();

console.log(globalVar); // 出力: "グローバル変数"

// console.log(functionVar); // ReferenceError (functionVar is not defined)
// console.log(ifBlockVar); // ReferenceError (ifBlockVar is not defined)
/* グローバル(全域)スコープ */
const globalVar = "グローバル変数"; // このファイル(またはスクリプト)の最上位ブロック全体で有効

function exampleFunction() {
    /* 関数ブロックスコープ */
    const functionVar = "関数ブロック変数"; // 関数全体のブロックで有効

    if (true) {
        const innerBlockVar = "ifブロック変数"; 
        console.log(functionVar);   // 出力: "関数ブロック変数"
        console.log(innerBlockVar); // 出力: "ifブロック変数"
    }

    // ifブロックスコープの外なので参照不可
    // console.log(innerBlockVar); // ReferenceError (innerBlockVar is not defined)
}

if (true) {
    const ifBlockVar = "ifブロック変数";
    console.log(ifBlockVar); // 出力: "ifブロック変数"
}

exampleFunction();

console.log(globalVar); // 出力: "グローバル変数"

// console.log(functionVar); // ReferenceError (functionVar is not defined)
// console.log(ifBlockVar); // ReferenceError (ifBlockVar is not defined)
/* 初期宣言および値の割り当て */
var myValue = 10;
console.log(myValue); // 出力: 10

/* 再代入 */
myValue = 20;
console.log(myValue); // 出力: 20(値が変更される)

/* 再宣言(varを再使用) */
var myValue = "Hello";
console.log(myValue); // 出力: "Hello"(エラーなく再宣言され、値が上書きされる)
// 同じスコープ内でletを使用して同一の識別子(変数名)で再宣言するとエラーが発生
let exampleLet = 10;
let exampleLet = 100; // Uncaught SyntaxError: Identifier 'exampleLet' has already been declared
// 異なるスコープ内でletを使用して同一の識別子(変数名)で再宣言することは可能
let exampleLet = 10;
console.log(exampleLet); // 出力: 10

if (true) {
    let exampleLet = 100;
    console.log(exampleLet); // 出力: 100
}

console.log(exampleLet); // 出力: 10
// グローバルスコープ
let globalVar = "グローバル変数";
console.log(globalVar); // "グローバル変数"

// 再代入可能
globalVar = "再代入されたグローバル変数";
console.log(globalVar); // "再代入されたグローバル変数"

if (true) {
    // ブロックスコープ
    let blockVar = "ブロック変数";
    console.log(blockVar); // "ブロック変数"

    // 再代入可能
    blockVar = "再代入されたブロック変数";
    console.log(blockVar); // "再代入されたブロック変数"
}

// ブロック外では参照不可
// console.log(blockVar); // ReferenceError
// 同じスコープ内でconstを使用して同一の識別子(変数名)で再宣言するとエラーが発生
const exampleConst = 10;
const exampleConst = 100; // Uncaught SyntaxError: Identifier 'exampleConst' has already been declared
// 異なるスコープ内でconstを使用して同一の識別子(変数名)で再宣言することは可能
const exampleConst = 10;
console.log(exampleConst); // 出力: 10

if (true) {
    const exampleConst = 100;
    console.log(exampleConst); // 出力: 100
}

console.log(exampleConst); // 出力: 10
const exampleConst = 10;

/* 同一の識別子に代入演算子(=)を使用して変数の値を変更することはできません。 */
exampleConst = 100; // Uncaught TypeError: Assignment to constant variable.
// 通常オブジェクトの宣言
const person = {
    name: 'Alice',
    age: 30
};

// 1. プロパティの追加
person.city = 'Seoul'; // 新しいプロパティを追加
console.log(person); // 出力: { name: 'Alice', age: 30, city: 'Seoul' }

// 2. プロパティの更新
person.age = 31; // 既存プロパティの値を更新
console.log(person); // 出力: { name: 'Alice', age: 31, city: 'Seoul' }

// 3. プロパティの削除
delete person.city; // プロパティを削除
console.log(person); // 出力: { name: 'Alice', age: 31 }
// 配列の宣言
const numbers = [1, 2, 3];

// 1. 要素の追加
numbers.push(4); // 配列の末尾に要素を追加
console.log(numbers); // 出力: [1, 2, 3, 4]

// 2. 要素の更新
numbers[0] = 10; // 最初の要素の値を更新
console.log(numbers); // 出力: [10, 2, 3, 4]

// 3. 要素の削除
numbers.pop(); // 配列の末尾の要素を削除
console.log(numbers); // 出力: [10, 2, 3]
/*
 * 以下のvar myNameで宣言されたmyName変数が
 * スコープの最上部に位置するかのようにホイスティングされます。
 * ただし、宣言された変数のみが持ち上げられ、
 * 宣言時に割り当てた値は元の位置に残ります。
 *
 * 宣言時に値がないため、
 * 実際に変数が宣言された位置より前に参照すると
 * undefinedで初期化されます。
*/

/* 実際に変数が宣言された位置より前に参照 */
console.log(myName); // 出力: undefined(宣言のみがホイスティングされ、値はundefinedで割り当てられる)

/* varで宣言した変数の位置 */
var myName = "John";
// TDZ領域の開始
// ↓
console.log(myVar); // ReferenceError: Cannot access 'myVar' before initialization
// ↑
// TDZ領域の終了

const myVar = 10;