ホームページ  >  記事  >  ウェブフロントエンド  >  純粋な JS オブジェクトの代わりにマップを使用する方法についての簡単な説明

純粋な JS オブジェクトの代わりにマップを使用する方法についての簡単な説明

青灯夜游
青灯夜游転載
2020-12-02 18:06:464949ブラウズ

純粋な JS オブジェクトの代わりにマップを使用する方法についての簡単な説明

JavaScript の通常のオブジェクト {key: 'value'} を使用して、構造化データを保存できます。

しかし、非常に面倒に思うことが 1 つあります。それは、オブジェクトのキーは文字列 (またはめったに使用されない記号) でなければならないということです。

数値をキーとして使用するとどうなりますか?この場合、エラーはありません。

const names = {
  1: 'One',
  2: 'Two',
};

Object.keys(names); // => ['1', '2']

JavaScript はオブジェクトのキーを暗黙的に文字列に変換するだけです。型の一貫性が失われるため、これは難しいことです。

この記事では、ES2015 で利用できる JavaScript Map オブジェクトが、キーの文字列への変換など、通常のオブジェクトの多くの問題をどのように解決するかを説明します。

1. マップは任意のタイプのキーを受け入れることができます

前述したように、オブジェクトのキーが文字列またはシンボルでない場合、JavaScript はそれを暗黙的に文字列に変換します。

幸いなことに、map ではキー タイプに問題はありません。

const numbersMap = new Map();

numbersMap.set(1, 'one');
numbersMap.set(2, 'two');

[...numbersMap.keys()]; // => [1, 2]

12numbersMap キーにあります。これらのキーのタイプ number は変更されません。

マップでは、数値、ブール値、従来の文字列や記号など、任意のキー タイプを使用できます。

const booleansMap = new Map();

booleansMap.set(true, "Yep");
booleansMap.set(false, "Nope");

[...booleansMap.keys()]; // => [true, false]

booleansMap ブール値をキーとして使用しても問題ありません。

同様に、ブール キーは通常のオブジェクトでは機能しません。

限界を押し広げてみましょう: オブジェクト全体をマップ内のキーとして使用できますか?もちろん!

1.1 オブジェクトをキーとして使用する

オブジェクトに関連するデータを保存する必要があるが、そのデータをオブジェクト自体には添付しないとします。

通常のオブジェクトではこれを行うことはできません。

1 つの解決策は、オブジェクト値のタプルのセットを使用することです。

const foo = { name: 'foo' };
const bar = { name: 'bar' };

const kindOfMap = [
  [foo, 'Foo related data'],
  [bar, 'Bar related data'],
];

kindOfMap は、オブジェクトのペアと関連する値を含む配列です。

このアプローチの最大の問題は、キーによる値へのアクセスの時間計算量が O(n) であることです。キーによって目的の値を取得するには、配列全体をループする必要があります。

function getByKey(kindOfMap, key) {
  for (const [k, v] of kindOfMap) {
    if (key === k) {
      return v;
    }
  }
  return undefined;
}

getByKey(kindOfMap, foo); // => 'Foo related data'

WeakMap (Map の特殊なバージョン) を使用すると、その必要はありません。これは面倒です。オブジェクトをキーとして受け入れます。

MapWeakMap の主な違いは、後者ではキーであるオブジェクトをガベージ コレクションできるため、メモリ リークが防止されることです。

WeakMap を使用するために上記のコードをリファクタリングするコストはわずかです:

Map

WeakMap とは対照的に、<pre class="brush:php;toolbar:false">const foo = { name: 'foo' }; const bar = { name: 'bar' }; const mapOfObjects = new WeakMap(); mapOfObjects.set(foo, 'Foo related data'); mapOfObjects.set(bar, 'Bar related data'); mapOfObjects.get(foo); // =&gt; 'Foo related data'</pre>オブジェクトのみをキーとして受け入れ、reduced メソッド セットを持ちます。

2. マップにはキー名に関する制限はありません

JavaScript のオブジェクトはすべて、そのプロトタイプ オブジェクトからプロパティを継承します。通常の JavaScript オブジェクトにも同じことが当てはまります。

プロトタイプから継承したプロパティをオーバーライドすると、次のプロトタイプ プロパティに依存するコードが壊れる可能性があります:

function isPlainObject(value) {
  return value.toString() === '[object Object]';
}

const actor = {
  name: 'Harrison Ford',
  toString: 'Actor: Harrison Ford'
};

// Does not work!
isPlainObject(actor); // TypeError: value.toString is not a function

オブジェクトで定義されたプロパティ actortoString プロトタイプから継承された toString() メソッドをオーバーライドします。 toString() メソッドに依存しているため、isObject() が壊れます。

通常のオブジェクトがプロトタイプから継承する プロパティとメソッド のリストを確認してください。カスタム プロパティを定義するためにこれらの名前を使用することは避けてください。

たとえば、いくつかのカスタム フィールドを管理するユーザー インターフェイスがあるとします。ユーザーは名前と値を指定してフィールドを追加できます:

純粋な JS オブジェクトの代わりにマップを使用する方法についての簡単な説明

カスタム フィールドの状態を通常のオブジェクトに保存すると便利です:

const userCustomFields = {
  'color':    'blue',
  'size':     'medium',
  'toString': 'A blue box'
};

ただし、ユーザーは、toString (例に示すように)、constructor などのカスタム フィールド名を選択する可能性があり、オブジェクトが破損する可能性があります。

ユーザー入力を受け入れて通常のオブジェクトにキーを作成しないでください。

map にはこの問題はありません。キーの名前は制限されていません:

function isMap(value) {
  return value.toString() === '[object Map]';
}

const actorMap = new Map();

actorMap.set('name', 'Harrison Ford');
actorMap.set('toString', 'Actor: Harrison Ford');

// Works!
isMap(actorMap); // => true

メソッド toString() は、actorMaptoString## という名前のプロパティがあるかどうかに関係なく機能します。 # 。

3. マップは反復可能です

通常のオブジェクトのプロパティをトラバースするには、

Object.keys() や # などの他の補助静的関数を使用する必要があります。 ## Object.entries() (ES2017 で利用可能): <pre class="brush:php;toolbar:false">const colorsHex = {   'white': '#FFFFFF',   'black': '#000000' }; for (const [color, hex] of Object.entries(colorsHex)) {   console.log(color, hex); } // 'white' '#FFFFFF' // 'black' '#000000'</pre>

Object.entries(colorsHex)

オブジェクトから抽出されたキーと値のペアの配列を返します。 ただし、マップ自体は反復可能です。

const colorsHexMap = new Map();

colorsHexMap.set('white', '#FFFFFF');
colorsHexMap.set('black', '#000000');

for (const [color, hex] of colorsHexMap) {
  console.log(color, hex);
}
// 'white' '#FFFFFF'
// 'black' '#000000'

colorsHexMap

は反復可能です。 for() ループ、アンロール演算子 [...map] など、反復可能な任意の場所で使用できます。 map は、反復を返す他のメソッドも提供します。

map.keys()

はキーを反復し、map.values() は値を反復します。 <h2>4. map的大小</h2> <p>普通对象的另一个问题是你无法轻松确定其拥有的属性数量:</p> <pre class="brush:php;toolbar:false">const exams = {   'John Smith': '10 points',   'Jane Doe': '8 points', }; Object.keys(exams).length; // =&gt; 2</pre> <p>要确定 <code>exams 的大小,你必须通过它所有键来确定它们的数量。

map 提供了一种替代方法,通过它的访问器属性 size 计算键值对:

const examsMap = new Map([
  ['John Smith', '10 points'],
  ['Jane Doe', '8 points'],
]);
  
examsMap.size; // => 2

确定 map 的大小更加简单:examsMap.size

5.结论

普通的 JavaScript 对象通常可以很好地保存结构化数据。但是它们有一些限制:

  1. 只能用字符串或符号用作键
  2. 自己的对象属性可能会与从原型继承的属性键冲突(例如,toStringconstructor 等)。
  3. 对象不能用作键

所有这些问题都可以通过 map 轻松解决。而且它们提供了诸如迭代器和易于进行大小查找之类的好处。

不要将 map 视为普通对象的替代品,而应视为补充。

你知道 map 相对于普通对象的其他好处吗?请在下面写下你的评论!

原文地址:https://dmitripavlutin.com/maps-vs-plain-objects-javascript/

译文地址:https://segmentfault.com/a/1190000020660481

更多编程相关知识,请访问:编程课程!!

以上が純粋な JS オブジェクトの代わりにマップを使用する方法についての簡単な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。