名前付きプロパティをオブジェクトのように配列に追加できるのはなぜですか?


105

次の2つの異なるコードスニペットは私と同等に見えます。

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

そして

var myObject = {'A': 'Athens', 'B':'Berlin'};

両方が同じように動作し、またtypeof(myArray) == typeof(myObjects)(どちらも「オブジェクト」を生成するため)。

これらの亜種の間に違いはありますか?

回答:


131

JavaScriptの実質的にすべてがオブジェクトであるため、任意のプロパティを設定することで、配列オブジェクトを「悪用」することができます。これは有害であると考えるべきです。配列は、数値でインデックス付けされたデータ用です。非数値キーの場合は、オブジェクトを使用します。

数値以外のキーが配列に「適合しない」理由のより具体的な例を次に示します。

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

alert(myArray.length);

これは「2」を表示しませんが、「0」を表示します-事実上、要素は配列に追加されておらず、いくつかの新しいプロパティが配列オブジェクトに追加されています。


4
myArray.lengthは、配列の最後の要素の数値インデックス/キーを返しますが、要素の実際の数は返しません。Arrayオブジェクトのプロパティは配列値と同じではありませんか?
ダーシャサロ

1
通常のオブジェクトのように扱う場合、Arrayオブジェクトの意図されたセマンティクスが悪用されることを説明しようとしていました。リンクされた記事はより良い仕事をします:)
ポールディクソン

13
次に誰かがJavaScriptを開発に適した言語だと言ったときに、このサンプルを紹介します。ありがとうございました。
Olivier Pons 2014

@オリビエ、あなたが「バグ」と呼ぶものは、素晴らしい「機能」になることもあります。タイトルや説明を配列に追加できます。その内容や長さに影響を与えたりtitledescriptionitemsプロパティを使用してオブジェクトにラップしたりする必要はありません。それはすべて、あなたがその言語をどれだけよく知っているか、そしてあなたがそれをどのように使うかにかかっています。
tao

配列でカスタムプロパティを使用することは、本質的に間違っていません。何が問題なのか、一度実行すると、配列のメンバーとして機能することを期待しています。これらはメンバーではなく配列プロパティであるため、配列メソッドの影響を受けません。これは実際には上記のリンクされた記事の著者のコメントで述べられています。さて、公平に言えば、コードを使用している人々の地獄を混乱させる可能性があるので、私はこれを習慣としてお勧めします。あるいは、彼らがまだ始まったばかりの場合、それは彼らを危険な道に置くでしょう。しかし、JavaScriptが悪いとは言わないでしょう。JavaScriptは、ほとんどの場合許可されていないものを許可するからです。
tao

14

JSでは、配列はオブジェクトであり、わずかに変更されています(いくつかの関数が追加されています)。

次のような機能:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 

リストされているすべての関数がすべてのJS実装に組み込まれているとは思いませんが、要点は理解できました。もう1つの違いは、プロトタイプが異なることです(これは、これらの追加機能によって暗示されます)。
Rashack、2009年

6

私は、以前の答えでは比喩的で不可解すぎると思います。説明が続きます。

Array、Boolean、Date、Function、Number、RegExp、Stringのインスタンスはオブジェクトですが、各タイプに固有のメソッドとプロパティで拡張されています。たとえば、配列には定義済みのlengthプロパティがありますが、一般的なオブジェクトにはありません。

javascript:alert([].length+'\n'+{}.length)

ディスプレイ

0
未定義

本質的に、FF Geckoインタープリターは、言語構造を評価する明確な違いがある配列と汎用オブジェクトを区別します。

javascript:
  ra=[  "one",   "two",   "three"]; ra.a=4;
  ob={0:"one", 1:"two", 2:"three"}; ob.a=4;
  alert(
    ra            +"\n\n"+
    ob            +"\n\n"+
    ra.toSource() +"\n\n"+
    ra.a          +"\t .toSource() forgot me! \n\n"+
    ra.length     +"\t and my length! \n\n"+
    ob.toSource());
  ps=""; for(i in ra)ps+=i+" "; alert(ps);  /* NB .length is missing! */
  ps=""; for(i in ob)ps+=i+" "; alert(ps);

表示

一二三

[オブジェクトオブジェクト]

["一二三"]

4 .toSource()は私を忘れました! 

3と私の長さ! 

({0: "1"、1: "2"、2: "3"、a:4})

0 1 2 a0 1 2 a

すべてのオブジェクトが関数であるというステートメントについて:

123()or "abc"()または[]()or {}()またはobj()where objが以外のタイプの関数として任意のオブジェクトインスタンスを関数として使用することは、構文的にも意味的にも正しくないFunctionため、任意のオブジェクトINSTANCEはではありませんFunction。ただし、オブジェクトobjとタイプがのArray, Boolean, Date, ...場合、どのようにしobjてになりましたArray, Boolean, Date, ...か?とはArray, Boolean, Date, ...

javascript:
    alert([Array, Boolean, Date, Function, 
              Number, Object, RegExp, String] . join('\n\n') );

ディスプレイ

function Array() {
    [native code]
}

function Boolean() {
    [native code]
}

function Date() {
    [native code]
}

function Function() {
    [native code]
}

function Number() {
    [native code]
}

function Object() {
    [native code]
}

function RegExp() {
    [native code]
}

function String() {
    [native code]
}

いずれの場合も、等価でない場合、オブジェクトタイプはfunction定義として明示されるため、すべてのオブジェクトは関数であるというステートメントです。(意地悪は、オブジェクトのインスタンスとそのタイプの区別を意図的に覆い隠してぼやけたものです!それでも、これは「もう1つなしでは1つを持たない」ことを示しています!オブジェクトと関数!インスタンスとは反対です。)

機能とオブジェクトの両方のパラダイムは、JSインタープリターの低レベルの組み込みプリミティブ(Mathand JSONやなど)のプログラミングと実装の基本であるようtrueです。

 javascript:alert([Math, JSON, true.toSource()].join("\n\n"));

ディスプレイ

[object Math]

[object JSON]

(new Boolean(true))

Javascriptの開発時には、オブジェクト中心のプログラミングスタイル(OOPの-オブジェクト指向プログラミングスタイル-"の"は私自身の駄洒落です!) 。関数型プログラミング手法は、オートマトン、再帰関数、形式言語などの理論を研究する、より抽象的で難解な試験に追いやられました。ただし、これらの正式な考慮事項の長所は、特にFFのGeckoエンジン(つまり.toSource())に実装されているJavascriptに明らかに現れています。


関数のオブジェクト定義は、繰り返し関係として定義されているため、特に満足です!独自の定義を使用して定義されています!

function Function() { [native code] }
関数はオブジェクトなので、と同じ感情が保持され
function Object() { [native code] }ます。

他の定義のほとんどは、静的なターミナル値に静止します。ただし、これeval()は特に強力なプリミティブであるため、文字列は任意の機能を埋め込むこともできます。

繰り返しますが、上記で使用されている用語は、オブジェクトタイプとインスタンスの区別を覆い隠しています。


5

JavaScriptのすべては、プリミティブ型以外のオブジェクトです。

コード

var myArray = Array();

Arrayオブジェクトのインスタンスを作成しながら

var myObject = {'A': 'Athens', 'B':'Berlin'};

Objectオブジェクトのインスタンスを作成します。

次のコードを試してください

alert(myArray.constructor)
alert(myObject.constructor)

したがって、オブジェクトコンストラクターのタイプに違いがあることがわかります。

Arrayオブジェクトのインスタンスには、Arrayプロトタイプのすべてのプロパティとメソッドが含まれます。


2

配列とJavaScriptの他のオブジェクトの違い。配列には魔法のように長さを更新するプロパティがありますが、配列以外のオブジェクトの場合、そのようなプロパティを実装する方法はありません。

var arrName = [];
arrName[5] = "test";
arrName.length; // <- 6

配列は、序数のインデックスを持つものを格納するために使用されます-従来の配列、スタック、またはキューのように使用します。オブジェクトはハッシュです-異なるキーを持つデータに使用します。


2

名前付きプロパティはJavaScriptのほとんどすべてに追加できますが、そうする必要はありません。 代わりにArray連想配列を使用する場合は、JavaScriptのリストを使用する必要がありますObject

これらのArrayプロパティの代わりにwith名前付きプロパティを本当に使用したい場合Objectfor...ofループではアクセスできず、JSONエンコードしてそれを渡すときに予期しない結果が発生する可能性があることに注意してください。数値以外のすべてのインデックスが無視される以下の例を参照してください。

let arr = [];
let obj = {};

arr['name'] = 'John';
obj['name'] = 'John';

console.log(arr);    // will output [name: "John"]
console.log(obj);    // will output {name: "John"}

JSON.stringify(arr); // will return [] <- not what you expected
JSON.stringify(obj); // will return {"name":"John"}

-1

- {}表記は、コードをより良くするための構文上の砂糖です;-)

JavaScriptには、関数の構築のような類似した多くの構造があります。ここで、function()は、

var Func = new Function("<params>", "<code>");

3
関数コンストラクターは、関数リテラルの同義語ではありません。コンストラクターがグローバルである一方で、リテラルはレキシカルにスコープされます。{}はリテラルオブジェクト表記で[]あり、リテラル配列です。あなたの答えの意味が何なのかわかりません。
フアンメンデス

また、宣言された関数はコードが実行される前に使用できます。Functionコンストラクターを使用した割り当ては、それらを作成するコードが実行されるまで使用できません。
RobG 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.