1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptのアロー関数と構造分解(分割代入)

Last updated at Posted at 2025-08-19

目的・意図

Reactを学ぶためにはJavaScriptのアロー関数と構造分解(分割代入)の理解が必須であることに気づいたので深掘りする。

JavaScriptのアロー関数とは?

ES2015のアロー関数の登場により、「簡潔に」「短く」関数を書けるようになった!

基本的な書き方
const 関数の変数名 = (引数) => 戻り値;

同じアロー関数でも、丸括弧や波括弧、returnの省略できる・できないのパターンがある。
(ここが理解できてなくて、文を見るたび毎回混乱してた・・・)

その1:引数が1つの場合は、丸括弧を省略できる
const square = x => x * x;
その2:戻り値が単一の式を返す場合のみ波括弧とreturnを省略できる(式が複数あったり文が含まれた時点で関数が何を返すか明確でなくなりreturnと波括弧が必要になる)
const add = (a, b) => a + b;
その3:オブジェクトを返す場合は丸括弧で囲む必要がある
const createPerson = (name) => ({ name });

🤔アロー関数をなぜ使うの?

  1. アロー関数を使うと短く簡潔になるため。特にコールバック関数や高階関数を使用するときに可読性がアップ!
  2. 親のスコープのthisを保持するため。特にReactコンポーネント内のメソッド定義においてthisのバインディングを意識する必要がなくなる
  • コールバック関数とは?
    • 他の関数に引数として渡され、特定のタイミングで呼び出される関数のこと
  • 高階関数とは?
    • 他の関数を引数として受け取ったり、関数を戻り値として返したりする関数のこと
      • 配列のmapメソッドは、コールバック関数を引数として受け取り、各要素に対してその関数を適用する
    • 高階関数は、元の関数の中身を上書きせずに、新しい値やオブジェクト(または配列)として処理した結果を返すことが多い
      • これにより、元のデータを保持しつつ、新しいデータを生成できる
  • thisを保持とは?
    • thisは関数が呼び出された時の文脈を指し、その関数がどのオブジェクトに属しているかを示す
functionを使った通常の関数だとthisの矛先がグローバルになってしまう🙅‍♀️
function Person() {
    this.age = 0;

    setInterval(function() {
    // ここでの`this`はグローバルオブジェクトである`window`を指す
    // そのため`this.age`が`undefined`となり、エラーになる
        this.age++; 
        console.log(this.age);
    }, 1000);
}

const person = new Person(); // `this`が期待通りに動作しない
functionで期待通りに動作させるには保持するための工夫が必要になる🙅‍♀️
function Person() {
    this.age = 0;
    const self = this; // `this`を保持ための変数が必要になる

    setInterval(function() {
        self.age++; // `self`を使って`this`を参照
        console.log(self.age);
    }, 1000);
}

const person = new Person(); // ここでは`self`を使って期待通りに動作する
アロー関数のthisだと矛先が親であるPesonオブジェクトを指す🙆
function Person() {
    this.age = 0;

    setInterval(() => {
        this.age++; // ここでの`this`はPersonを指す
        console.log(this.age);
    }, 1000);
}

const person = new Person(); // `this`が期待通りに動作する

🤔アロー関数ってどうやって書くんだっけ?

なかなかアロー関数の書き方になれなかった私。
通常の関数の書き方から、アロー関数に変化させることで覚えられた。

通常の関数
function 関数名(引数) {
    return 戻り値;
};
  • まずアロー関数になるとfunctionが不要になる
  • そして関数名だった部分をconst変数名として定義する
    • そうすることで、ただのスコープ内における関数から、代入ができる変数に昇格!
      • あとは前述した省略のパターンを覚えておけばOK
const 関数の変数名 = (引数) => {
    return 戻り値;
};

※厳密には(引数) => {return 戻り値;};の部分がアロー関数であるが、constとして変数に格納して使用することが多い。

JavaScriptの構造分解(分割代入)とは?

ES2015の分割代入により、オブジェクトや配列から値を簡単に取り出せるようになった!

基本的な書き方
const { プロパティ名1, プロパティ名2 } = オブジェクト名;
const [ 変数1, 変数2 ] = 配列名;
取り出すのが楽になる(オブジェクトバージョン)
const myProfile = {
    name: 'はな',
    age: '3',
};

// 従来であればドット繋ぎで呼び出す
const messages = `私の名前は${myProfile.name}です。${myProfile.age}です。`

// 分割代入する場合、
// 左側に取り出した後につけたい変数名、
// 右側にどこから取り出すか(オブジェクト名あるいは配列名)を定義
const { name, age } = myProfile;

// 分割代入すると定義した変数で直接呼び出せるようになる
const bunkatuMessages = `私の名前は${name}です。${age}です。`
取り出すのが楽になる(配列バージョン)
const ['メグ', 'ジョー', 'ベス', 'エイミー'] = mySister;

// 従来であればインデックスを使って要素を取り出す
const Messages = `私の姉妹の名前は${mySister[0]}, ${mySister[1]}, ${mySister[2]}, ${mySister[3]}です`;

// 配列を分割代入する場合、任意の変数名をつける(順番に気を付けて取り出す形)
const [meg, jo, beth, amy] = mySister;

const bunkatuMessages = `私の姉妹の名前は${meg}, ${jo}, ${beth}, ${amy}です`

😊構造分解(分割代入)の値を変更したときの挙動

  • 構造分解(分割代入)は左辺で任意の名前をつけた変数に対して右辺のオブジェクトや配列を分解して代入を行っている
  • そのため別個の変数として新しく定義しているので、右辺がプリミティブ値だった場合には、元のオブジェクトや配列を変更した場合でも、影響を受けない
  • ただし、右辺がオブジェクトだった場合には、新しい変数が作成されつつも(複数の変数が同じオブジェクトを指し示すことができるため)一方の変数を通じてオブジェクトを変更すると、他方の変数にもその変更が反映されてしまうので注意する

コンピューター科学において、オブジェクトは識別子によって参照可能なメモリー内の値です

→つまり、オブジェクト自体が変数に直接格納されるのではなく、そのオブジェクトが格納されているメモリのアドレス(参照)が変数に格納されている

プリミティブ値
const primitiveObj = { num: 50, str: 'hello', bool: true };
const { num, str, bool } = primitiveObj;

// 元のオブジェクトのnumと構造分解したnumは同じ「50」の値をもつ
console.log('数値:', num === primitiveObj.num); // true

// 元のオブジェクトのnumを「100」に変更
primitiveObj.num = 100;

// 構造分解したnumは影響を受けず「false」となる
console.log('数値は同じですか?', num === primitiveObj.num); // false

console.log('元の数値num', primitiveObj.num); // 100
console.log('分割代入の数値num', num); // 50
オブジェクト
const referenceObj = { obj: { x: 1 }, arr: [1, 2, 3] };
const { obj, arr } = referenceObj;

// 元のオブジェクトのobjと構造分解したobjは同じ「obj: { x: 1 }」の値をもつ
console.log('オブジェクト:', obj === referenceObj.obj); // true

// 元のオブジェクトobjを「{ x: 2 }」に変更
referenceObj.obj.x = 2;

// 構造分解したobjも影響を受けており「true」となる
console.log('オブジェクトは同じですか?', obj === referenceObj.obj); // true

console.log('元のオブジェクトobj:', referenceObj.obj.x); // 2
console.log('構造分解のobj', obj.x); // 2

🤔(心の声)なんで分割代入っていうの?名前から直感的に意味が理解できない

現在は、「分割代入」ではなく「構造分解」に改名されていた。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring

スクリーンショット 2025-08-23 17.51.43.png

@juner ありがとうございます🙇‍♀️

🐻:なんで分割代入っていうんだろ?

  1. 分割した変数に対してオブジェクトあるいは配列の値を代入する
  2. その変数を使って呼び出すことで、従来はオブジェクト名.値配列名[0]のように呼び出していたのがあるいは配列用に新しくつけた変数名で呼び出せるようになった

つまり、

  1. 複数の中身があるものに対して、複数の変数名をつけてあげる
  2. この操作を一つの式で行うので「分割で代入すること」が起こっているのか

🐻:あなたが頭の柔軟な小学生なら、分割代入ではなくてどんな名前をつける?

🐰:「簡単呼び出し!」

🐻:そうそう!!
「代入」よりも「取り出し」への利点に目がいっちゃうので直感的じゃないって思ったんだ!
つまり、分割代入という名前は、オブジェクトや配列の中身を分けて新しい変数に代入するというプロセスを表しているが、実際には値を取り出すことに重点が置かれているのか!

🐰:値を取り出すことだけに重点が置かれているのか?

🐻:分割代入による例を見てみよう!

可読性が高まる(オブジェクトから必要な2つのプロパティを取り出していることが明示的である)
const user = {
    name: 'Alice',
    age: 30,
    email: 'alice@example.com'
};

// 分割代入を使うことで、`name`と`age`を使っていることがわかる
const { name, age } = user;

console.log(name); // 'Alice'
console.log(age);  // 30
ネストされている場合でも1つの変数で取り出せるようになる
const userProfile = {
    user: {
        name: 'Alice',
        age: 30,
        address: {
            city: 'Tokyo',
            postalCode: '100-0001'
        }
    },
    preferences: {
        theme: 'light',
        notifications: true
    }
};

// ネストされたオブジェクトを分割代入
const { user: { name, address: { city } } } = userProfile;

console.log(name); // 'Alice'
// ネストしたオブジェクトも`city`という変数一つで呼び出せる
console.log(city); // 'Tokyo'
デフォルト値を設定できるのでエラー回避に繋がる
const user = {
    name: 'Bob'
    // ageプロパティが存在しない
};

// 分割代入でデフォルト値を設定
const { name, age = 25 } = user;

console.log(name); // 'Bob'
console.log(age);  // 25 (デフォルト値)

🐰:以下のパターンがありそうだね

  1. オブジェクトや配列からどの値を使っていて使っていないのか明示的
  2. ネストを含めて変数一つで呼び出せるので取り出しが簡単・簡潔になる
  3. デフォルト値を設定できるのでエラーを起こすリスクを減らせる

🐻:公開されているAPIを利用しに行ったとき、1つのエンドポイントに複数の値が入っていて、その中から自分のシステムで使う値を明示的に示せたり、ネストされているときも簡潔にできたり、反対にAPIレスポンスには含まれてない値をデフォルト値で設定したりで使えそうって思ったわ

🐻:出た結論
分割代入とは、「値を簡単に取り出す」「明示的になる」「堅牢になる」メリットがあり、その手段として「分割で変数に代入している」
だから直感的に意味不明って思ったんだとスッキリした。

⚠️オブジェクトの省略記法と似てるけど別物なので間違えるな!

JavaScriptでは、プロパティ名と変数名が一致していたら、プロパティ名を省略できる。
(これをプロパティのショートハンドという)

もしもプロパティ名と変数名が一致していたらプロパティ名を省略できる
 const name = 'はな';
 const age = 3;

 // 通常の書き方
 const myProfile = {
     name: name,
     age: age
 };

 // 省略記法
 const myProfile = {
     name, // 右側のnameは変数名を参照
     age   // 右側のageも同様
 };

これが1行で書かれていると、一見「え?分割代入!?」と思ってしまうがこれは省略記法の話なので違う。
左側に書いているか、右側に書いているかで意味が別物なので気をつけよう。

これは分割代入ではなく、オブジェクトの省略記法なだけ
const myProfile = { name, age };

🤔プロパティ名とその値が自然に一致することってあるのか?

この話を聞いた時に、namenameageageでなぜ一致するんだ?と思った。
よくよく調べたら、省略記法を使うには、まずその変数が事前に宣言している必要があった。

事前に宣言しているから省略できる
const name = 'はな'; // 変数を宣言
const myProfile = {
   name // 省略記法を使用
};
もしも事前に宣言してなければ、省略できない
const myProfile = {
   name // これはエラー
};

なので初めは、

「プロパティ名とその値が一致していたら、プロパティ名を省略できる。」

と思っていたが、正しくは、

「プロパティ名と事前定義した変数名が一致していたら、プロパティ名を省略できる。」

ということだった。

あとは、当たり前かもしれないけど、配列にはプロパティという概念はないため、
配列に対してプロパティのショートハンドは起こり得ない。

プロパティのショートハンドは名前の通り、配列は関係ないよ!
const mySisters = ['メグ', 'ジョー', 'ベス', 'エイミー'];
// 配列ではプロパティのショートハンドは適用されない
1
1
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?