現代フロントエンド開発における主要技術スタック解説

1. DOM イベントシステムとフロー

標準的なドキュメントオブジェクトモデル(DOM)イベント処理は、主に以下の流れで発生します。

  • キャプチャフェーズ:ルートノードからターゲット要素へ向かって下向きに伝播します。
  • ターゲットフェーズ:特定のイベント対象ノードに到達します。
  • バブリングフェーズ:ターゲット要素からルートノードへ向かって上向きに伝播します。
// イベントリスナーの登録
// useCapture が true の場合、キャプチャフェーズで発火します
element.addEventListener('click', handlerFunction, false); 
// プロパティ割り当てと比較して、addEventListener は複数回登録が可能です

内部ネストされた要素でイベント発生を遮断するには、コールバック内で event.stopPropagation() メソッドを呼び出します。これにより上位要素への伝播を防ぐことができます。

2. イベント委譲(代理処理)の活用

子要素の数が多い場合や動的生成される要素に対して、共通の祖先ノード(親要素など)にイベントリスナーを登録し、バブリング現象を利用して処理を行う手法です。

  • メリット:メモリ使用量の削減、サブ要素追加時のリスナー再設定が不要。
  • デメリット:意図しない要素に対するトリガーが発生する可能性(フィルタリングが必要)。

3. CSS 優先順位とボックスモデル

スタイル適用ルールは、重要度順に以下のように評価されます:!important > インライン > ID > クラス/疑似クラス > タグ/疑似要素 > 継承 > 万能選択子。

box-sizing プロパティはレンダリングの算出方法を変更します。content-box がデフォルトであり、指定した幅はコンテンツ部分のみを示します。一方、border-box はパディングとボーダーを含む全体幅として解釈するため、レイアウト調整時に推奨されます。

4. レンダリング空間の隔離:BFC

ブロックレベルフォーマットコンテキスト(BFC)は、ブラウザによる通常のフローレンダリングにおける問題を解決するための独立した描画領域です。

主な課題と対策:

  • 高さの崩れ: floated 要素によって親要素の高さが計算されなくなる現象。解決法として、最後の要素に clear: both を適用するか、親要素に overflow: hiddendisplay: flow-root などを設定して BFC を起動させます。
  • マージンの重なり: 垂直方向のマージンが結合される現象。親要素にボーダーやパディングを設定することで回避可能です。

5. ライアウト構成テクニック

カラム配置には様々な手法が存在します。固定幅と可変幅を組み合わせる際、フローティング要素にはサイズを指定し、残りの部分を計算式で制御する方法や、Flexbox/Grid を使用するアプローチがあります。

6. 疑似クラスと疑似要素

  • 疑似クラス:要素の状態に基づいてスタイルを適用(例::hover, :nth-child)。DOMツリー内の状態を示唆します。
  • 疑似要素:DOMツリーに含まれない仮想要素を作成し装飾可能(例:::before, ::after)。

7. ポジショニングと配置

position 属性は要素の配置基準を決定します。

  • absolute:絶対配置。最初の親となる非 static 要素に対して相対します。ドキュメントフローから離脱します。
  • relative:相対配置。元自身の位置からのオフセット。フローに残ります。
  • fixed:ビューポートに対して固定。スクロールしても移動しません。
  • sticky:ストッパートリップ。ある閾値を超えると固定挙動をとります。

8. 中央揃え手法

柔軟な中央配置の実現方法:

// Flexbox を使用する場合
.container {
  display: flex;
  justify-content: center; /* 主轴 */
  align-items: center;     /* 副軸 */
}

// Absolute + Transform を使用する場合
.item {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
}

9. 重なり順序(Z-Index)

Z アドレス方向への積層順序は、stacking context ごとに管理されます。一般的に z-index が高いほど手前に表示され、同一レベルでは後続の要素優先となります。背景、境界線、ブロックボックス、フロート、インラインボックス等の順序に従います。

10. Flex レイアウト詳細

フレックスコンテナと項目の関係性を制御します。

  • コンテナ設定:flex-direction(配列方向)、flex-wrap(折り返し)、justify-content(主軸整列)、align-items(副軸整列)。
  • アイテム設定:flex-grow(拡張率)、flex-shrink(縮小率)、flex-basis(基本サイズ)。

11. JavaScript データ型と変換

基本型(Number, String, Boolean, Undefined, Null, BigInt, Symbol)と参照型(Object, Function)が存在します。

// 型判定の注意点
typeof null === 'object' // これは仕様上のバグです(ラベルが一致するため)
// 正確な判定には Object.prototype.toString.call を推奨
Object.prototype.toString.call([]) // '[object Array]'

数値や文字列への明示的・暗黙的変換が行われます。

12. モダン ECMAScript 機能

ES6 以降、新しいデータ構造 Set と Map が導入されました。

  • Set:一意な値のコレクション。重複排除に有効。
  • Map:キーと値のペアを保持。キーに任意の型(オブジェクト含む)を使用可能。

13. コピー処理の深さ

浅いコピー:トップレベルのプロパティのみ複製。参照型の中身は共有されます。{ ...obj } または Object.assign() で実装可能です。

深いコピー:ネストした構造まで再帰的に複製します。

function performDeepClone(source) {
  if (source === null || typeof source !== 'object') return source;
  
  const clone = Array.isArray(source) ? [] : {};
  
  for (const prop in source) {
    if (source.hasOwnProperty(prop)) {
      clone[prop] = performDeepClone(source[prop]);
    }
  }
  return clone;
}

14. 配列操作方法のカスタム実装

組み込みメソッドの動作原理を理解するために、関数を自作できます。

Array.prototype.customForEach = function(cb) {
  for (let idx = 0; idx < this.length; idx++) {
    cb(this[idx], idx, this);
  }
};
// map は新しい配列を返却
Array.prototype.customMap = function(callbackFn) {
  const newArray = [];
  for (let i = 0; i < this.length; i++) {
    newArray.push(callbackFn(this[i], i, this));
  }
  return newArray;
};

15. 実行コンテキストとスコープ

コード実行環境には「グローバル」と「関数」の 2 種類あります。スコープチェーンにより、ローカル変数が存在しない場合は上位スコープを探索します。閉包は、外側関数の変数を内側関数が記憶し続ける機構です。

16. メモリ管理とガベージコレクション

使用されなくなったオブジェクトは「マークアンドスクェース」アルゴリズムによって回収されます。長期生存オブジェクトと短期生存オブジェクトを区別する分代収集も行われ、パフォーマンスが最適化されます。

17. this のバインド制御

this 指向先は呼び出し元によって異なります。優先順位:new > call/apply/bind > 隐式绑定 > デフォルト。Arrow Function は自身の this を持たず、定義時周囲のスコーップを引きます。

18. コールバック関数の自作

関数ライブラリの基礎となる myCall, myApply, myBind は、文脈(context)を一時的に付与して実行することで実現します。

Function.prototype.myBind = function(ctx, ...argsFixed) {
  const func = this;
  return function(...restArgs) {
    return func.apply(ctx, [...argsFixed, ...restArgs]);
  };
};

19. 同期および非同期的処理

JavaScript は単スレッドですが、イベントループを通じて並行処理をシミュレートします。

  • マクロタスク:setTimeout, I/O, UI レンダリング。
  • マイクロタスク:Promise.then, queueMicrotask

コールバック地獄を解消し、同期的な記述が可能になるのが async/await 構文です。

20. カスタム Promise の構築

Promise の内部状態遷移(Pending, Fulfilled, Rejected)を実装すると理解が深まります。

class SimplePromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.successCallbacks = [];
    this.failureCallbacks = [];

    const resolve = (val) => {
      if (this.state !== 'pending') return;
      this.state = 'fulfilled';
      this.value = val;
      this.successCallbacks.forEach(fn => fn());
    };

    const reject = (err) => {
      if (this.state !== 'pending') return;
      this.state = 'rejected';
      this.reason = err;
      this.failureCallbacks.forEach(fn => fn());
    };

    try { executor(resolve, reject); } catch(e) { reject(e); }
  }

  then(onFulfilled, onRejected) {
    return new SimplePromise((resolve, reject) => {
      const handleValue = (data) => {
        try {
          const result = onFulfilled ? onFulfilled(data) : data;
          resolve(result); 
        } catch (error) { reject(error); }
      };

      const handleError = (err) => {
        try {
          const result = onRejected ? onRejected(err) : err;
          reject(result); 
        } catch (error) { reject(error); }
      };

      if (this.state === 'fulfilled') setTimeout(handleValue, 0, this.value);
      else if (this.state === 'rejected') setTimeout(handleError, 0, this.reason);
      else {
        this.successCallbacks.push(() => handleValue(this.value));
        this.failureCallbacks.push(() => handleError(this.reason));
      }
    });
  }
}

21. Vue フレームワークの反応性

Vue 2 では Object.defineProperty、Vue 3 では Proxy を使用し、データ変更を検知して DOM を更新します。defineProperty には新プロパティ追従性の弱点がありましたが、Proxy はこれを解消しています。

22. コンポーネント通信と状態管理

親から子へは Props、子から親へは Emit(または $emit)を使用します。跨階層通信には Provide/Inject または Zustand/Pinia などのストアライブラリを用います。

// Pinia/Vuex 類似のパターン
store.dispatch('fetchData').then(res => {
  // 非同期アクション完了後の処理
});

23. ルーティング戦略

クライアントサイドルーティングには Hash モードと History モードがあります。History モードは URL をきれいに保ちますが、サーバー側の設定(404 ページのリダイレクトなど)が必要です。

24. パフォーマンス最適化手法

画像ロード遅延(Lazy Load)、不要なコンポーネント再レンダリング防止(Keep-alive)、コード分割などが挙げられます。

25. Vite とビルドツール設定

最新のビルドシステムは ES Modules をネイティブサポートしており、開発時のホットリロード機能が高速化されています。テーマのカスタマイズは SASS 変数の上書きを通じて行われます。

Vue Application Architecture Concept

タグ: javascript CSS HTML5 vuejs ES6

7月6日 01:59 投稿