0
0

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文法(12):最新のJavaScript機能

Posted at

前回の記事 では、非同期処理について、Promise、async/await構文、そしてAPI通信の方法を紹介しました。今回は最終回として、最新のJavaScript機能と今後の開発について、モダンな開発環境や新しい言語機能を中心に紹介します。

ESモジュール(import/export)

ES2015(ES6)で導入されたモジュールシステムは、コードの再利用性と保守性を向上させる重要な機能です。

基本的なexport/import

以下の例では、math.jsというモジュールファイルを作成し、そこから関数と定数をエクスポートし、main.js でそれらをインポートしています。

// math.js - モジュールのエクスポート
export const PI = 3.14159;

export function add(a, b) {
    return a + b;
}

export function multiply(a, b) {
    return a * b;
}

// デフォルトエクスポート
export default function subtract(a, b) {
    return a - b;
}
// main.js - モジュールのインポート
import subtract, { PI, add, multiply } from './math.js';

console.log(PI); // 3.14159
console.log(add(5, 3)); // 8
console.log(multiply(4, 6)); // 24
console.log(subtract(10, 3)); // 7

デフォルトエクスポートは、1つのモジュールにつき1つだけ可能です。デフォルトエクスポートにしたものは、インポート時に { } を使う必要がないという特徴があります。

モジュールの種類と使い分け

// 名前つきエクスポート(複数の機能をエクスポート)
export { PI, add, multiply };

// すべてをインポート
import * as MathUtils from './math.js';
console.log(MathUtils.add(1, 2));

// エイリアスを使用
import { add as addNumbers } from './math.js';
console.log(addNumbers(3, 4));

// 動的インポート(非同期)
async function loadModule() {
    const mathModule = await import('./math.js');
    console.log(mathModule.PI);
}

プライベートクラスフィールド

ES2022で導入されたプライベートクラスフィールドにより、真の意味でのプライベートメンバーが利用可能になりました。

プライベートフィールドの基本

class BankAccount {
    // プライベートフィールド(#で始める)
    #balance = 0;
    #accountNumber;

    constructor(accountNumber) {
        this.#accountNumber = accountNumber;
    }

    // パブリックメソッド
    deposit(amount) {
        if (amount > 0) {
            this.#balance += amount;
            console.log(`${amount}円を入金しました`);
        }
    }

    withdraw(amount) {
        if (amount > 0 && amount <= this.#balance) {
            this.#balance -= amount;
            console.log(`${amount}円を出金しました`);
        } else {
            console.log('残高不足です');
        }
    }

    getBalance() {
        return this.#balance;
    }

    // プライベートメソッド
    #validateTransaction(amount) {
        return amount > 0 && amount <= 1000000;
    }
}

const account = new BankAccount('123-456-789');
account.deposit(10000);
console.log(account.getBalance()); // 10000

// プライベートフィールドには外部からアクセスできない
// console.log(account.#balance); // SyntaxError

従来の書き方との比較

// 従来の書き方(命名規則でプライベートを表現)
class OldClass {
    constructor() {
        this._privateField = 'private'; // アンダースコアで表現
    }

    _privateMethod() {
        return 'This should be private';
    }
}

// 新しい書き方(真のプライベート)
class NewClass {
    #privateField = 'private';

    #privateMethod() {
        return 'This is truly private';
    }

    getPrivateValue() {
        return this.#privateField;
    }
}

新しい組み込みメソッド

便利なメソッドをいくつか紹介します。

String.replaceAll()

マッチしたすべての部分を置換するメソッドです。従来は正規表現を使う必要がありましたが、replaceAll により簡単に実現できます。

const text = "Hello world, world is beautiful";

// 従来の方法
const oldWay = text.replace(/world/g, "JavaScript");
console.log(oldWay); // "Hello JavaScript, JavaScript is beautiful"

// 新しい方法(ES2021)
const newWay = text.replaceAll("world", "JavaScript");
console.log(newWay); // "Hello JavaScript, JavaScript is beautiful"

Array.flat() とArray.flatMap()

下記のサンプルのように、フラット化とは、多次元配列を1次元に変換することを言います。

// 配列のフラット化
const nestedArray = [1, [2, 3], [4, [5, 6]]];

console.log(nestedArray.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nestedArray.flat(2)); // [1, 2, 3, 4, 5, 6]

// flatMap() - map と flat を組み合わせ
const numbers = [1, 2, 3, 4];
const doubled = numbers.flatMap(x => [x, x * 2]);
console.log(doubled); // [1, 2, 2, 4, 3, 6, 4, 8]

Object.fromEntries()

キーと値のペアの配列やMapからオブジェクトを生成します。

// 配列からオブジェクトを作成
const entries = [['name', '太郎'], ['age', 25], ['city', '東京']];
const person = Object.fromEntries(entries);
console.log(person); // { name: '太郎', age: 25, city: '東京' }

// Map からオブジェクトへの変換
const map = new Map([
    ['language', 'JavaScript'],
    ['year', 2025]
]);
const obj = Object.fromEntries(map);
console.log(obj); // { language: 'JavaScript', year: 2025 }

Temporal API(日時操作の新しい方法)

執筆時点(2025年8月)でまだexperimental(実験的)な段階にあるTemporal APIは、Dateオブジェクトの問題点を解決する、日付・時刻データ用APIです。

Dateオブジェクトの問題点

// Dateオブジェクトの問題例
const date1 = new Date('2025-01-15'); // タイムゾーンに依存
const date2 = new Date(2025, 0, 15); // 月は0ベース(0=1月)

// 月の計算が直感的でない
console.log(new Date(2025, 0, 15).getMonth()); // 0(1月なのに0)

// タイムゾーンの扱いが複雑
console.log(new Date().getTimezoneOffset()); // UTCの時刻との分単位の時差

Temporal APIの利点(将来的な機能)

注意: 執筆時点(2025年8月)で、下記のコードはFirefoxでのみサポートされています。今後、他のブラウザでも実行可能になるものと思われます。

// より直感的な日付操作
const today = Temporal.PlainDate.from('2025-01-15');
console.log(today.month); // 1(1月は1)

// タイムゾーンを意識した時刻操作
const zonedDateTime = Temporal.ZonedDateTime.from({
    year: 2025,
    month: 1,
    day: 15,
    hour: 15,
    minute: 30,
    timeZone: 'Asia/Tokyo'
});

// 期間の計算
const startDate = Temporal.PlainDate.from('2025-01-01');
const endDate = Temporal.PlainDate.from('2025-12-31');
const duration = startDate.until(endDate);
console.log(duration.days); // 364

TypeScriptやDenoなどへの展開

TypeScriptの基本

TypeScriptの大きな特徴は、型注釈を追加できることです。以下は、その簡単な例です。

// types.ts - 型定義
interface User {
    id: number;
    name: string;
    email: string;
    isActive: boolean;
}

// 関数の型注釈
function createUser(name: string, email: string): User {
    return {
        id: Math.floor(Math.random() * 1000),
        name,
        email,
        isActive: true
    };
}

// 配列とジェネリクス
function filterActiveUsers(users: User[]): User[] {
    return users.filter(user => user.isActive);
}

const users: User[] = [
    createUser("太郎", "taro@example.com"),
    createUser("花子", "hanako@example.com")
];

console.log(filterActiveUsers(users));  // アクティブなユーザーのみ表示

Denoの特徴

Denoは、TypeScriptをネイティブにサポートし、セキュリティを重視したランタイムです。以下は、Denoでの簡単なHTTPサーバーの例です。

// Deno環境でのHTTPサーバー例
import { serve } from "https://deno.land/std@0.201.0/http/server.ts";

const handler = (request: Request): Response => {
  const body = `Your user-agent is:\n\n${request.headers.get("user-agent") ?? "Unknown"}`;
  return new Response(body, { status: 200 });
};

// deno run --allow-net server.js
serve(handler);

復習

問題

1. ESモジュールを使用して、以下の要件を満たすコードを作成する

  • calculator.js ファイルに加算、減算、乗算、除算の関数を定義
  • main.js でそれらの関数をインポートして使用
  • デフォルトエクスポートとして計算履歴を管理するクラスを作成

2. プライベートクラスフィールドを使用してカウンタークラスを作成する

要件
  • プライベートフィールド #count を持つ
  • increment(), decrement(), getCount() メソッドを提供
  • 外部から #count に直接アクセスできないことを確認

3. 以下のデータを変換するコードを作成する

const data = [
    ['name', '太郎'],
    ['skills', ['JavaScript', 'Python', 'Go']],
    ['experience', [
        ['JavaScript', 3],
        ['Python', 2]
    ]]
];
要件
  • Object.fromEntries() を使用してオブジェクトに変換
  • スキル配列をフラット化
  • 経験データもオブジェクトに変換

解答例

問題1

// calculator.js
export function add(a, b) {
    return a + b;
}

export function subtract(a, b) {
    return a - b;
}

export function multiply(a, b) {
    return a * b;
}

export function divide(a, b) {
    if (b === 0) {
        throw new Error('ゼロで割ることはできません');
    }
    return a / b;
}

export default class CalculatorHistory {
    #history = [];

    addCalculation(operation, operands, result) {
        this.#history.push({
            operation,
            operands,
            result,
            timestamp: new Date()
        });
    }

    getHistory() {
        return [...this.#history];
    }

    clearHistory() {
        this.#history = [];
    }
}
// main.js
import CalculatorHistory, { add, subtract, multiply, divide } from './calculator.js';

const history = new CalculatorHistory();

const result1 = add(10, 5);
console.log('10 + 5 =', result1);
history.addCalculation('add', [10, 5], result1);

const result2 = multiply(4, 6);
console.log('4 * 6 =', result2);
history.addCalculation('multiply', [4, 6], result2);

console.log('計算履歴:', history.getHistory());

問題2

class Counter {
    #count = 0;

    increment() {
        this.#count++;
        console.log(`カウント: ${this.#count}`);
    }

    decrement() {
        this.#count--;
        console.log(`カウント: ${this.#count}`);
    }

    getCount() {
        return this.#count;
    }

    // プライベートメソッドの例
    #reset() {
        this.#count = 0;
    }
}

const counter = new Counter();
counter.increment(); // カウント: 1
counter.increment(); // カウント: 2
counter.decrement(); // カウント: 1

console.log('現在のカウント:', counter.getCount()); // 1

// プライベートフィールドにはアクセスできない
// console.log(counter.#count); // SyntaxError

問題3

const data = [
    ['name', '太郎'],
    ['skills', ['JavaScript', 'Python', 'Go']],
    ['experience', [
        ['JavaScript', 3],
        ['Python', 2]
    ]]
];

// Object.fromEntriesを使用してオブジェクトに変換
const person = Object.fromEntries(data);
console.log('基本オブジェクト:', person);

// スキル配列のフラット化
const flattenedSkills = person.skills.flat();
console.log('フラット化されたスキル:', flattenedSkills);

// 経験データをオブジェクトに変換
const experienceObject = Object.fromEntries(person.experience);
console.log('経験オブジェクト:', experienceObject);

// 最終的なデータ構造
const finalData = {
    ...person,
    skills: flattenedSkills,
    experience: experienceObject
};

console.log('最終データ:', finalData);

まとめ

本シリーズの最終回として、最新のJavaScript機能と開発環境について、主に下記の内容を紹介しました。

  • モジュールシステム
  • プライベートクラスフィールド
  • 新しい組み込みメソッド

最後に補足事項です。

今後の学習ステップ

  1. フレームワークの学習
    • React, Vue.js
    • Next.js, Nuxt.js
  2. TypeScriptの習得
    • 型安全性の向上
    • 大規模開発への対応
    • 開発効率の向上
  3. バックエンド開発
    • Node.js, Express.js
    • データベース操作(RDB, NoSQL)
    • REST API, GraphQLの構築
  4. モバイル・デスクトップ開発
    • React Native(モバイル)
    • Electron(デスクトップ)
    • Progressive Web Apps(PWA)
  5. 開発ツールとワークフロー
    • Webpack, Viteなどのバンドラ
    • Docker, CI/CDの活用
    • テスト駆動開発(Jest, Vitest)

公式ドキュメントとリソース

  1. MDN Web Docs
    • JavaScript言語仕様の詳細
    • ブラウザ互換性情報
    • 実践的なサンプルコード
  2. ECMAScript仕様書
    • TC39のGitHubリポジトリ
    • 新機能の提案状況
    • Stage 0-4の進捗状況
  3. Can I Use
    • ブラウザサポート状況の確認
    • 代替手段の情報

情報収集のコツ

  • 公式ドキュメント で学ぶ
  • TC39のproposal で新機能の動向をチェック
  • GitHub でのオープンソースプロジェクトから学ぶ
  • 技術ブログやカンファレンス で最新トレンドを把握
  • 実際にコードを書いて試す

これで「新・JavaScript文法」シリーズは完了です。読んでいただき、ありがとうございました。

0
0
2

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?