ホームページ  >  記事  >  ウェブフロントエンド  >  配列、配列コンストラクター、for in ループ、typeof、instanceOf_javascript 技巧

配列、配列コンストラクター、for in ループ、typeof、instanceOf_javascript 技巧

WBOY
WBOYオリジナル
2016-05-16 18:02:28889ブラウズ

注: JavaScript の配列は連想配列ではありません。 JavaScript には、キーと値の対応を管理するオブジェクトのみがあります。ただし、連想配列は順序を維持しますが、オブジェクトは順序を維持しません。

for in ループはプロトタイプ チェーン上のすべてのプロパティを列挙するため、これらのプロパティをフィルタリングする唯一の方法は `hasOwnProperty` 関数を使用することなので、通常の for ループよりも何倍も遅くなります。

反復
配列の走査で最高のパフォーマンスを達成するには、従来の for ループを使用することをお勧めします。

コードをコピー コードは次のとおりです:

var list = [1, 2, 3 , 4, 5, ... 100000000];
for(var i = 0, l = list.length; i console.log(list[i]); >}

上記のコードには、l = list.length によって配列の長さをキャッシュする処理があります。

長さは配列のプロパティですが、各ループで長さにアクセスするとパフォーマンスのオーバーヘッドが発生します。 最新の JavaScript エンジンがこれを最適化している可能性がありますが、コードがこれらの最新のエンジンで実行されるかどうかは保証できません。

実際、配列の長さをキャッシュしない方法は、キャッシュされたバージョンよりもはるかに遅くなります。

`length` プロパティ (`length` プロパティ)
length プロパティの getter メソッドは単純に配列の長さを返しますが、setter メソッドは配列を切り詰めます。

コードをコピーします コードは次のとおりです:
var foo = [1, 2, 3 , 4, 5, 6];
foo.length = 3; // [1, 2, 3]

foo; // [1, 2, 3]


翻訳者注: この時点で Firebug で foo の値を表示すると、 [1, 2, 3, unfined, undefined, unknown] になりますが、この結果は正確ではありませんChrome のコンソールで foo の結果を確認すると、次のようになることがわかります。 [1, 2, 3] 変数は JavaScript の変数であるため、変数の意味は異なります。上の 2 つの結果はまったく異なります。
// 翻訳者注: 確認するには、次のコードを実行して、シリアル番号 5 が foo に存在するかどうかを確認してみましょう。
5 in foo; // Firebug または Chrome のどちらでも false を返します。
foo[5] = unknown;
5 in foo; // Firebug または Chrome の場合、
は長さ A に設定されます。値を小さくすると配列が切り詰められますが、length プロパティを増やしても配列には影響しません。

結論 (結論として)
パフォーマンスを向上させるには、通常の for ループを使用し、配列の長さプロパティをキャッシュすることをお勧めします。 for in を使用して配列を反復処理することは、悪いコーディング方法とみなされ、エラーが発生し、パフォーマンスの問題が発生する傾向があります。

配列コンストラクター
配列のコンストラクターは引数の処理方法が少し曖昧であるため、配列の作成には配列のリテラル構文 [] を使用することを常にお勧めします。

[1, 2, 3]; // 結果: [1, 2, 3]
new Array(1, 2, 3); // 結果: [1, 2, 3]

[3]; // 結果: [3]
new Array(3) // 結果: []
new Array('3') // 結果: ['3']
翻訳者注: ここでの曖昧さは、配列の 2 つのコンストラクター構文を指します。 var arr1 = new Array(arrayLength); var arr2 = new Array(element0, element1, ..., elementN); / 翻訳者注: したがって、次のコードは非常に混乱するでしょう
new Array(3, 4, 5) // 結果: [3, 4, 5]
new Array(3) // 結果: [] 、この配列の長さは 3 です。
コンストラクターに渡されるパラメーターは 1 つだけであり (翻訳者注: new Array(3) の呼び出しメソッドを指します;)、このパラメーターは数値であるため、コンストラクターは空の値を返します。このパラメータに設定された長さプロパティを持つ配列。この時点では長さプロパティのみが設定され、実際の配列は生成されないことに注意することが重要です。翻訳者注: Firebug では [未定義、未定義、未定義] と表示されますが、これは実際には間違っています。前のセクションに詳細な分析があります。

var arr = new Array(3);
arr[1]; // 未定義
1 in arr; // 配列はまだ生成されていません
これが優先されます配列の設定よりも長さの属性は、for ループの問題を避けるために文字列をループする必要がある場合など、いくつかの状況でのみ役立ちます。

new Array(count 1).join(stringToRepeat);
// 翻訳者注: new Array(3).join('#') は "##" を返します
結論 (In結論)
新しい配列を作成するために配列コンストラクターを使用することは避けるべきです。配列のリテラル構文を使用することをお勧めします。これらはより短く、より簡潔であるため、コードの可読性が向上します。

for in ループ
in 演算子と同様に、for in ループもオブジェクトのプロパティを検索するときにプロトタイプ チェーン上のすべてのプロパティを走査します。

注: for in ループは、配列の length プロパティなど、enumerable が false に設定されているプロパティを反復しません。




コードをコピー
コードは次のとおりです:

// Object.prototype を変更します
Object.prototype.bar = 1;

var foo = {moo: 2};
for(var i in foo); 🎜>console.log(i); // bar と moo の 2 つの属性を出力します
}

for 自体の動作を変更することは不可能なので、フィルタリングする必要がありますループ本体に現れる予期しないプロパティ。これは、Object.prototype プロトタイプの `hasOwnProperty` 関数を通じて実行できます。

注: for in は常にプロトタイプ チェーン全体を走査するため、オブジェクトの継承レベルが深すぎるとパフォーマンスに影響します。

フィルタリングに `hasOwnProperty` を使用する

コードをコピー コードは次のとおりです:
// foo 変数は上記の例の変数です。
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i); 🎜>}
}


このバージョンのコードが唯一の正しい書き方です。 hasOwnPropertyを使用したので、今回はmooのみが出力されます。 hasOwnProperty が使用されていない場合、ネイティブ オブジェクト プロトタイプ (Object.prototype など) が拡張されるときにこのコードが壊れる可能性があります。

広く使用されているクラス ライブラリである Prototype は、ネイティブ JavaScript オブジェクトを拡張します。したがって、このクラス ライブラリがページに含まれている場合、hasOwnProperty フィルターを使用しない for in ループでは必然的に問題が発生します。

ベスト プラクティス
常に hasOwnProperty を使用することをお勧めします。コードが実行されている環境について仮定を立てたり、ネイティブ オブジェクトが拡張されているかどうかを仮定したりしないでください。

typeof 演算子
typeof 演算子 (`instanceof` とともに) は、おそらく JavaScript の最大の設計上の欠陥です。なぜなら、typeof 演算子から望ましい結果を得るのはほぼ不可能だからです。

instanceof には非常に少数のアプリケーション シナリオがありますが、typeof には実用的なアプリケーションが 1 つだけあります (翻訳者注: この実用的なアプリケーションは、オブジェクトが定義されているか、値が割り当てられているかを検出するために使用されます)。オブジェクトのタイプを確認するためには使用されません。

注: typeof は typeof(obj) などの関数構文で呼び出すこともできますが、これは関数呼び出しではありません。これら 2 つの括弧は式の値を計算するためにのみ使用され、戻り値は typeof 演算子のオペランドとして使用されます。実際には typeof という名前の関数はありません。


JavaScript 型テーブル
値クラス型 ---------------------- - ------------------
"foo" String string
new String("foo") String オブジェクト
1.2 Number 数値
new Number (1.2 ) Number オブジェクト
true Boolean boolean
new Boolean(true) Boolean オブジェクト
new Date() Date オブジェクト
new Error() Error オブジェクト
[1,2,3] 配列object
new Array(1, 2, 3) 配列オブジェクト
new Function("") 関数 function
/abc/g RegExp オブジェクト (Nitro/V8 の関数)
new RegExp("meow ") RegExp オブジェクト (Nitro/V8 の関数)
{} Object オブジェクト
new Object() Object オブジェクト
上の表の Type 列は、typeof 演算子の演算結果を表します。ご覧のとおり、ほとんどの場合、この値は「オブジェクト」を返します。

クラス オブジェクトの内部プロパティ [[Class]] の値を表す列。

JavaScript 標準ドキュメントでは次のように定義されています: [[Class]] 値は次の文字列の 1 つだけです: Arguments、Array、Boolean、Date、Error、Function、JSON、Math、Number、Object、RegExp、String .

オブジェクトの [[Class]] を取得するには、Object.prototype で定義されたメソッド toString を使用する必要があります。

オブジェクトのクラス (オブジェクトのクラス)
JavaScript 標準ドキュメントでは、[[Class]] 値を取得する 1 つの方法のみが提供されており、それは Object.prototype.toString を使用することです。


function is(type, obj) {
var clas = Object.prototype.toString.call(obj).slice(8, -1);
return obj !== 未定義 && obj !== null && clas === type;

is('String', 'test'); // true
is('String', new String('test')); // true


上記の例では、Object.prototype.toString メソッドが呼び出され、[[Class]] 値を取得する必要があるオブジェクトに設定されます。
翻訳者注: Object.prototype.toString は標準形式の文字列を返すため、上記の例では、以下に示すように、スライスを介して指定された位置で文字列をインターセプトできます。 >
コードをコピーします


コードは次のとおりです:
Object.prototype.toString.call([]) // "[オブジェクト配列]" Object.prototype.toString.call({}) // "[オブジェクト オブジェクト]" Object.prototype.toString.call(2) // "[オブジェクト番号]"
ES5 のヒント: ECMAScript 5 では、便宜上、Object.prototype.toString メソッドが null および未定義で呼び出され、その戻り値が Object から Null および Unknown に変更されます。

翻訳者注: 以下に示すように、この変更は IE8 および Firefox 4 で確認できます:
コードをコピーコードは次のとおりです。

// IE8
Object.prototype.toString.call(null) // "[object Object]"
Object.prototype.toString.call ( unknown) // "[object Object]"

// Firefox 4
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString 。 call(unknown) // "[object Unknown]"
未定義変数のテスト
typeof foo !== 'unknown'

上記のコードは、foo が定義されているかどうかを検出します。定義されていない場合、直接使用すると、ReferenceError 例外が発生します。 typeof が役立つのはここだけです。

結論
オブジェクトの型を検出するには、Object.prototype.toString メソッドを使用することを強くお勧めします。これが唯一信頼できる方法だからです。上の表に示すように、typeof の一部の戻り値は標準ドキュメントで定義されていないため、エンジンの実装が異なると異なる場合があります。

変数が定義されているかどうかを確認する場合を除き、typeof 演算子の使用は避けるべきです。

instanceof 演算子
instanceof 演算子は、2 つのオペランドのコンストラクターを比較するために使用されます。カスタム オブジェクトを比較する場合にのみ意味があります。組み込み型の比較に使用すると、typeof 演算子と同じくらい役に立たなくなります。

カスタム オブジェクトの比較
コードをコピー コードは次のとおりです:

function Foo() {}
function Bar() {}
Bar.prototype = new Foo();

new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true

// Foo コンストラクターのインスタンスではなく、Bar.prototype を関数 Foo 自体に設定するだけの場合
Bar.prototype =
new Bar; )instanceof Foo; // false
`instanceof` ネイティブ型で `instanceof` を使用する)
new String('foo')instanceof String; // true
new String('foo ')instanceof Object; // true

'foo'instanceof String; // false
'foo'instanceof Object; // false

注意すべき点は、instanceof の場合です。異なる JavaScript コンテキスト (ブラウザー内の異なるドキュメント構造など) に属するオブジェクトを比較する場合、それらのコンストラクターは同じオブジェクトではないためです。

結論 instanceof 演算子は、同じ JavaScript コンテキストからのカスタム オブジェクトを比較する場合にのみ使用してください。 「typeof」演算子の場合と同様、他の使用は避けてください。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。