[解決済み】JavaScriptで文字列がリストに入っているかどうかを判断する
質問
SQLでは、ある文字列がリストに含まれているかどうかを、次のように確認することができます。
Column IN ('a', 'b', 'c')
JavaScriptでこれをやるには、何かいい方法はないでしょうか?これをやるのはとても不格好なんだ。
if (expression1 || expression2 || str === 'a' || str === 'b' || str === 'c') {
// do something
}
それに、パフォーマンスや分かりやすさにも自信がありません。
if (expression1 || expression2 || {a:1, b:1, c:1}[str]) {
// do something
}
あるいは、switch関数を使うこともできる。
var str = 'a',
flag = false;
switch (str) {
case 'a':
case 'b':
case 'c':
flag = true;
default:
}
if (expression1 || expression2 || flag) {
// do something
}
しかし、それは恐ろしいほどの混乱です。何かアイデアはありませんか?
今回は、企業のイントラネットのページ用なので、Internet Explorer 7を使わなければなりません。そこで
['a', 'b', 'c'].indexOf(str) !== -1
は、何らかのシンタックスシュガーがなければ、ネイティブでは動作しません。
どのように解決するのですか?
EcmaScript 6 以上
ES6以上を使用している場合、最もクリーンな方法は、アイテムの配列を構築して
Array.includes
:
['a', 'b', 'c'].includes('b')
これは、以下のような利点があります。
indexOf
があるかどうかを適切にテストできるからです。
NaN
の真ん中の要素のような、欠落している配列要素にマッチさせることができます。
[1, , 2]
から
undefined
.
includes
も動作します。
JavaScript の型付き配列
のような
Uint8Array
.
ブラウザのサポートが心配な場合(IEやEdgeなど)、次のようにします。
チェック
Array.includes
CanIUse.Comにて
がないブラウザやブラウザのバージョンを対象にする場合は
includes
をお勧めします。
ポリフィル.io
は、ポリフィリング用です。
より高いパフォーマンス
注意点
Array.includes()
は、配列の要素数に応じて処理時間が変化し、その性能は O(n) となります。より高いパフォーマンスが必要で、かつアイテムのセットを繰り返し構築する必要がない場合 (ただし、アイテムが何らかの要素を含んでいるかどうかを繰り返しチェックする必要がある場合) は、 配列を構成するために
Set
.
const interestingItems = new Set(['a', 'b', 'c'])
const isItemInSet = interestingItems.has('b')
には、任意の反復可能な項目を渡すことができることに注意してください。
Set
コンストラクタをサポートするものであれば
の...のための
). また
Set
を使って配列に変換します。
Array.from(set)
.
配列がない場合
これはあまりお勧めできませんが、新しい
isInList
プロパティを文字列に対して以下のように設定します。
if (!String.prototype.isInList) {
Object.defineProperty(String.prototype, 'isInList', {
get: () => function(...args) {
let value = this.valueOf();
for (let i = 0, l = args.length; i < l; i += 1) {
if (arguments[i] === value) return true;
}
return false;
}
});
}
そして、このように使用します。
'fox'.isInList('weasel', 'fox', 'stoat') // true
'fox'.isInList('weasel', 'stoat') // false
に対しても同じことができます。
Number.prototype
.
なお
Object.defineProperty
は、IE8以前や、他のブラウザの非常に古いバージョンでは使用できません。しかし
String.prototype.isInList = function() { ... }
なぜなら、このような単純な代入を行うことで
String.prototype
これは、コードを破壊する可能性が高くなります。
配列.indexOf
モダンブラウザをお使いの場合。
indexOf
は常に動作します。しかし、IE8以前の場合はポリフィルが必要です。
もし
indexOf
は -1 を返すので、その項目はリストにはありません。しかし、このメソッドでは
NaN
にマッチし、明示的な
undefined
にはマッチしませんが、欠落している要素にはマッチします。
undefined
のように、配列
[1, , 2]
.
のポリフィル
indexOf
または
includes
IE、またはサポートがないその他のブラウザ/バージョンでは
のようなサービスを利用したくない場合。
polyfill.io
上記のように、標準に準拠したカスタムポリフィルを自分のソースコードに含めることはいつでも可能です。例えば、Mozilla Developer Network には、以下のようなものがあります。
indexOf
.
Internet Explorer 7に対応するために、よりシンプルな形で
indexOf()
関数は、標準に準拠していない。
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(item) {
var i = this.length;
while (i--) {
if (this[i] === item) return i;
}
return -1;
}
}
オブジェクトのプロトタイプを変更する際の注意点
しかし、私は
String.prototype
または
Array.prototype
は、長期的には良い戦略です。JavaScriptのオブジェクトプロトタイプを変更すると、深刻なバグにつながる可能性があります。自分の環境でそうすることが安全かどうかを判断する必要があります。特に注意したいのは、配列の反復処理(Array.prototypeにプロパティが追加されている場合)において
for ... in
は新しい関数名をキーの1つとして返します。
Array.prototype.blah = function() { console.log('blah'); };
let arr = [1, 2, 3];
for (let x in arr) { console.log(x); }
// Result:
0
1
2
blah // Extra member iterated over!
今、あなたのコードが動作していても、将来、誰かがサードパーティのJavaScriptライブラリやプラグインを追加した瞬間に、継承されたキーに対して熱心にガードしていない場合、すべてが壊れる可能性があります。
その破損を避けるための古い方法は、列挙中に、オブジェクトが非相続プロパティとして実際にそれを持っているかどうかを各値でチェックすることです。
if (arr.hasOwnProperty(x))
と
その時だけ
を使用します。
x
.
このエクストラキー問題を回避するための新しいES6の方法は、以下の通りです。
-
使用する
of
の代わりにin
,for (let x of arr)
. しかし、出力ターゲットとダウンレベル トランスパイラの正確な設定/能力によっては、これは信頼できないかもしれません。さらに、あなたのコードとサードパーティライブラリのすべてがこの方法に厳密に従うことを保証できるのでなければ、この質問の目的には、おそらくincludes
上記のように -
プロトタイプに新しいプロパティを定義するには、次のようにします。
Object.defineProperty()
これは、そのプロパティを(デフォルトで)非列挙型にするためです。これは、あなたが使っているすべてのJavaScriptライブラリやモジュールが同じように動作している場合にのみ、問題を解決することができます。
最後の注意点
最後に、ポリフィルは理にかなっており、オブジェクトのプロトタイプを変更することは有用な戦略ですが、そのアプローチにはスコープ問題がある場合があることに留意してください。
ブラウザでは、それぞれの異なる
document
オブジェクトはそれ自身の新しいグローバルスコープであり、ブラウザJSでは、新しいドキュメントを作成したり(オフスクリーンレンダリングやドキュメントフラグメントの作成に使われるものなど)、他のページの
document
オブジェクトのプロトタイプが、期待するメソッドを備えていない可能性があります。
nodeの場合、プロトタイプを変更することで
global
オブジェクトのプロトタイプは安全かもしれませんが、グローバルではない、インポートされたオブジェクトのプロトタイプを変更すると、同じパッケージの2つのバージョンが要求/インポートされることになった場合、破損につながる可能性があります。つまり、依存関係やサブ依存関係が期待したものと異なるバージョンを使用するまで、あなたのコードは問題なく動作し、あなた自身のコードを変更することなく、単純な
npm install
または
yarn install
がこの問題の引き金になる可能性があります。(この問題に対処するためのオプションとして、yarnの
resolutions
プロパティで
package.json
が、他に選択肢があるのであれば、それに頼るのは得策ではありません)。
関連
-
[解決済み] テスト
-
[解決済み】React-Routerの子が1つしかない。
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] リストのリストからフラットなリストを作るには?
-
[解決済み] JavaScriptでランダムな文字列/文字を生成する
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Facebook Graph API のクエリで with=location を使用すると "Uncaught (in promise) undefined" というエラーが発生する。
-
[解決済み】フォームコントロールの値アクセサがない
-
[解決済み】NodeJS "ESモジュールをロードするためにインポートを使用する必要があります。"
-
[解決済み】Javascriptのコールバック関数がFirefoxで「Callback is not a function」というエラーを投げる
-
[解決済み】エラー:リスン EACCES 0.0.0.0:80 OSx Node.js
-
[解決済み】TypeError:res.jsonは関数ではありません。
-
[解決済み】Uncaught TypeError: 未定義のプロパティ 'msie' を読み取れない - jQuery tools
-
[解決済み】 \u003C とは何ですか?
-
[解決済み】JavaScriptで関数が存在するかどうかを確認する方法は?
-
[解決済み] JavaScriptで複数ケースを扱うSwitch文