オブジェクトを作成するためのこのコンストラクターベースの構文の違いは何ですか:
person = new Object()
...そしてこのリテラル構文:
person = {
property1 : "Hello"
};
JSLint はオブジェクト リテラル表記を使用することを好みますが、どちらも同じことを行うようです。
どちらが優れているのか、その理由は?
オブジェクトを作成するためのこのコンストラクターベースの構文の違いは何ですか:
person = new Object()
...そしてこのリテラル構文:
person = {
property1 : "Hello"
};
JSLint はオブジェクト リテラル表記を使用することを好みますが、どちらも同じことを行うようです。
どちらが優れているのか、その理由は?
例のように、メソッドのない単純なオブジェクトに違いはありません。ただし、オブジェクトにメソッドを追加し始めると、大きな違いがあります。
文字通りの方法:
function Obj( prop ) {
return {
p : prop,
sayHello : function(){ alert(this.p); },
};
}
プロトタイプの方法:
function Obj( prop ) {
this.p = prop;
}
Obj.prototype.sayHello = function(){alert(this.p);};
どちらの方法でも、次のObj
ようなインスタンスを作成できます。
var foo = new Obj( "hello" );
ただし、文字通りの方法でsayHello
は、オブジェクトの各インスタンス内にメソッドのコピーを持ち運びます。一方、プロトタイプの方法では、メソッドはオブジェクトプロトタイプで定義され、すべてのオブジェクトインスタンス間で共有されます。
多くのオブジェクトまたは多くのメソッドがある場合、文字通りの方法は非常に大きなメモリの浪費につながる可能性があります。
2 番目のオブジェクトがオブジェクトを作成し、それにプロパティを追加することを除けば、どちらも同じことを行います (誰かが異常なことをした場合を除きます)。ただし、リテラル表記はソース コード内で必要なスペースが少なくて済みます。何が起こっているのかがはっきりと認識できるので、 を使用するnew Object()
と、実際には入力が増えるだけであり (理論的には、JavaScript エンジンによって最適化されていない場合)、不要な関数呼び出しを行っています。
これらは
person = new Object() /*You should put a semicolon here too.
It's not required, but it is good practice.*/
-or-
person = {
property1 : "Hello"
};
技術的には同じことをしないでください。1 つ目はオブジェクトを作成するだけです。2 番目は、1 つを作成し、プロパティを割り当てます。最初のものを同じにするには、プロパティを作成して割り当てるための 2 番目のステップが必要です。
誰かができる「異常なこと」は、デフォルトのObject
グローバルをシャドウまたは割り当てることです。
// Don't do this
Object = 23;
その非常に珍しいケースでnew Object
は、失敗します{}
が動作します。
実際には、new Object
むしろ使用する理由はありませ{}
ん (非常に珍しいことをした場合を除きます)。
JavaScript では、次の 2 つの方法で新しい空のオブジェクトを宣言できます。
var obj1 = new Object();
var obj2 = {};
これら 2 つが舞台裏でどのように動作するかに関して、大きな違いがあることを示唆するものは何も見つかりませんでした (間違っている場合は訂正してください。知りたいです)。ただし、2 番目の方法 (オブジェクト リテラル表記を使用) には、いくつかの利点があります。
メンバ Name と TelNo を含む新しいオブジェクトを考えてみましょう。新しい Object() 規則を使用すると、次のように作成できます。
var obj1 = new Object();
obj1.Name = "A Person";
obj1.TelNo = "12345";
JavaScriptのExpando Properties機能を使用すると、この方法でその場で新しいメンバーを作成でき、意図したことを達成できます。ただし、この方法はあまり構造化またはカプセル化されていません。expando プロパティや作成後の代入に依存することなく、作成時にメンバーを指定したい場合はどうなるでしょうか?
これは、オブジェクト リテラル表記が役立つ場所です。
var obj1 = {Name:"A Person",TelNo="12345"};
ここでは、1 行のコードと大幅に少ない文字数で同じ効果を実現しています。
上記のオブジェクト構築方法の詳細については、JavaScript およびオブジェクト指向プログラミング (OOP) を参照してください。
そして最後に、Object を覆した馬鹿はどうなる?ありえないと思った?さて、この JSFiddleはそうではないことを証明しています。オブジェクトリテラル表記を使用することで、この道化師にだまされるのを防ぐことができます。
( http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/より)
Node.js を使用しているマシンで、次のコマンドを実行しました。
console.log('Testing Array:');
console.time('using[]');
for(var i=0; i<200000000; i++){var arr = []};
console.timeEnd('using[]');
console.time('using new');
for(var i=0; i<200000000; i++){var arr = new Array};
console.timeEnd('using new');
console.log('Testing Object:');
console.time('using{}');
for(var i=0; i<200000000; i++){var obj = {}};
console.timeEnd('using{}');
console.time('using new');
for(var i=0; i<200000000; i++){var obj = new Object};
console.timeEnd('using new');
これは、次の内容の拡張であることに注意してください:なぜ arr = [] は arr = new Array よりも高速ですか?
私の出力は次のとおりです。
Testing Array:
using[]: 1091ms
using new: 2286ms
Testing Object:
using{}: 870ms
using new: 5637ms
明らかに、{} と [] は、空のオブジェクト/配列を作成するために new を使用するよりも高速です。
ここにいる誰もが、この 2 つの類似点について話しています。違いを指摘していきます。
を使用new Object()
すると、別のオブジェクトを渡すことができます。明らかな結果は、新しく作成されたオブジェクトが同じ参照に設定されることです。サンプルコードは次のとおりです。
var obj1 = new Object();
obj1.a = 1;
var obj2 = new Object(obj1);
obj2.a // 1
使用法は、OOP オブジェクトのようにオブジェクトに限定されません。他のタイプも渡すことができます。関数はそれに応じてタイプを設定します。たとえば、整数 1 を渡すと、number 型のオブジェクトが作成されます。
var obj = new Object(1);
typeof obj // "number"
上記のメソッド ( new Object(1)
) を使用して作成されたオブジェクトは、プロパティが追加されるとオブジェクト型に変換されます。
var obj = new Object(1);
typeof obj // "number"
obj.a = 2;
typeof obj // "object"
オブジェクトがオブジェクトの子クラスのコピーである場合、型変換なしでプロパティを追加できます。
var obj = new Object("foo");
typeof obj // "object"
obj === "foo" // true
obj.a = 1;
obj === "foo" // true
obj.a // 1
var str = "foo";
str.a = 1;
str.a // undefined
また、O'Really javascriptの本のいくつかによると....(引用)
オブジェクトコンストラクターとは対照的にリテラルを使用するもう1つの理由は、スコープの解決がないことです。同じ名前のローカルコンストラクターを作成した可能性があるため、インタープリターは、Object()を呼び出している場所から、グローバルObjectコンストラクターが見つかるまでスコープチェーンを検索する必要があります。
ES6/ES2015 の場合、1 つの違いが見つかりました。オブジェクトを で囲まない限り、簡略矢印関数構文を使用してオブジェクトを返すことはできませんnew Object()
。
> [1, 2, 3].map(v => {n: v});
[ undefined, undefined, undefined ]
> [1, 2, 3].map(v => new Object({n: v}));
[ { n: 1 }, { n: 2 }, { n: 3 } ]
これは、コンパイラが{}
角かっこによって混乱し、これn: i
をlabel: statement構造体と見なすためです。セミコロンはオプションなので、文句はありません。
オブジェクトに別のプロパティを追加すると、最終的にエラーがスローされます。
$ node -e "[1, 2, 3].map(v => {n: v, m: v+1});"
[1, 2, 3].map(v => {n: v, m: v+1});
^
SyntaxError: Unexpected token :
オブジェクトの初期化に「新しい」キーワードを使用するのは、インライン矢印関数のみです。
() => new Object({ key: value})
以下のコードは有効ではないため:
() => { key: value} // instead of () => { return { key: value};}
10,000 インスタンスを作成すると、メモリ使用量が異なります。
new Object()
は 1 部のみ保持します{}
が、10,000 部は保持します。