🙄

今さら訊けないJavaScriptの基本メモ

に公開2

やること

モダンなフロントエンド開発で大事そうなJavaScriptの基本をまとめておく

参考文献

https://jsprimer.net/

アロー関数

アロー関数(Arrow Function)は、ES2015(ES6)で導入された関数を定義する新しい構文で、従来のfunctionキーワードを使った関数宣言や関数式よりも短く簡潔に書くことができます。
アロー関数の基本的な構文と特徴は以下のとおりです。

// 基本的な構文
const 変数名 = () => {
    // 処理内容
    return 返り値;
};

①省略記法
 仮引数が1つのみなら()を省略できる:x => { ... }
 処理が1つの式だけなら{}とreturnを省略できる:x => x * 2
②常に無名関数
 名前をつけることができない(変数に代入して使う)
③thisの扱いが特殊
 通常の関数と違い、アロー関数内のthisは静的に決定される
 アロー関数は自分自身のthisを持たず、定義されたスコープのthisを継承する。この特性により、コールバック関数内でのthisの問題を解決可能
④制約
 new演算子で呼び出せない(コンストラクタとして使えない)
 arguments変数を参照できない

例えば、配列の各要素を2倍にする処理を通常の関数とアロー関数で比較してみます。

// 通常の関数式
const doubleArray1 = array.map(function(value) {
    return value * 2;
});

// アロー関数(簡潔に書ける)
const doubleArray2 = array.map(value => value * 2);

この後紹介するコールバック関数を多用する場合や簡潔な記述が求められる場合に、アロー関数は非常に便利です。

コールバック関数

コールバック関数とは、他の関数に引数として渡される関数のことです。これにより、ある処理が終わったあとに実行される処理を定義することができます。他の関数やメソッドに「後で呼び出してもらうための関数」として渡されるため、この仕組みにより非同期処理や反復処理などを簡潔に記述できるのが特徴です。

// 基本的なコールバック関数の例
function 親関数(コールバック関数) {
    // 何らかの処理
    コールバック関数(); // 渡された関数を実行
}

// 親関数にコールバック関数を渡して実行
親関数(function() {
    console.log("コールバック関数が実行されました");
});

主な用途としては、JavaScriptの配列で要素を反復処理するメソッドとしてコールバック関数を活用する例が挙げられます。

const array = [1, 2, 3];
array.forEach((currentValue, index, array) => {
    console.log(currentValue, index, array);
});
// 出力:
// 1, 0, [1, 2, 3]
// 2, 1, [1, 2, 3]
// 3, 2, [1, 2, 3]

あと非同期処理では、結果を処理するためにコールバック関数を使うことがあります。ここでの注意点として、非同期処理のコールバック関数内で発生した例外は、その外側にある try...catch では捕捉できません。そのため、コールバック関数内で明示的にエラーハンドリングを行う必要があります。

// setTimeout関数の例
// 非同期処理の外
setTimeout(() => {
    console.log("非同期のコールバック関数が実行されました");
    // 非同期処理の中
    try {
        throw new Error("エラー");
    } catch (error) {
        console.log("エラーをキャッチできる");
    }
}, 1000); // 1000ミリ秒(1秒)後に実行

分割代入

分割代入は、ES2015(ES6)で導入された構文で、オブジェクトや配列から値を取り出して個別の変数に代入する構文です。分割代入のメリットとしては以下が挙げられます。
①複数の変数への代入が1行で行えるので、コードを簡潔に書ける
②オブジェクトや配列から必要な値だけを簡単に取り出せる
③デフォルト値を設定できる
④関数が期待するオブジェクトのプロパティを明示的に示せる

以下、オブジェクトや配列、関数の引数で用いた例を見てみます。

オブジェクトの分割代入

オブジェクトから特定のプロパティを取り出して変数に代入する場合、分割代入を使うと以下のように簡潔に書くことができます。

// 従来の方法
const languages = {
    ja: "日本語", en: "英語"
};
const ja = languages.ja;
const en = languages.en;
console.log(ja); // => "日本語"
console.log(en); // => "英語"

// 分割代入
const languages = {
    ja: "日本語", en: "英語"
};
const { ja, en } = languages;
console.log(ja); // => "日本語"
console.log(en); // => "英語"

また、プロパティが存在しない場合に備えてデフォルト値を設定できるのも1つのポイントです。

const languages = {
    ja: "日本語"
};
// enプロパティが存在しない場合は「不明」をデフォルト値として使用
const { ja, en = "不明" } = languages;
console.log(ja); // => "日本語"
console.log(en); // => "不明"

配列の分割代入

配列の分割代入では、左辺に配列リテラルのような構文で変数名を並べます。配列の要素は、その位置(インデックス)に基づいて対応する変数に代入されます。配列の場合も、存在しない要素に対してデフォルト値を設定できます。

const array = ["one", "two", "three"];
const [first, second, third] = array;
console.log(first);  // => "one"
console.log(second); // => "two"
console.log(third);  // => "three"

const array = ["one"];
// 2番目の要素が存在しない場合は「unknown」をデフォルト値として使用
const [first, second = "unknown"] = array;
console.log(first);  // => "one"
console.log(second); // => "unknown"

Spread構文

Spread構文は、ES2015(ES6)で導入された機能で、配列やオブジェクトの要素を展開するための便利な構文です。ピリオド3つ(...)で表現され、様々な状況で使用できます。Spread構文のメリットとしては以下が挙げられます。
①配列やオブジェクトの結合、コピー操作が直感的に書ける
②配列要素やオブジェクトプロパティを任意の位置に挿入できる
③元のデータ構造を変更せずに新しいデータ構造を作成できる(immutableな操作)

配列の結合やコピーは以下のような記述で実現できます。Spread構文を使うと、簡単に配列の浅いコピー(shallow copy)を作成でき、元の配列を変更せずに新しい配列で操作を行うときに重宝します。

const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
// Spread構文を使用した配列の結合
const combinedArray = [...array1, ...array2];
console.log(combinedArray); // => [1, 2, 3, 4, 5, 6]
// 従来のconcatメソッドを使った場合
const combinedArrayWithConcat = array1.concat(array2);
console.log(combinedArrayWithConcat); // => [1, 2, 3, 4, 5, 6]

// Spread構文を使用した配列のコピー
const original = [1, 2, 3];
const copy = [...original];
console.log(copy); // => [1, 2, 3]
console.log(original === copy); // => false(新しい配列オブジェクト)

配列処理メソッド

コールバック関数のところでも少し触れましたが、特に使われている map と filter メソッドを確認しておきます。

// mapメソッドの基本的な構文
const newArray = array.map((currentValue, index, array) => {
    // 返り値が新しい配列の要素となる
    return 変換後の値;
});

// filterメソッドの基本的な構文
const newArray = array.filter((currentValue, index, array) => {
    // trueを返した要素だけが新しい配列に含まれる
    return 条件式;
});

/* 各引数の意味
currentValue: 現在処理している配列の要素
index: 現在処理している要素のインデックス(位置)
array: mapが呼び出された配列自体(元の配列)
*/

mapメソッドの例

map メソッドは、与えられたコールバック関数を配列のすべての要素に対して呼び出し、その結果から新しい配列を作成します。原則的には元の配列と同じ長さの新しい配列を返します。

// 各数値を2倍にする
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((num) => {
    return num * 2;
});
console.log(doubled); // => [2, 4, 6, 8, 10]

/// 特定のプロパティだけを抽出
const users = [
    { id: 1, name: "田中", age: 28 },
    { id: 2, name: "佐藤", age: 35 },
    { id: 3, name: "鈴木", age: 22 }
];
const names = users.map(user => user.name);
console.log(names); // => ["田中", "佐藤", "鈴木"]

filterメソッドの例

filter メソッドは、与えられたコールバック関数を配列の各要素に対して実行し、その結果が true となる要素だけを集めた新しい配列を返します。その名の通り、配列をフィルタリング(選別)するためのメソッドです。

// 偶数だけを抽出する
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter(num => {
    return num % 2 === 0;
});
console.log(evenNumbers); // => [2, 4, 6, 8, 10]

// 特定の条件を満たすオブジェクトだけを抽出
const users = [
    { id: 1, name: "田中", age: 28, active: true },
    { id: 2, name: "佐藤", age: 35, active: false },
    { id: 3, name: "鈴木", age: 22, active: true },
    { id: 4, name: "高橋", age: 42, active: false }
];

// アクティブなユーザーだけを抽出
const activeUsers = users.filter(user => user.active);
console.log(activeUsers);
// => [
//   { id: 1, name: "田中", age: 28, active: true },
//   { id: 3, name: "鈴木", age: 22, active: true }
// ]

// 30歳以上のユーザーだけを抽出
const olderUsers = users.filter(user => user.age >= 30);
console.log(olderUsers);
// => [
//   { id: 2, name: "佐藤", age: 35, active: false },
//   { id: 4, name: "高橋", age: 42, active: false }
// ]

コメントなど

ざっくりJavaScriptの基本をまとめてみました。アロー関数やSpread構文などPythonにはない概念もあって学びが多かったです。あと習熟するためには実際に使って覚えていくしかないかなーというところです。次はReactをキャッチアップしていきたいと思います。

ヘッドウォータース

Discussion

junerjuner

②常に無名関数

変数に直接代入したときに限って 名前はついています。

const v1 = () => undefined;
console.log(v1.name); // -> 'v1'

const v2 = (() => () => undefined)();
console.log(v2.name); // -> ''

https://runjs.app/play/#Y29uc3QgdjEgPSAoKSA9PiB1bmRlZmluZWQ7CmNvbnNvbGUubG9nKHYxLm5hbWUpOyAvLyAtPiAndjEnCgpjb25zdCB2MiA9ICgoKSA9PiAoKSA9PiB1bmRlZmluZWQpKCk7CmNvbnNvbGUubG9nKHYyLm5hbWUpOyAvLyAtPiAnJwo=