1728327975
2024-10-07 13:26:45
最新の JavaScript をかなりの時間を費やした人なら、おそらく十分な楕円を見たことがあるでしょう (...) 最も陰気な 90 年代のロールプレイング ゲームの主人公ですら顔負けです。少しわかりにくいと思われたとしても、私はあなたを責めません。確かに、見つけたからといってあなたを責めるつもりはありません 何でも JavaScript についてはわかりにくいですが、これらの楕円は一見すると独特に直感的ではないと常々思っていました。それ自体が奇妙な構文である「代入の構造化」のコンテキストで、こうした小さな奇妙な問題に頻繁に遭遇するのは仕方のないことです。
あ 代入の構造化 これを使用すると、昔ながらの方法 (次のようにインデックスまたはキーによって一度に 1 つずつ) で各要素の値にアクセスする必要がなく、配列またはオブジェクトから個々の値を抽出して一連の識別子に割り当てることができます。
const myArray = [ true, false, false ]; const firstElement = myArray[0]; const secondElement = myArray[1]; const thirdElement = myArray[2];
「バインディング パターンの構造化」と呼ばれる最も単純な形式では、各値が配列またはオブジェクト リテラルから解凍され、対応する識別子に割り当てられます。これらはすべて単一の識別子で初期化されます。 let または const (または var関数スコープを懐かしく感じている人はそうかもしれません)。
割り当てられた値は、構造化される配列またはオブジェクト リテラルです。配列を操作する場合、識別子は一対の大括弧で囲まれ、これらの大括弧内で定義した各識別子は、ソース配列内の同じインデックスに対応します。
const myArray = [10, 200, 3000 ]; const [ firstElement, secondElement, thirdElement ] = myArray;
firstElement; > 10 secondElement; > 200 thirdElement; > 3000
カンマを使用して識別子を省略すると、要素をスキップできます。これは、 スパース配列:
const myArray = [ "goose", "duck", "duck", "goose" ]; const [ firstElement, , , fourthElement ] = myArray;
firstElement; > "goose" fourthElement; > "goose"
構造化をデータ構造の「アンパック」と呼ぶことがありますが、そのように聞こえるかもしれませんが、構造化によって元の配列やオブジェクトが変更されるわけではないことに注意してください。
const myArray = [ "first", "second", "third" ]; const [ startElement, middleElement, endElement ] = myArray;
myArray; > Array(3) [ "first", "second", "third" ]
構造化: 配列だけではないパーマリンク
さて、あなたはそうすることはあまりありません 作成する データ構造を取得し、それに含まれる要素の値をこのように多数の識別子に即座に割り当てますが、場合によっては、 は これらの値を使用または操作するには、スクリプト内の他の場所にまとめられたデータ構造の内容を取得する必要があります。たとえば、API が、画像の構築に使用する画像に関する情報を含むオブジェクト リテラルを提供したとします。 img 要素:
const myImage = { "src": "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs", "alt": "A single black pixel.", "size": { "width": 600, "height": 400 } };
確かに、このオブジェクトを分解するのは、Web 開発全体の中で最も面倒な作業ではありませんが、一度に 1 行ずつ行うのは少し面倒に感じます。
const imgContainer = document.querySelector( ".img-container" ); const src = myImage.src; const alt = myImage.alt || ""; const width = myImage.size.width || 800; const height = myImage.size.height || 400; if(imgSource) { imgContainer.innerHTML = `${ src }" alt="${ alt }" height="${ height }" width="${ width }">`; }
配列を分割するのと同じようにオブジェクトを分割できますが、構文にいくつかの違いがあります。まず、識別子は括弧ではなく一対の中括弧で囲まれています。次に、識別子には、指定された順序に関係なく、対応するオブジェクト キーの値が設定されます。
const { alt, size, src } = myImage; const { height, width } = size;
alt; > "A single black pixel."
そして、これらの値を識別子に割り当てるのと同じように、 ドット表記、プロパティがまったく存在しない場合、またはプロパティに明示的なプロパティが含まれている場合に割り当てられるデフォルト値を設定できます。 undefined 価値:
const { size, src, alt = "" } = myImage; const { width = 800, height = 450 } = size;
これを均等にすることができます もっと 簡潔。ネストされたものを解凍する必要はありません size 個別に反対する。同時に開梱することもできます。
const { src, alt = "", size: { width = 800, height = 450 } } = myImage;
これにより、次の更新されたコードが残ります。
const imgContainer = document.querySelector( ".img-container" ); const { src, alt = "", size: { width = 800, height = 450 } } = myImage; if(imgSource) { imgContainer.innerHTML = `${ src }" alt="${ alt }" height="${ height }" width="${ width }">`; }
全体的に見て、分割代入は複雑なデータ構造を分解するための迅速かつ便利な方法を提供しますが、その密度の高さから見て、最も親しみやすい構文とは言えません。
それでは、省略記号はどこに登場するのでしょうか?パーマリンク
構造化代入のコンテキストでは、識別子が続く省略記号は「残りのプロパティ」、つまり新しい配列またはオブジェクトとして解凍される配列またはオブジェクトの残りの部分を含む識別子を表します。この残りのプロパティには、独自の識別子に明示的に解凍した要素以外の残りの要素がすべて含まれ、すべて解凍したものと同じ種類のデータ構造にバンドルされます。
const myArray = [ false, true, false ]; const [ firstElement, ...remainingElements ] = myArray;
firstElement; > false remainingElements; > Array [ true, false ]
別の例:
const myObject = { "key1": "first value", "key2": "second value", "key3": "third value" }; const { key1, ...otherProperties } = myObject;
key1; > "first value" otherProperties; > Object { key2: "second value", key3: "third value" }
構造化代入自体と同様に、 残りのプロパティ おそらく、このような真空状態ではあまり役に立たないと思われます。繰り返しになりますが、私たちは単にまとめたばかりの単純なデータ構造をバラバラにしているのです。これが本当に役立つのは、必ずしも制御できない大規模なデータ構造を扱う場合です。
たとえば、単一ページの静的サイト ジェネレーターの出力を操作していたとします。
const postData = { inputPath: './index.md', url: '/', lede: "This is the introduction to the post", date: new Date(), title: 'My Title', postId: 25, tags: ['tag1', 'tag2'], body: 'This is the body of the post' }
このオブジェクトは、すべてが混在している 2 つの懸念事項に対処します。投稿に関するメタ情報 (投稿を生成したファイルのパス、生成された投稿が保存されるパス、投稿の ID、投稿に関連付けられたタグ)、および投稿自体を構成するコンテンツ。おそらくこのすべての情報が必要になりますが、必要に応じて各プロパティにアクセスするのは反復的な作業になるため、構造化構文を使用して必要なメタ情報を取得し、残りのすべてのプロパティ (投稿コンテンツ自体) を保持します。新しいオブジェクトとして:
const { inputPath, url, postId, tags, ...postContent } = postData;
postContent; > Object { lede: "This is the introduction to the post", date: Date Fri Aug 23 2024 14:05:19 GMT-0400 (Eastern Daylight Time), title: "My Title", body: "This is the body of the post" }
一行!各プロパティ値を取得して個別に識別子に割り当てる必要がなく、スクリプト全体を通じて大きくて扱いにくいオブジェクトに継続的にアクセスする必要がなく、投稿自体を構成するすべてのプロパティがきちんとした新しいオブジェクトにまとめられます。最小限の大騒ぎで、混乱はほとんどありません。
残りとスプレッド演算子パーマリンク
休む
最も頻繁に遭遇するのは、rest 演算子 (...) 構造化代入では、優柔不断なテキスト メッセージ送信者と同じように、JavaScript はいくつかの予期しない場所に省略記号を表示します。これらの使用法はすべて、分解で知った使用法と共通点があります。それらはすべて、データをデータ構造に集約したり、データ構造からデータを分散したりすることに関係しています。
関数パラメータの識別子の前にある省略記号は、構造化代入を実行するときと同じ機能を実行します。つまり、「残りの演算子」として、すべての関数をバンドルします。 残りの引数 を反復可能なデータ構造 (配列) としてこの関数に渡し、省略記号の後に続く識別子を割り当てます。これにより、「可変引数関数」という印象深い用語ですが、実際には「任意の数の引数を受け入れることができる関数」を意味します。
function myFunction( firstParameter, ...remainingParameters ) { };
広める
最後に省略記号に遭遇する箇所 (特に感情的なコメントは別として) は、まったく異なります。配列要素または関数の引数が予期されるコンテキストでは、同じ省略記号がまったく異なる名前をとり、「スプレッド演算子」(...)、反復可能なデータ構造 (配列、オブジェクト リテラル、さらには文字列) を個々の要素に展開します。
スプレッド演算子の最も一般的な用途は、配列のコピーと結合です。
const myArray = [ 4, 5, 6 ]; const myMergedArray = [1, 2, 3, ...myArray ];
myMergedArray; > Array(6) [ 1, 2, 3, 4, 5, 6 ]
ここで、もう一度、スプレッド構文は、関数呼び出しの引数または配列の要素が予期される場合にのみ適用されることに注意してください。上の例で見たように、配列は予想どおりに配列から要素を受け取ります。あまり予想しにくいことですが、オブジェクト リテラルも同様です。
const myArray = [ true, false ]; const myObject = { ...myArray };
myObject; > Object { 0: true, 1: false }
データ構造の内容を…まあ、何も分散する必要がある状況には決して遭遇しないはずです。たとえば、JavaScript の多くの省略記号に関するブログ投稿の例として、次のように試してみるとします。
const myArray = [ 1, 2, 3 ];
...myArray; > Uncaught SyntaxError: expected expression, got '...'
サイコロはありません。しかし、同じ構文を console.logの場合、引数のコンテキストでスプレッド演算子を使用することになります。 console.log メソッドですので、 する 仕事:
const myArray = [ 1, 2, 3 ]; console.log( ...myArray );
オブジェクトの広がり
スプレッド演算子をオブジェクト リテラルで使用するのは、JavaScript に最近追加された機能です。 スプレッド演算子自体は 2015 年の ES6 で追加されました、それだけ ES2018 以降のオブジェクト リテラルに適用されます。スプレッド オペレータは、オブジェクトの「浅い」コピーを作成します。つまり、値の「」を広めます。自分の財産” — つまり、任意の 数え切れないほどのプロパティ ない プロトタイプチェーンを経由して継承される — 新しいオブジェクトに。
const oldObject = { "key1": "first value", "key2": "second value", "key3": "third value" }; const myObject = { "key0": "zeroth value", ...oldObject };
myObject; > Object { key0: "zeroth value", key1: "first value", key2: "second value", key3: "third value" }
これは 信じられないほど 便利な構文を使用すると、わずか数文字でオブジェクトをコピーおよび結合できます。
留意すべき点がいくつかあります。重複キーを含む配列を結合すると、それらのキーに関連付けられた値が上書きされます。
const firstObject = { "key1" : "first value", "key2" : "second value", "key3" : "third value" }; const secondObject = { "key0" : "zeroth value", "key1" : "another value" }; const myObject = { ...firstObject, ...secondObject }
myObject; > Object { key1: "another value", key2: "second value", key3: "third value", key0: "zeroth value" }
また、オブジェクトは配列や文字列と同じように反復可能ではないため、オブジェクトの拡散のコンテキストはまったく同じではありません。一方、配列と文字列はオブジェクト、配列、または関数の引数全体に拡散できます。 、オブジェクトは別のオブジェクトにのみ拡散できます。
const myObject = { "key1": "first value", "key2": "second value", "key3": "third value" }; console.log( ...myObject );
> Uncaught SyntaxError: expected expression, got '...'
すべてをひとつにまとめる
これらの構文をすべて理解すれば、スクリプト ファイルに 2005 年頃の LiveJournal の投稿よりも多くの省略記号が含まれることを理解するのは難しくありません。
非構造化構文とスプレッド構文の両方について、より現実に近い例をもう一度見てみましょう。レンダリングしたい画像に関する情報を含むオブジェクトと、単一のブログ投稿に関する大量の情報を含むオブジェクトです。
const apiPost = { inputPath: './index.md', url: '/', lede: "This is the introduction to the post", date: new Date(), title: 'My Title', postId: 25, tags: ['tag1', 'tag2'], body: 'This is the body of the post' }; const apiImage = { "src": "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs", "alt": "...", "size": { "width": 600, "height": 400 } };
これらのオブジェクトを箱から出してすぐにそのまま使用することもできますが、それには多くの作業が必要です。代わりに、構造化構文を使用して、 postData 先ほどと同じように、投稿のメタ情報と、レンダリングされたページを設定するために使用する投稿の本文という 2 つの別々の関心事にオブジェクトを分割します。
const { inputPath, url, postId, tags, ...postContent } = apiPost;
postContent; > Object { lede: "This is the introduction to the post", date: Date Fri Sep 13 2024 15:39:50 GMT-0400 (Eastern Daylight Time), title: "My Title", body: "This is the body of the post" }
それでは、オブジェクトスプレッドを使用して、新しく作成したオブジェクトを組み合わせてみましょう postContent オブジェクトと、画像に関する情報を含むオブジェクトを組み合わせます。ただし、1 つ追加します。この画像はページの先頭に表示するので、次のような問題には遭遇したくないからです。 最大のコンテンツ豊富なペイント、これを明示的にレンダリングしたい場合があります。 loading="eager" 属性 — 画像データを表すオブジェクトにも追加します。
const myPost = { ...postContent, "heroImg": { "loading": "eager", ...apiImage } };
そして最終的には、独自のプロパティを簡単に追加するなど、必要なプロパティのみを含むオブジェクトが残ります。ブログ後のレンダリングのニーズをすべてワンストップで満たすことができます。
myPost; > Object { lede: "This is the introduction to the post", date: Date Fri Sep 13 2024 13:05:12 GMT-0400 (Eastern Daylight Time), title: "My Title", body: "This is the body of the post", heroImg: { alt: "...", loading: "eager", size: Object { width: 600, height: 400 }, src: "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs" } }
その 多くの ドット表記を行ごとに操作し、押しつけられた無秩序なオブジェクトからプロパティを 1 つずつ取り出すよりも簡単です。欠点は何ですか?つまり…私は 推測 私たちのコードはもう少し読むことになるかもしれません…まあ…まあ、気にしないでください…
#JavaScript #での構造化ガイド