001 React / Vue プロジェクトでリストコンポーネントに key を記述する理由とその役割は?#
key の役割は、コンポーネントを更新する際に二つのノードが同じかどうかを判断することです。同じであれば再利用し、異なれば再作成します。これにより「その場での再利用」による副作用を避けることができます。
002 関数のスロットリングとデバウンス?#
関数のスロットリング(throttle)とデバウンス(debounce)の核心思想は、関数の呼び出しを制限することでパフォーマンスを最適化することですが、両者の概念は異なります:
-
関数のスロットリング:関数を指定した間隔で呼び出し、関数の呼び出し頻度を制限します。
-
関数のデバウンス:一定時間内に連続して呼び出された関数を一度だけ実行します。
両者の使用シーンも異なります:
-
関数のスロットリング:ページのスクロールイベントリスナー(scroll)、DOM 要素のドラッグ(mousemove)、キーボードイベント(keydown)
-
関数のデバウンス:テキスト入力の検証リクエスト送信、ウィンドウのリサイズ(resize)
003 Set、Map、WeakSet、WeakMap の違いは?#
-
Set は配列に似ていますが、メンバーの値はすべてユニークで、反復可能です。
-
WeakSet のメンバーはすべてオブジェクトであり、すべて弱い参照です。DOM ノードを保存するのに使用でき、メモリリークを引き起こしにくく、反復できません。
-
Map は本質的にキーと値のペアの集合で、反復可能です。
-
WeakMap はオブジェクトのみをキーとして受け入れ(null を除く)、他の型の値をキーとして受け入れず、キーが指すオブジェクトは反復できません。
004 Async/Await はどのようにして同期的な方法で非同期を実現するのか?#
Async/Await は自動実行される generate 関数であり、Generator の構文糖です。generate 関数の特性を利用して非同期のコードを「同期」の形式で記述します。
Generator が同期的に非同期を実現できるのは、実行を一時停止し、再開する特性と、関数内外のデータ交換およびエラーハンドリングメカニズムを持っているからです。
005 JS の非同期解決策#
-
コールバック関数、欠点:コールバック地獄、try catch でエラーを捕捉できない、return できない
-
Promise、欠点:Promise をキャンセルできない、エラーはコールバック関数で捕捉する必要がある
-
Generator、co ライブラリと組み合わせる必要がある
-
Async/await:コードが明確で、Promise のように大量の then チェーンを書く必要がなく、コールバック地獄の問題を解決しました。
006 HTTP/2 のマルチプレクシングについて簡単に説明してください#
HTTP/1 では、リクエストごとに HTTP 接続を確立するため、3 回のハンドシェイクと 4 回の切断が必要です。このプロセスは、1 回のリクエスト中にかなりの時間を占めます。Keep-Alive を有効にしても、複数の接続の問題を解決しましたが、依然として二つの効率的な問題があります:
-
シリアルファイル転送。a ファイルをリクエストすると、b ファイルは待機する必要があり、a がサーバーに接続され、サーバーがファイルを処理し、サーバーがファイルを返すという三つのステップを待ちます。
-
接続数が多すぎる。サーバーが最大同時接続数を 300 に設定した場合、ブラウザの制限により、ブラウザが発起できる最大リクエスト数は 6 です。つまり、サーバーが処理できる最大同時接続数は 50 であり、51 番目のユーザーがアクセスすると、前のリクエストの処理が完了するまで待機する必要があります。
HTTP/2 のマルチプレクシングは、上記の二つのパフォーマンス問題を解決するために設計されています。HTTP/2 では、** フレーム(frame)とストリーム(stream)** という二つの非常に重要な概念があります。フレームは最小のデータ単位を表し、各フレームはそのフレームがどのストリームに属するかを識別します。ストリームは複数のフレームで構成されるデータストリームです。マルチプレクシングは、1 つの TCP 接続内に複数のストリームが存在できることを意味し、複数のリクエストを送信でき、相手はフレーム内の識別子を通じてどのリクエストに属するかを知ることができます。この技術により、HTTP の古いバージョンにおけるヘッダーのブロッキング問題を回避し、伝送性能を大幅に向上させることができます。
007 TCP の三回のハンドシェイクと四回の切断について話してください#
三回のハンドシェイクは、クライアントとサーバーが互いに受信および送信能力に問題がないことを確認するための最小回数です。
-
最初のクライアント => サーバー、サーバーはクライアントが送信能力を持っていることを判断できます。
-
二回目のサーバー => クライアント、クライアントはサーバーが送信および受信能力を持っていることを判断できます。
-
三回目のクライアント => サーバー、双方が自分の受信および送信能力に問題がないことを確認します。
四回の切断は、TCP が全二重チャネルであるため、クライアントとサーバーが二つのチャネルを確立することを意味します:
-
チャネル 1:クライアントの出力がサーバーの入力に接続されます。
-
チャネル 2:クライアントの入力がサーバーの出力に接続されます。
二つのチャネルは同時に動作できるため、二重チャネルを閉じるには四回の切断が必要です:
-
クライアントが入力チャネルを閉じ、サーバーが出力チャネルを閉じます。
-
サーバーが入力チャネルを閉じ、クライアントが出力チャネルを閉じます。
008 TCP/IP プロトコルスタックの四層は何ですか?#
四層:アプリケーション層、トランスポート層、ネットワーク層、データリンク層。
HTTP、TCP、IP はそれぞれアプリケーション層、トランスポート層、ネットワーク層にあります。
009 URL 入力からページ表示までに何が起こるのか?#
-
DNS 解決:ドメイン名を IP アドレスに解決します。
-
TCP 接続:TCP 三回のハンドシェイク。
-
HTTP リクエストを送信。
-
サーバーがリクエストを処理し、HTTP メッセージを返します。
-
ブラウザがページを解析してレンダリングします。
-
接続を切断:TCP 四回の切断。
010 HTTPS のハンドシェイクプロセスと中間者攻撃について説明してください#
HTTPS のハンドシェイクプロセス:
-
クライアントが HTTPS の URL を使用して Web サーバーにアクセスし、サーバーとの SSL 接続を確立するよう要求します。
-
Web サーバーがクライアントのリクエストを受け取った後、サイトの証明書(公開鍵を含む)をクライアントに送信します。
-
クライアントがサイトの証明書を受け取った後、証明書の発行機関と有効期限を確認し、問題がなければランダムに秘密鍵を生成します。
-
クライアントが公開鍵を使用してセッション鍵を暗号化し、サーバーに送信します。サーバーは自分の秘密鍵を使用してセッション鍵を復号化します。
-
その後、サーバーとクライアントは秘密鍵を使用して暗号化されたデータを送信します。
HTTPS 中間者攻撃:
-
サーバーがクライアントに公開鍵を送信します。
-
攻撃者が公開鍵を傍受し、自分の手元に保持します。
-
攻撃者が偽の公開鍵を生成し、クライアントに送信します。
-
クライアントが偽の公開鍵を受け取った後、秘密鍵を暗号化してサーバーに送信します。
-
攻撃者が暗号化された秘密鍵を取得し、自分の秘密鍵を使用して本物の秘密鍵を復号化します。
-
同時に偽の暗号化された秘密鍵を生成し、サーバーに送信します。
-
サーバーが秘密鍵を使用して偽の秘密鍵を復号化します。
-
サーバーが暗号化された秘密鍵を使用して情報を送信します。
防止方法:サーバーがブラウザに公開鍵を送信する際に CA 証明書を追加し、ブラウザが CA 証明書の有効性を検証できるようにします。
011 Http と Https の違いは?#
Http:ハイパーテキスト転送プロトコル、平文転送、データは暗号化されておらず、安全性が低く、ポート 80 を使用します。
Https:セキュアソケットハイパーテキスト転送プロトコル、SSL/TSL 証明書を持ち、データ転送プロセスは暗号化されており、安全性が高く、ポート 443 を使用し、Http よりもサーバーリソースを多く消費します。
012 再描画と再フロー(Repaint & Reflow)について説明し、最適化方法を教えてください#
ブラウザのレンダリングメカニズム
ブラウザはフローレイアウトモデルを採用しています。ブラウザは HTML を DOM に、CSS を CSSOM に解析し、DOM と CSSOM を統合してレンダリングツリー(Render Tree)を生成します。Render Tree があれば、すべてのノードのスタイルがわかり、ページ上のサイズと位置を計算し、最後にノードをページに描画します。
再描画
ノードの幾何学的属性が変更されたり、スタイルが変更されたりしてもレイアウトに影響を与えない場合、これを再描画と呼びます。例えば、outline、visibility、color、background-color などです。
再フロー
レイアウトや幾何学的属性を変更する必要がある場合、これを再フローと呼びます。再フローはブラウザのパフォーマンスに影響を与える重要な要因です。なぜなら、その変化はページのレイアウト更新に関与するからです。ある要素の再フローは、そのすべての子要素や直後のノード、祖先ノード要素の再フローを引き起こす可能性があります。
再フローは必ず再描画を引き起こしますが、再描画は必ずしも再フローを引き起こすわけではありません。
再描画と再フローを減らす方法
CSS
-
top/left の代わりに transform を使用します。
-
display: none の代わりに visibility を使用します。前者は再描画を引き起こすだけですが、後者はレイアウトを変更するため再フローを引き起こします。
-
テーブルレイアウトの使用を避けます。小さな変更がテーブル全体の再レイアウトを引き起こす可能性があります。
-
多層のインラインスタイルを設定するのを避け、ノードの階層が多すぎないようにします。
-
できるだけ具体的な CSS セレクタを書くのを避けます。
-
position 属性が absolute または fixed の要素にアニメーション効果を適用し、他の要素のレイアウトに影響を与えないようにします。これにより、再描画だけで済み、再フローは発生しません。
-
CSS 表現式の使用を避けます。再フローを引き起こす可能性があります。
-
頻繁に再描画または再フローが発生するノードをレイヤーとして設定します。レイヤーはそのノードのレンダリング動作が他のノードに影響を与えるのを防ぎます。例えば、will-change、video、iframe などのタグは、ブラウザが自動的にそのノードをレイヤーに変えます。
-
CSS3 ハードウェアアクセラレーション(GPU アクセラレーション)を使用すると、transform、opacity などのアニメーションが再フローや再描画を引き起こさないようにできます。
JavaScript
-
スタイルを頻繁に操作するのを避け、可能であれば一度に style 属性を再書き込みするか、スタイルリストをクラスとして定義し、一度にクラス属性を変更します。
-
DOM を頻繁に操作するのを避け、documentFragment を作成し、その上ですべての DOM 操作を適用し、最後にそれを文書に追加します。
-
再フローや再描画を引き起こす属性を頻繁に読み取るのを避け、実際に何度も使用する必要がある場合は、変数にキャッシュします。
-
複雑なアニメーションを持つ要素には絶対位置を使用し、文書フローから外します。そうしないと、親要素や後続の要素が頻繁に再フローを引き起こします。
013 opacity: 0、visibility: hidden、display: none の利点と適用シーン#
-
opacity: 0 はレイヤーを再構築し、パフォーマンスが高いです。
-
visibility: hidden は再描画を引き起こし、再フローよりもパフォーマンスが高いです。
-
display: none は再フローを引き起こし、パフォーマンスコストが大きく、再フローはそのすべての子要素や直後のノード、祖先ノード要素の位置や属性を再計算する可能性があります。
014 同一オリジンポリシーとは?クロスオリジンを解決する方法は?#
同一オリジンとは「プロトコル + ドメイン + ポート」の三者が同じことを指します。
クロスオリジンを解決する方法:
-
CORS(クロスオリジンリソースシェアリング)
-
Nginx リバースプロキシ
-
JSONP:JSONP は主に script タグにクロスオリジン制限がない特性を利用して実現され、GET メソッドのみをサポートします。
015 cookie と token はどちらもヘッダーに保存されますが、なぜ token がハイジャックされないのですか?#
-
XSS:クロスサイトスクリプティング攻撃で、攻撃者がさまざまな方法で悪意のあるコードを他のユーザーのページに注入します。これにより、スクリプトを通じて情報を取得したり、リクエストを発起したりする操作が可能になります。
-
CSRF:クロスサイトリクエストフォージェリ。簡単に言うと、攻撃者が技術的手段を使用してユーザーのブラウザを騙し、以前に認証されたサイトにアクセスさせて操作を実行させることです(メールを送信したり、メッセージを送信したり、財産操作を行ったりします)。ブラウザが以前に認証されたため、アクセスされたサイトは本物のユーザーの操作と見なして実行します。CSRF はユーザーの情報を取得することはできず、ユーザーのブラウザを騙してその名義で操作を行わせるだけです。
上記の二つの攻撃方法は、XSS 攻撃を受けた場合、token でも cookie でも取得されるため、XSS 攻撃に対しては cookie と token に違いはありません。しかし、CSRF に関しては違いがあります。
上記の CSRF 攻撃の例:
-
cookie:ユーザーがリンクをクリックし、cookie が無効でない場合、リクエストを発起した後、バックエンドはユーザーの正常な操作だと考え、請求を行います。
-
token:ユーザーがリンクをクリックしても、ブラウザは自動的に token を持っていかないため、リクエストを送信しても、バックエンドの token 検証は通過せず、請求は行われません。
これが、cookie をハイジャックしても token をハイジャックしない理由です。
拡張:防御方法は?
XSS:すべての入力可能な場所で入力データを処理しない場合、XSS 脆弱性が存在します。XSS 攻撃を防ぐ最も簡単で直接的な方法は、ユーザーの入力をフィルタリングすることです。
CSRF:
-
CAPTCHA
-
HTTP Referer フィールドの検証
-
cookie ではなく token を追加します。
016 よく使う DOM 操作メソッドは?#
getElementById
、getElementsByClassName
、getElementsByTagName
、getElementsByName
、querySelector
、querySelectorAll
、getAttribute
、setAttribute
017 ブラウザのキャッシュメカニズム#
キャッシュの位置から見ると、四種類に分かれ、それぞれ優先順位があります。キャッシュを順に探してもヒットしない場合のみ、ネットワークをリクエストします。
-
Service Worker
-
Memory Cache
-
Disk Cache
-
Push Cache
Service Worker はブラウザの背後で動作する独立したスレッドです。Service Worker を使用する場合、伝送プロトコルは必ず HTTPS でなければなりません。なぜなら、Service Worker にはリクエストのインターセプトが含まれるため、セキュリティを確保するために HTTPS プロトコルを使用する必要があります。Service Worker のキャッシュは、ブラウザの他の組み込みキャッシュメカニズムとは異なり、どのファイルをキャッシュするか、キャッシュをどのように照合するか、キャッシュをどのように読み取るかを自由に制御できます。また、キャッシュは持続的です。
Service Worker によるキャッシュ機能の実装は、一般的に三つのステップに分かれます。まず、Service Worker を登録し、install イベントをリッスンした後、必要なファイルをキャッシュします。次回ユーザーがアクセスしたときに、リクエストをインターセプトしてキャッシュが存在するかどうかを確認し、キャッシュが存在すれば直接キャッシュファイルを読み取り、存在しなければデータをリクエストします。
Memory Cache は、現在のページで取得したリソースを主に含みます。例えば、ページ上で既にダウンロードされたスタイル、スクリプト、画像などです。メモリ内のデータを読み取るのはディスクよりも速く、メモリキャッシュは読み取り効率が高いですが、持続性が非常に短く、プロセスの解放とともに解放されます。一度タブページを閉じると、メモリ内のキャッシュも解放されます。
Disk Cache は、ハードディスクに保存されるキャッシュで、読み取り速度は遅いですが、すべてをディスクに保存できます。Memory Cache に比べて容量と保存の持続性に優れています。ほとんどのキャッシュは Disk Cache から来ています。
Push Cache(プッシュキャッシュ)は HTTP/2 の内容で、上記の三種類のキャッシュがヒットしない場合にのみ使用されます。セッション(Session)内にのみ存在し、セッションが終了すると解放され、キャッシュ時間も非常に短く、Chrome ブラウザでは約 5 分程度です。また、HTTP ヘッダーのキャッシュ指示を厳密に実行するわけではありません。
018 call と apply の違いは?どちらの方がパフォーマンスが良いか?#
Function.prototype.apply と Function.prototype.call の役割は同じですが、渡す引数が異なります:
-
最初の引数は、関数体内の this の指向を指定します。
-
二番目の引数から異なり、apply はインデックス付きの集合、配列または類似配列を渡し、apply はそれを関数の引数として渡します。call は二番目から渡す引数が不定で、すべて関数の引数として渡されます。
call は apply よりもパフォーマンスが良いです。なぜなら、内部で apply の二番目の引数を解構する操作が一回少ないからです。
ES6 でスプレッド演算子が導入された後、引数が配列であっても call を使用できます:
let params = [1, 2, 3, 4]
xx.call(obj, ...params)
019 なぜ通常、データ埋め込みリクエストを送信する際に 1x1 ピクセルの透明な gif 画像を使用するのか?#
-
クロスオリジンの問題がない
-
ページの読み込みをブロックせず、ユーザーの体験に影響を与えない(JS/CSS ファイルリソースの報告を除く)
-
すべての画像の中で、最もサイズが小さい(PNG/JPG と比較)
020 JS のデータ型はいくつありますか?#
七つ:Number、String、Boolean、Object、Null、Undefined、Symbol
021 Symbol の使用シーンは?#
-
マジック文字を排除する
-
Symbol 値をプロパティ名として使用して上書きを避ける
-
クラスのプライベートメソッドを模倣する:ES6 のクラスにはプライベートメソッドやプライベート変数を宣言するための private キーワードがありませんが、Symbol のユニーク性を利用して模倣できます。
const speak = Symbol();
class Person {
[speak]() {
...
}
}
022 HTTP の一般的なステータスコード#
HTTP ステータスコードは 5 種類に分類されます:
分類 | 分類説明 |
---|---|
1** | 情報、サーバーがリクエストを受け取り、リクエスターに操作を続行する必要がある |
2** | 成功、操作が正常に受信され、処理された |
3** | リダイレクト、リクエストを完了するためにさらなる操作が必要 |
4** | クライアントエラー、リクエストに構文エラーが含まれているか、リクエストを完了できない |
5** | サーバーエラー、サーバーがリクエストを処理する際にエラーが発生した |
023 メディアクエリとは?レスポンシブデザインとアダプティブデザインの違いは?#
メディアクエリ#
メディアクエリは、異なる条件下で異なるスタイルを使用できるようにし、ページが異なる端末デバイスで異なるレンダリング効果を達成します。
原理:メディアクエリ(メディアタイプとメディア特性を含む)に使用する式を追加でき、これにより異なるスタイルシートを選択し、異なる画面解像度に自動的に適応します。
- メディアタイプ:異なるデバイスを異なるタイプに分類します。
-
all (すべてのデバイス)
-
print (印刷デバイス)
-
screen (コンピュータの画面、タブレット、スマートフォン)
- メディア特性:デバイスの特徴を説明するために使用されます。例えば、幅や高さなどです。
-
width ウェブページの表示領域が設定された幅と完全に等しい
-
height ウェブページの表示領域が設定された高さと完全に等しい
-
max-width /max-height ウェブページの表示領域が設定された幅以下である
-
min-width /min-width ウェブページの表示領域が設定された幅以上である
-
orientation: portrait (縦向き) | landscape (横向き)
レスポンシブデザインとアダプティブデザイン#
- レスポンシブデザインとアダプティブデザインの違いは?
-
レスポンシブデザイン:レスポンシブ開発は一つのインターフェースを作成し、ビューポートの解像度を検出して、異なるクライアントに対してコード処理を行い、異なるレイアウトやコンテンツを表示します。
-
アダプティブデザイン:アダプティブは複数のインターフェースを開発する必要があり、ビューポートの解像度を検出して、現在アクセスしているデバイスが PC、タブレット、またはスマートフォンであるかを判断し、異なるページを返します。
- レスポンシブデザインとアダプティブデザインの選択方法は?
-
ページがそれほど複雑でない場合、レスポンシブレイアウトを使用します。
-
ページに情報が多く、レイアウトが複雑な場合、アダプティブレイアウトを使用します。
- レスポンシブデザインとアダプティブデザインの長所と短所は?
レスポンシブレイアウト
長所:柔軟性が高く、多デバイス表示の適用問題を迅速に解決できる。
短所:効率が低く、各デバイスの互換性作業が大きい。コードが冗長で、読み込み時間が長くなる可能性がある。ある程度、サイトの元のレイアウト構造が変更される。
アダプティブレイアウト
長所:サイトの複雑さに対する互換性が高く、コードがより効率的です。
短所:同じサイトに対して異なるデバイス用に異なるページを開発する必要があり、開発コストが増加します。
024 BFC について説明し、その応用#
BFC(Formatting context)はブロックフォーマットコンテキストであり、ページのボックスモデルレイアウトにおける CSS レンダリングモードの一種で、独立したコンテナに相当し、その中の要素と外部の要素は互いに影響を与えません。
BFC を作成する方法は:
-
float 浮動
-
position が absolute または fixed
-
display がテーブルレイアウトまたはフレックスレイアウト
-
overflow が visible 以外の値(hidden、auto、scroll)
BFC の特性:
-
内部のボックスは垂直方向に一つずつ配置されます。
-
垂直方向の距離は margin によって決まります。
-
BFC の領域は浮動要素の領域と重ならない。
-
BFC の高さを計算する際、浮動要素も計算に参加します。
-
BFC はページ上の独立したコンテナであり、その中の子要素は外部の要素に影響を与えません。
BFC の主な役割は:
-
浮動をクリアする
-
同じ BFC コンテナ内の隣接要素間の外側のマージン重複問題を防ぐことです。
025 イベントループの概要?#
イベントループは、ブラウザや Node の JS 単一スレッド実行時にブロックしないようにするメカニズムで、私たちがよく使用する非同期の原理です。
JS では、タスクは二種類に分けられます。一つはマクロタスク(MacroTask)、もう一つはマイクロタスク(MicroTask)です。
マクロタスク(MacroTask):setTimeout、setInterval、setImmediate、I/O、UI Rendering。
マイクロタスク(MicroTask):Promise、MutationObserver、Process.nextTick(Node 独自)。
マクロタスクはマクロタスクキューに追加され、マイクロタスクはマイクロタスクキューに追加されます。
JS にはメインスレッドと呼び出しスタックがあり、すべてのタスクは呼び出しスタックに追加され、メインスレッドの実行を待ちます。
JS の呼び出しスタックは後入れ先出しのルールを採用しており、タスクが実行されるとスタックのトップに追加され、実行スタックが完了すると、スタックのトップから取り出され、スタックが空になるまで続きます。
JS コードの具体的な流れ:
-
グローバルスクリプトの同期コードを実行します。これらの同期コードには、一部は同期文であり、一部は非同期文です。
-
グローバルスクリプトのコードが実行されると、呼び出しスタックは空になります。
-
マイクロタスクキューから先頭のコールバックタスクを取り出し、呼び出しスタックに追加して実行し、実行が完了するとスタックのトップから取り出し、キューの長さが 1 減ります。
-
先頭のタスクを取り出し、呼び出しスタックに追加して実行し、これを繰り返します。マイクロタスクキュー内のすべてのタスクが実行されるまで続けます。マイクロタスクを実行している間に新しいマイクロタスクが生成された場合、それはキューの末尾に追加され、このサイクル内で呼び出されて実行されます。
-
マイクロタスクキュー内のすべてのタスクが実行され、マイクロタスクキューが空になり、呼び出しスタックも空になります。
-
マクロタスクキューから先頭のタスクを取り出し、実行します。
-
実行が完了すると、呼び出しスタックは空になります。
-
マイクロタスクキュー内のタスクを再度実行し、マクロタスクキューのタスクを実行します。
重点:
-
マイクロタスクキュー内のすべてのタスクは順次取り出されて実行され、キューの長さが空になるまで続きます。
-
マクロタスクキューは一度にキューから一つのタスクを取り出して実行し、実行が完了した後にマイクロタスクキュー内のタスクを実行します。
026 ファーストスクリーンの読み込み速度を向上させる方法は?#
-
コードを圧縮して、コードのサイズを小さくします。
-
ルーティングの遅延読み込み。
-
第三者ライブラリを CDN から導入し、コードのサイズを小さくしてファーストスクリーンの読み込み速度を向上させます。
-
SSR サーバーサイドレンダリング。
027 対称暗号と非対称暗号は?#
対称暗号方式は、同じ鍵を使用してメッセージを暗号化および復号化します。システムの機密性は主に鍵の安全性によって決まり、アルゴリズムの機密性とは関係ありません。
非対称暗号方式は、公開鍵で暗号化し、秘密鍵で復号化します。非対称暗号方式を使用することで、通信の安全性を強化できます。
一般的な対称暗号アルゴリズムには、DES、AES があります。
非対称暗号アルゴリズムには、RSA があります。
ハッシュは暗号化と見なされますか?見なされません。ハッシュは不可逆であり、暗号化は暗号化されたデータから復元できるべきです。
028 webpack の loader と plugin の違いは?#
loader は変換器であり、A ファイルを B ファイルにコンパイルします。例えば、A.less を A.css に変換する単純なファイル変換プロセスです。
plugin は拡張器であり、webpack 自体を豊かにし、loader の終了後、webpack のパッキング全体のプロセスに対して機能します。ファイルを直接操作するのではなく、イベントメカニズムに基づいて動作し、webpack のパッキングプロセスの特定のノードをリッスンして広範なタスクを実行します。
029 フレックスボックスの flex: 0 1 auto は何を意味し、left と right ボックスの幅は?#
三つのパラメータはそれぞれ flex-grow、flex-shrink、flex-basis に対応し、デフォルト値は 0 1 auto です。
-
flex-grow プロパティは、プロジェクトの拡大比率を定義し、デフォルトは 0 です。つまり、余剰スペースがあっても拡大しません。
-
flex-shrink プロパティは、プロジェクトの縮小比率を定義し、デフォルトは 1 です。つまり、スペースが不足している場合、そのプロジェクトは縮小します。
-
flex-basis プロパティは、余分なスペースが割り当てられる前に、プロジェクトが占める主軸のスペース(メインサイズ)を定義します。
問題 1、flex-shrink を考慮して、最終的な left と right の幅を求めます。
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
<style>
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
flex: 1 2 500px;
background: red;
}
.right {
flex: 2 1 400px;
background: blue;
}
</style>
対応する問題:
-
子項目のオーバーフロー幅は:
500 + 400 - 600 = 300
-
left の収縮比率:
(500 * 2) / (500 * 2 + 400 * 1) = 0.7143
-
right の収縮比率:
(400 * 1) / (500 * 2 + 400 * 1) = 0.2857
対応する:
-
left の収縮幅:
0.7143 * 300 = 214.29
-
right の収縮幅:
0.2857 * 300 = 85.71
したがって:
-
left の最終幅:
500 - 214.29 = 285.71
-
right の最終幅:
400 - 85.71 = 314.29
問題 2、flex-grow を考慮して left と right の幅を求めます。
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
<style>
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
flex: 1 2 300px;
background: red;
}
.right {
flex: 2 1 200px;
background: blue;
}
</style>
残りのスペース:600 - (300 + 200) = 100
子要素の flex-grow の値はそれぞれ 1 と 2 で、残りのスペースは 3 等分されます:100 / 3 = 33.3333333
したがって:
-
left の最終幅:
300 + 1 * 33.33 = 333.33
-
right の最終幅:
200 + 2 * 33.33 = 266.67
拡張:flex:1
は何を意味するのか? flex:1 1 0%
と同じです。
030 require と import の違いは?#
-
import は es6 の構文標準であり、require は AMD 規範の導入方法です。
-
import はコードコンパイル時に読み込まれるため、ファイルの先頭に配置する必要がありますが、require はコード実行時に読み込まれるため、理論的にはコードの任意の場所で使用できます。そのため、import の方がパフォーマンスが良いです。
-
import で導入されたオブジェクトが変更されると、元のオブジェクトも変更され、浅いコピーに相当します。require で導入されたオブジェクトが変更されると、元のオブジェクトは変更されず、公式には値のコピーと称され、深いコピーと理解できます。
-
import は tree-shaking(JavaScript コンテキスト内で未参照のコードを削除する)に有利であり、require は tree-shaking に対して友好的ではありません。
-
import はコード分割(コードを異なるバンドルに分離し、必要に応じてロードまたは並行してロードできるようにする)をトリガーしますが、require はトリガーしません。
現在、すべてのエンジンはまだ import を実装しておらず、import は最終的に require にトランスコードされます。webpack のパッキングでは、import と require はどちらも webpack_require に変わります。
031 H5 の 6 つの新機能は?#
-
セマンティックタグ、例えば header、footer、section、article などのセマンティックタグの役割:ページの読みやすさを向上させ(構造が強化され)、SEO に有利であり、スクリーンリーダーを使用する人にとってもより親切です。
-
新しいメディア要素、audio と video タグは、音声やビデオストリームを簡単に出力でき、ファイル情報を取得する便利な API を提供します。
-
描画用の canvas 属性。Canvas API は、JavaScript と HTML の canvas 要素を使用してグラフィックスを描画する方法を提供します。アニメーション、ゲーム画面、データ可視化、画像編集、リアルタイムビデオ処理などに使用できます。
-
新しいローカルストレージ方式:sessionStorage、localStorage。sessionStorage はセッションレベルのデータを保存するために使用され、セッションが終了するとデータは消失し、期限を設定できません。localStorage は永続的に保存する必要があるデータを保存するために使用され、手動で削除しない限り、データは消失しません。
-
新しい技術:webworker、websocket。 webworker:マルチスレッドプログラミングに使用され、websocket:クライアントとサーバー間の双方向データ通信プロトコルです。
-
新しいフォームコントロール:calendar、date、time、email、url、search。
032 CSS3 の新機能は?#
-
セレクタ
-
ボーダーと角丸
-
背景とグラデーション
-
トランジション
-
変換
-
アニメーション
033 ES6 の新機能は?#
-
変数宣言:const と let
-
テンプレート文字列
-
アロー関数
-
関数のデフォルト引数
-
スプレッド演算子
-
オブジェクトと配列の分割代入
-
データ型 Symbol
-
データ構造 Set と Map
-
Proxy 代理と Reflect 反射
-
Promise オブジェクト
-
Iterator イテレーター
-
Generator 関数
-
Async/Await
-
Class クラス継承
-
モジュールの構文 import/export
034 オブジェクトをマージする方法は?#
-
スプレッド演算子:
const newObj = { ...obj1, ...obj2 };
-
Object.assign()
:const newObj = Object.assign(obj1, obj2);
違い:スプレッド演算子は新しいオブジェクトを返しますが、Object.assign()
関数は最初の引数のオブジェクトを変更します。
035 e.target と e.currentTarget は?#
e.target はイベントを引き起こしたオブジェクトの参照であり、イベントが発生した要素です。
e.currentTarget はイベントがバインドされた要素を指します。
036 アロー関数と通常の関数(function)の違いは?コンストラクタ関数(function)は new を使用してインスタンスを生成できますが、アロー関数はできますか?なぜですか?#
アロー関数は通常の関数と比較して、以下の点で異なります:
-
関数体内の this オブジェクトは、定義時に存在するオブジェクトであり、使用時に存在するオブジェクトではありません。
-
arguments オブジェクトを使用できません。このオブジェクトは関数体内には存在しません。使用する必要がある場合は、rest パラメータを代わりに使用できます。
-
yield コマンドを使用できないため、アロー関数は Generator 関数として使用できません。
-
new コマンドを使用できません。なぜなら:
-
自分自身の this がなく、call や apply を呼び出すことができません。
-
prototype プロパティがなく、new コマンドが実行されるときにコンストラクタ関数の prototype が新しいオブジェクトの proto に割り当てられる必要があります。
037 var、let、const の違いの実装原理は?#
var と let/const の違い:
-
ブロックスコープ:var で宣言された変数はブロックスコープが存在せず、グローバル範囲内で有効ですが、let/const で宣言された変数はそのコードブロック内でのみ有効です。
-
変数の昇格が存在しない:var で定義された変数は先に使用でき、後で宣言できますが、let/const は先に宣言し、後で使用する必要があります。
-
一時的死区:let/const で宣言された変数は一時的死区が存在し、ブロックスコープ内に存在する限り、その変数はその領域にバインドされ、外部の影響を受けません。
-
重複宣言ができない:let/const は同じスコープ内で同じ変数を重複して宣言することを許可しません。
-
let/const で宣言されたグローバル変数は、トップレベルオブジェクトの下に掛からない。
const:
-
const は宣言後にすぐに値を割り当てる必要があり、そうしないとエラーが発生します。
-
const の単純な型は一度宣言すると変更できませんが、複雑な型(配列、オブジェクトなど)はポインタの指向を変更できず、内部データは変更できます。
let は一般的に変数を宣言するために使用され、const は定数関数を宣言します。
038 シームレスなスライドショーを設計して実装する方法は?#
無限スライドショーの基本プラグインはすでに実現できますが、ネイティブコードでシームレスなスクロールを実現するための考え方を提案できます。スライドショーは基本的に ul ボックス内の li 要素にあります。
-
まず、最初の li 要素と最後の li 要素を取得します。
-
最初の li 要素と最後の li 要素をクローンします。
-
それぞれ lastli の後ろと firstli の前に挿入します。
-
次に、スクロールイベントをリッスンし、スライド距離が x または -x を超えた場合、次の画像にジャンプするか、前の画像にジャンプします(ここでスライド距離を設定するのが最善です)。
-
最後の画像をスライドさせたときに、最後の画像とクローンされた最初の画像のシームレスな変換を実現します。クローンされた最初の画像に到達したときに停止し、実際の最初の画像に切り替えます。これにより、無限スライドが実現されます。前方にスライドする場合も同様です。
039 ES6 コードを ES5 コードに変換する実装の考え方は?#
ES6 コードを ES5 コードに変換するには、Babel の実装方法を参考にできます。Babel はどのようにして ES6 を ES5 に変換するのでしょうか。その大まかな流れは三つのステップに分かれます:
-
コード文字列を抽象構文木(AST)に解析します。
-
AST を処理します。この段階で、ES6 コードを対応する ES5 コードに変換できます。
-
処理された AST に基づいて、再度コード文字列を生成します。
040 this の指向を変更する方法とその違いは?#
三つの方法:call、apply、bind
call と apply の違い:受け取る引数が異なります。call と apply の最初の引数は関数の実行の作用域 this であり、call メソッドの後続の引数は一つずつ列挙され、apply メソッドの二番目は引数の配列です。
bind と call、apply の違い:bind の戻り値は関数であり、call と apply は即座に呼び出されます。
041 モバイル端末の Retina スクリーンで 1px ピクセルの問題を解決する方法は?#
-
擬似要素 + transform scaleY (.5)
-
border-image
-
background-image
-
box-shadow
042 配列に 10 万個のデータがある場合、最初の要素と 10 万番目の要素を取得する時間の差はどのくらいですか?#
配列はインデックスに基づいて対応する要素を直接取得できるため、どの位置の要素を取得する場合でも時間の計算量は O (1) です。
結論:消費時間はほぼ同じであり、差異は無視できる。
043 for in と for of の違いは?#
両者はどちらも反復に使用できますが、for in は配列のインデックス(index)を反復し、for of は配列の要素値(value)を反復します。
for in はオブジェクトの反復に適しており、もちろん配列を反復することもできますが、いくつかの問題が発生する可能性があります。例えば:
-
index インデックスは文字列型の数字であり、直接的に幾何学的演算を行うことができません。
-
反復順序は実際の配列の内部順序とは異なる可能性があります。
-
for in を使用すると、配列のすべての列挙可能なプロパティ、原型を含むすべてのプロパティが反復されます。 原型メソッドやプロパティを反復したくない場合は、ループ内で判断し、hasOwnProperty () メソッドを使用してそのプロパティがオブジェクトのインスタンスプロパティであるかどうかを判断できます。
for (let index in arr) {
if (arr.hasOwnProperty(index)) {
}
}
for of は配列の要素値を反復し、for of は配列内の要素のみを反復し、原型プロパティやインデックスは含まれません。
まとめ:
-
for in は配列のインデックス(すなわちキー名)を反復し、for of は配列の要素値を反復します。
-
for in は常にオブジェクトのキーまたは配列、文字列のインデックスを取得します。
-
for of は常にオブジェクトの値または配列、文字列の値を取得します。
044 クロージャとは?クロージャを使用する際に注意すべきことは?#
JavaScript において、関数内部はグローバル変数に直接アクセスできますが、関数外部からは関数内のローカル変数を読み取ることはできません。クロージャとは、他の関数のスコープ内の変数にアクセスする権限を持つ関数のことを指し、他の関数内部の変数を読み取ることができる関数です。
クロージャを使用する際に注意すべきことは?
-
コードのメンテナンスが難しくなる:クロージャ内部は上位スコープにアクセスでき、上位スコープのプライベート変数を変更できるため、使用には注意が必要であり、上位スコープのプライベート変数の値を随意に変更しないようにします。
-
メモリリーク:クロージャは関数内の変数をメモリに保持するため、メモリ消費が大きくなります。したがって、クロージャを乱用しないようにし、不要になったメモリは適時解放する必要があります。これを怠るとメモリリークを引き起こす可能性があります。
-
this の指向:クロージャの this は window を指します。
クロージャの応用シーン:コールバック、IIFE、関数のデバウンス、スロットリング、カリー化、モジュール化。
045 react-router の <Link>
タグと <a>
タグの違いは?#
最終的にレンダリングされる DOM から見ると、両者はリンクであり、どちらも <a>
タグです。違いは:
-
<Link>
は react-router でルーティングのジャンプを実現するリンクであり、一般的に<Route>
と組み合わせて使用されます。react-router はそのデフォルトのリンクジャンプ動作を引き継ぎ、従来のページジャンプとは異なり、<Link>
の「ジャンプ」動作は、対応する<Route>
に一致するページコンテンツの更新のみをトリガーし、ページ全体をリフレッシュすることはありません。 -
<a>
タグは通常のハイパーリンクであり、現在のページから href が指す別のページにジャンプするために使用されます(アンカーの場合を除く)。
046 遅延読み込みを実現する方法は?#
ルーティングの遅延読み込み:React/Vue のような SPA(シングルページアプリケーション)では、アプリケーションをパッキング構築する際、JS パッケージが非常に大きくなり、ページの読み込みに影響を与えます。ルーティングの遅延読み込みは、異なるルートに対応するコンポーネントを異なるコードブロックに分割し、ルートがアクセスされたときにのみ対応するコンポーネントを読み込むことができ、より効率的になります。
Vue ルーティングの遅延読み込みの実装:
Vue において、Vue Router は動的インポートをサポートしており、静的インポートの代わりに動的インポートを使用できます。
// import UserDetails from './views/UserDetails'
// 替換成
const UserDetails = () => import('./views/UserDetails')
コンポーネントをグループごとに分割し、特定のルート下のすべてのコンポーネントを同じ非同期ブロック(chunk)にパッケージ化したい場合は、名前付きチャンクを使用し、特別なコメント構文を使用してチャンク名を提供します(Webpack > 2.4 が必要です)。webpack は任意の非同期モジュールを同じブロック名で組み合わせて同じ非同期ブロックにします。
const UserDetails = () => import(/* webpackChunkName: "group-user" */ './UserDetails.vue')
const UserDashboard = () => import(/* webpackChunkName: "group-user" */ './UserDashboard.vue')
const UserProfileEdit = () => import(/* webpackChunkName: "group-user" */ './UserProfileEdit.vue')
React でのルーティングの遅延読み込みの実装:
-
React.lazy() + Suspense
を使用してコンポーネントの動的読み込みを実現します。 -
import()
でパッキングを分割します。
047 MVVM とは?#
MVVM は Model-View-ViewModel の略で、MVC の Controller を ViewModel に進化させたものです。Model 層はデータモデルを表し、View は UI コンポーネントを表し、ViewModel は View と Model 層の橋渡しをします。データは ViewModel 層にバインドされ、自動的にデータがページにレンダリングされ、ビューが変化すると ViewModel 層に通知されてデータが更新されます。
048 Vue の親コンポーネントと子コンポーネントのライフサイクルフックの実行順序は?#
-
ロードレンダリングプロセス:親 beforeCreate -> 親 created -> 親 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 親 mounted
-
子コンポーネントの更新プロセス:親 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 親 updated
-
親コンポーネントの更新プロセス:親 beforeUpdate -> 親 updated
-
廃棄プロセス:親 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 親 destroyed
049 なぜ Vuex のミューテーションと Redux のリデューサーでは非同期操作ができないのか?#
状態を変更する関数は純粋な関数でなければなりません。純粋な関数は、同じ入力に対して常に同じ出力を返し、何の副作用もありません。 非同期である場合、追加の副作用が導入され、変更後の状態が予測不可能になります。
非同期操作が成功するか失敗するかは予測できず、非同期操作がいつ行われるかも予測できません。非同期操作が成功または失敗した場合、commit(ミューテーション)や dispatch(アクション)を行わないと、Vuex や Redux は非同期の結果を捕捉できず、適切な操作を行うことができません。
拡張:なぜ Redux ではリデューサーを純粋な関数として設計するのか?
答え:純粋な関数は、同じ入力に対して常に同じ出力を返し、副作用を生じさせません。Redux の設計思想は副作用を生じさせず、データ変更の状態を追跡可能にするため、Redux では至る所に純粋な関数が存在します。
050 Vue では、子コンポーネントが親コンポーネントから渡された Prop を変更できないのはなぜですか?#
データの一方向の流れを保証し、データの追跡を容易にし、データの混乱を避けるためです。
051 双方向バインディングと Vuex は衝突しますか?#
厳格モードで Vuex を使用する場合、ユーザーが入力すると、v-model はプロパティ値を直接変更しようとしますが、この変更はミューテーション内で行われていないため、エラーが発生します。コンポーネント内で Vuex の state を使用する必要がある場合、二つの解決策があります:
-
input に value(Vuex の state)をバインドし、input の change または input イベントをリッスンし、イベントコールバック内でミューテーションを呼び出して state の値を変更します。
-
setter を持つ双方向バインディングの計算プロパティを使用します。
<input v-model="message" />
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.dispatch('updateMessage', value);
}
}
}
mutations: {
UPDATE_MESSAGE (state, v) {
state.obj.message = v;
}
}
actions: {
update_message ({ commit }, v) {
commit('UPDATE_MESSAGE', v);
}
}
052 Vue のリアクティブ原理において Object.defineProperty にはどのような欠陥がありますか?なぜ Vue3.0 では Proxy を採用し、Object.defineProperty を廃止したのですか?#
-
Object.defineProperty は配列のインデックスの変化を監視できず、配列のインデックスを通じて要素を追加すると、リアルタイムで反応しません。
-
Object.defineProperty はオブジェクトのプロパティをハイジャックすることしかできず、各オブジェクトの各プロパティを遍歴する必要があるため、プロパティ値がオブジェクトである場合、深く遍歴する必要があります。Proxy はオブジェクト全体をハイジャックし、新しいオブジェクトを返します。
-
Proxy はオブジェクトだけでなく、配列や動的に追加されるプロパティもハイジャックできます。
053 Vue の computed はどのように実装されていますか?#
computed は、コンポーネントインスタンスに代理される形で実装されており、計算プロパティを読み取ると、内部の getter が実行され、ユーザー定義のメソッドではありません。
computed は内部で惰性ウォッチャーを実装しており、インスタンス化時には評価されず、内部で dirty プロパティを使用して計算プロパティが再評価される必要があるかどうかをマークします。computed に依存する任意の状態が変化すると、この惰性ウォッチャーに通知され、dirty プロパティが true に設定されます。したがって、再度この計算プロパティを読み取ると、再評価が行われます。
惰性ウォッチャー / 計算プロパティは、作成時には評価されず、使用時に評価されます。
054 Vue の computed と watch の違いは?#
computed:計算プロパティは、data 内の既知の値から得られる新しい値です。この新しい値は、既知の値の変化にのみ依存し、他の無関係なデータの変化には影響されません。計算プロパティは data 内には存在しません。他者の変化が自分に影響を与えます。
watch:監視器はデータの変化を監視し、監視するデータは data 内の既知の値です。自分の変化が他者に影響を与えます。
-
watch が得意なシーン:一つのデータが複数のデータに影響を与える。
-
computed が得意なシーン:一つのデータが複数のデータに影響を受ける。
055 v-if、v-show、v-html の原理は?どのように封装されていますか?#
-
v-if は addIfCondition メソッドを呼び出し、vnode を生成する際に対応するノードを無視し、render の際にはレンダリングされません。
-
v-show は vnode を生成し、render の際にも実際のノードとしてレンダリングされますが、render プロセス中にノードの属性を変更し、display 属性値を変更します。
-
v-html はノード下のすべてのノードを先に削除し、html メソッドを呼び出し、addProp を通じて innerHTML 属性を追加します。根本的には、v-html の値として innerHTML を設定します。
056 v-show と v-if ディレクティブの共通点と違いは?#
共通点:どちらも要素の表示と非表示を制御できます。
違い:実装の本質的な方法が異なります。v-show は本質的に CSS の display を none に設定して非表示にし、隠すだけで、初回のコンパイルは一度だけ行われます。v-if は動的に DOM ツリーに DOM 要素を追加または削除し、初期値が false の場合はコンパイルされず、v-if は頻繁に破棄と作成を行うため、パフォーマンスを消費します。
まとめ:特定のノードを頻繁に切り替える必要がある場合は v-show を使用します(切り替えコストが比較的小さく、初期コストが比較的大きい)。特定のノードを頻繁に切り替える必要がない場合は v-if を使用します(初期レンダリングコストが比較的小さく、切り替えコストが比較的大きい)。
057 Vue コンポーネント間の通信方法は?#
-
親子通信:親から子へデータを渡すのは props を通じて、子から親へは $emit を通じて行います。$parent(親コンポーネントインスタンス)や $children(子コンポーネントインスタンス)を通じて通信することもできます。$ref もコンポーネントインスタンスにアクセスできます。provide/inject;$attrs/$listeners;
-
兄弟通信:Event Bus、Vuex
-
階層を越えた通信:Event Bus、Vuex;provide/inject;$attrs/$listeners;
058 ブラウザの複数タブ間で通信を実現する方法は?#
- localStorage を使用して通信を実現します。
window.addEventListener('storage', (e) => {
console.info('localStorage が変更されました:', e)
})
- websocket
原理は非常にシンプルで、例えば pageA と pageB がサーバーと websocket 接続を確立している場合、二つのページはサーバーから送信されたメッセージをリアルタイムで受信でき、サーバーにメッセージを送信することもできます。もし pageA がデータを変更した場合、サーバーにメッセージを送信し、サーバーがそのメッセージを pageB に送信すれば、二つのタブ間で簡単に通信を実現できます。
- SharedWorker
sharedWorker は webWorker の一種であり、すべての同一オリジンページで共有できます。この特性を利用して、複数のタブ間の通信を実現できます。
これは webSocket による複数ページ間の通信の原理に非常に似ており、データを送信し受信するという手順を踏みます。sharedWorker は webSocket サーバーのような役割を果たします。
// worker.js
const set = new Set()
onconnect = (event) => {
const port = event.ports[0]
set.add(port)
// メッセージを受信
port.onmessage = (e) => {
// メッセージをブロードキャスト
set.forEach((p) => {
p.postMessage(e.data)
})
}
// メッセージを送信
port.postMessage('worker がブロードキャストしたメッセージ')
}
// pageA
const worker = new SharedWorker('./worker.js')
worker.port.onmessage = (e) => {
console.info('pageA がメッセージを受信', e.data)
}
// pageB
const worker = new SharedWorker('./worker.js')
worker.port.postMessage(`クライアント B が送信したメッセージ:HELLO`)
- cookie + setInterval
原理は、メッセージを受信する必要があるページが cookie を定期的にポーリングして確認し、メッセージを送信するページがデータを cookie に保存することで、簡単にデータ共有を実現します。
setInterval(() => {
// 定期的に関数を呼び出し、ページをリフレッシュする
console.log('cookie', document.cookie)
}, 1000)
059 イベント代理の原理とその利点・欠点は?#
イベント代理とは:イベントはバブリング段階で親ノードに向かって伝播するため、子ノードのリスナー関数を統一して処理することができます。特定のイベントハンドラを指定することで、特定のタイプのすべてのイベントを管理できるようになります。これをイベント代理と呼びます。
原理:イベントバブリングメカニズムを利用します。
利点:
-
メモリ使用量を大幅に節約し、イベント登録を減らすことができます。
-
新しい子オブジェクトが追加された場合、再度イベントをバインドする必要がなく、特に動的コンテンツ部分に適しています。
欠点:
-
イベント代理の実装はバブリングに依存しているため、バブリングをサポートしないイベントには適していません。
-
すべてのイベントバインディングがイベント代理に適しているわけではなく、不適切に使用すると、必要のない要素にもイベントがバインドされる可能性があります。
060 Vue では v-for で各要素にイベントをバインドする際にイベント代理を使用する必要がありますか?なぜですか?#
まず、イベント代理の主な役割を理解する必要があります。
-
イベント代理は、要素ごとに新しいイベントを追加および削除する必要がなくなります。
-
イベント代理は、各要素にイベントをバインドするよりもパフォーマンスが良いです。
Vue の観点から見ると、上記の二