`new Object()`とオブジェクトリテラル表記の違いは何ですか?


199

オブジェクトを作成するためのこのコンストラクタベースの構文の違いは何ですか?

person = new Object()

...そしてこのリテラル構文:

person = {
    property1 : "Hello"
};

JSLintではオブジェクトリテラル表記の使用を推奨していますが、どちらも同じことを行うようです。

どっちがいいの?なぜ?


7
すべて同じ:a = new Objecta = new Object()a = {}、リテラルがはるかに簡単であると私はしばらく前に走ったいくつかのテストは、それが高速であると言う、新しいコンパイラは私の文は偽であることを引き起こしている可能性があります。同じことがリテラル配列にも当てはまります
Juan Mendes、2011年

8
うまくいけばvar、アプリケーションコードでキーワードを使用して変数を宣言し、グローバルネームスペースの汚染を回避し、変数のスタック内の現在のレコードを超えて調べる必要を生じさせます。
サモ

1
基本的に、プログラムの実行中の任意の時点で、レコードまたはブロックのスタックがあります。各レコードには、そのスコープで作成された変数のリストがあります。JavaScriptでは、式に変数が含まれていて、インタプリタがそのスコープのスタックレコードでそれを見つけられない場合、変数が見つかるまで次のレコードに移動し続けます。詳細情報davidshariff.com/blog/…–
サモ

2
JSLintを回避することは、優れた開発者になるための最初のステップです。使用newは、平凡な言語の無意味なつまらないことを超越する規則です。new意味がはっきりしているので使ってください。ケースの99.9%では、パフォーマンスの向上は無関係です。
Hal50000 2016

1
誰によると@ Hal50000平凡な言語?
Xam

回答:


124

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のではなく{}(あなたがその非常に珍しい事をやった場合を除きます)。


11
著者はこの答えを正しいものとして選択しましたが、不完全です。メモリ割り当てに入るとき、2つの構文に違いがあることに注意してください。
newshorts '20年

2
違いはありません。プロトタイプベースのオブジェクトモデルと継承(そこにあるコードは、プレーンオブジェクトから継承するObjクラスをセットアップします)について話しているので、以下の答えの1つを参照している場合は、トピックから外れています。この質問は、カスタムクラスのインスタンスを作成することではありません。オブジェクトのインスタンスを作成することです。この質問に対する正しい答えは、「違いはありません」です。
dos

FYIも() new Object()必要ありません。(不要なものについて話している)
Royi Namir

現在の仕様では新品を使う必要はないと思います。あなたの考えを教えてください@kevin
Vamsi Pavan Mahesh

1
継承チェーンから継承しないオブジェクトが必要な場合は、Object createを使用してnullを渡すこともできます。それらは等しくなく、それぞれに有用な目的があります。
アーロン

234

あなたの例のようにメソッドのない単純なオブジェクトの違いはありません。ただし、オブジェクトにメソッドを追加し始めると、大きな違いがあります。

文字通りの方法:

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は、オブジェクトの各インスタンス内でメソッドのコピーを保持します。一方、プロトタイプの方法では、メソッドはオブジェクトプロトタイプで定義され、すべてのオブジェクトインスタンス間で共有されます。 多くのオブジェクトまたは多くのメソッドがある場合、文字通りの方法は非常に大きなメモリの浪費につながる可能性があります。


39
私にとっての質問は、new Object()vs {}を使用して空のオブジェクトを作成することの違いについての詳細でした。
Peter

11
@Lobabob最初の文を除いて、この回答は実際にはOPの質問に関する情報を提供しません。「new Object()」はどこにも含まれていません。率直に言って、デビッド氏はその質問を誤解したと思います。
JLRishe 14

17
私がこれを投稿したとき、受け入れられた回答はすでにそこにあり、受け入れられました。そして、それはOPの質問に完全に答えるので、同じことを繰り返すつもりはありませんでした。私は主に空の/単純なオブジェクトを超えて主題を広げるために私の回答を投稿しました。その場合にはそこ言及する価値がある重要な違いが。
レミーDAVID

3
この回答はトピックから外れています。コードでは、ObjはObjectから継承した独立したクラスです。オブジェクトリテラル表記を使用する場合は、ObjではなくObjectクラスを使用します。もちろん、プロトタイプにメソッドを含むクラスを設定すると、多くのプレーンオブジェクトを作成し、プロパティとしてメソッドを追加するよりもメモリフットプリントが小さくなりますが、これは、ここで尋ねた質問とはまったく関係ありません。この質問に対する正しい答えは、「いいえ、違いはまったくありません(読みやすさを除いて)」です。
dos

3
私は私のような質問に基づいてこの答えを求めましたが、最終的に私が知る必要があることを正確に学習しました。ありがとうございました。
Pat Migliaccio、2016

55

JavaScriptでは、次の2つの方法で新しい空のオブジェクトを宣言できます。

var obj1 = new Object();  
var obj2 = {};  

これら2つが舞台裏でどのように動作するかに関して、これら2つに大きな違いがあることを示唆するものは何もありません(私が間違っている場合は修正してください-知りたいです)。ただし、2番目の方法(オブジェクトリテラル表記を使用)にはいくつかの利点があります。

  1. 短い(正確には10文字)
  2. オンザフライでオブジェクトを作成する方が簡単で構造化されています
  3. 一部の道化師が誤ってオブジェクトをオーバーライドしたかどうかは関係ありません

メンバーNameとTelNoを含む新しいオブジェクトを考えます。新しいObject()規約を使用して、次のように作成できます。

var obj1 = new Object();  
obj1.Name = "A Person";  
obj1.TelNo = "12345"; 

ExpandoプロパティJavaScript機能を使用すると、このようにその場で新しいメンバーを作成でき、意図したとおりの結果が得られます。ただし、この方法はあまり構造化もカプセル化もされていません。作成時に、expandoプロパティや割り当て後の割り当てに依存することなく、メンバーを指定したい場合はどうでしょうか。

これは、オブジェクトリテラル表記が役立つ場所です。

var obj1 = {Name:"A Person",TelNo="12345"};  

ここでは、1行のコードで文字数を大幅に減らし、同じ効果を実現しています。

上記のオブジェクト構築メソッドの詳細については、JavaScriptおよびオブジェクト指向プログラミング(OOP)を参照してください。

そして最後に、オブジェクトをオーバーライドしたバカはどうですか?それは不可能だと思いましたか?そうですね、このJSFiddleはそれ以外のことを証明しています。オブジェクトリテラル表記を使用すると、このバッファローのファウルに陥るのを防ぐことができます。

http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/から)


1
Object.Createはどうですか?参照:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
フィル

new Object()何かがObject関数を上書きした可能性があるためにオブジェクトリテラルを優先する場合は、ヘルパーを使用Object.keysして、それが未定義ではないことを確認するために、いたるところにガードを作成する必要があります。私は常に人々に文字表記を使用することをお勧めしますが、そのように考えることの結果を考えると、この特定の議論はばらばらになると思います。
philraj 2018

41

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を使用して空のオブジェクト/配列を作成するよりも高速です。


3
私はこれが質問が本当に探していた答えであるように感じますが、確認するためにいくつかのプロパティを持つオブジェクトでこれをさらにテストしたいのですが。
チェイスサンドマン2014

2
興味深い数字。これを知っておく必要がある人もいますが、わずか200,000個のオブジェクトを割り当てるだけでも5.6msのコストがかかるため、心配する必要はありません。

ノード10.13.0で変更されたテスト配列:using []:117.178ms new:116.947msテストオブジェクト:using {}:116.252ms using new:115.910ms
PirateApp

31

ここの誰もが2つの類似点について話している。違いを指摘しておきます。

  1. を使用new Object()すると、別のオブジェクトを渡すことができます。明らかな結果は、新しく作成されたオブジェクトが同じ参照に設定されることです。これがサンプルコードです:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. 使用方法は、OOPオブジェクトのようにオブジェクトに限定されません。他のタイプもそれに渡すことができます。関数はそれに応じてタイプを設定します。たとえば、整数1を渡すと、number型のオブジェクトが作成されます。

    var obj = new Object(1);
    typeof obj // "number"
  3. 上記のメソッド(new Object(1))を使用して作成されたオブジェクトは、プロパティが追加されるとオブジェクトタイプに変換されます。

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. オブジェクトがオブジェクトの子クラスのコピーである場合、型変換なしでプロパティを追加できます。

    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

3
私は最後の2行について非常に混乱しています。なぜstr.aに値1を割り当てた場合、str.aは未定義ですか?.. @Jermin Bazazin
Andrea Scarafoni 14

3
@AndreaScarafoni strは型であるstringため、プロパティを割り当てることができません。jsfiddle.net/grq6hdx7/1
Chris Bier

1
4への答えは変わりましたか?最新のChrome 53ではvar obj = new Object("foo"); typeof obj; obj === "foo" // true
ウィリアムヒルトン

21

実際、JavaScriptでオブジェクトを作成する方法はいくつかあります。オブジェクトを作成したいだけの場合、「new」演算子を使用して「コンストラクタベースの」オブジェクトを作成するメリットはありません。「オブジェクトリテラル」構文を使用してオブジェクトを作成するのと同じです。しかし、「プロトタイプの継承」について考えていると、「new」演算子で作成された「コンストラクタベースの」オブジェクトが信じられないほど使用されます。リテラル構文で作成されたオブジェクトの継承チェーンは維持できません。ただし、コンストラクター関数を作成し、そのプロトタイプにプロパティとメソッドをアタッチできます。"演算子、それはそのコンストラクター関数のプロトタイプに添付されたすべてのメソッドとプロパティにアクセスできるオブジェクトを返します。

コンストラクター関数を使用してオブジェクトを作成する例を次に示します(下部のコードの説明を参照)。

function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
}

Person.prototype.fullname = function() {
    console.log(this.firstname + ' ' + this.lastname);
}

var zubaer = new Person('Zubaer', 'Ahammed');
var john = new Person('John', 'Doe');

zubaer.fullname();
john.fullname();

これで、Person構築関数をインスタンス化することで、必要な数のオブジェクトを作成でき、それらすべてからfullname()が継承されます。

注:「this」キーワードはコンストラクター関数内の空のオブジェクトを参照し、「new」演算子を使用してPersonから新しいオブジェクトを作成すると、「this」キーワードが付加されたすべてのプロパティとメソッドを含むオブジェクトを自動的に返します。そして、これらのオブジェクトは確実に、Personコンストラクター関数のプロトタイプにアタッチされたメソッドとプロパティを継承します(これがこのアプローチの主な利点です)。

ちなみに、「オブジェクトリテラル」構文で同じ機能を取得したい場合は、以下のようにすべてのオブジェクトにfullname()を作成する必要があります。

var zubaer = {
    firstname: 'Zubaer',
    lastname: 'Ahammed',
    fullname: function() {
        console.log(this.firstname + ' ' + this.lastname);
    }
};

var john= {
    firstname: 'John',
    lastname: 'Doe',
    fullname: function() {
        console.log(this.firstname + ' ' + this.lastname);
    }
};

zubaer.fullname();
john.fullname();

最後に、なぜオブジェクトリテラルアプローチではなくコンストラクタ関数アプローチを使用する必要があるのか​​を尋ねた場合:

***プロトタイプの継承により、非常に便利で強力な継承の単純なチェーンが可能になります。

***コンストラクター関数プロトタイプで定義された共通のメソッドとプロパティを継承することにより、メモリを節約します。それ以外の場合は、すべてのオブジェクトでそれらを何度もコピーする必要があります。

これが理にかなっているといいのですが。


ありがとう!オブジェクトリテラルに不足している「this」を追加してくれたKarl。それは恐ろしい間違いだった。私はこの種の間違いをするべきではなかった。
Md。Zubaer Ahammed 2016

「リテラル構文で作成されたオブジェクトから継承することはできません。」-真実ではない(私は信じている)。Object.create(<object defined using literal notation>)またはnew Object(<object defined using literal notation>)必要に応じて継承チェーンを作成できます。
balajeerc

@balajeercコメントありがとうございます。実際には、「リテラル構文で作成されたオブジェクトでは継承チェーンを維持できない」はずです。複数のステップでの回答:1. Object.create():はい、オブジェクトリテラルをそれに渡すことが可能で、プロトタイプがオブジェクトリテラルを渡した新しいオブジェクトを返します。しかし、それはそれがコンストラクター関数であるかを知らないか、それが作成された元のオブジェクトリテラルを覚えていません。したがって、testobj1.constructorは空の関数を返し、そのオブジェクトリテラルが親/祖先であるため、そのオブジェクトリテラルにプロパティ/メソッドを追加する方法はありません。
Md。Zubaer Ahammed 2016年

@balajeerc 2. new Object():この場合、ほとんど同じことが起こります。さらに、あなたが記憶について考えるならば、それはより悪いです。プロトタイプにプロパティとメソッドを配置する代わりに、渡されたオブジェクトリテラルからすべてをコピーして、返されたオブジェクトに配置します。記憶に良くない。一方、メソッドとプロパティをその場で編集できるコンストラクター関数を使用した真の継承チェーンに焦点を当てました。コンストラクターメソッドを使用して作成された他のオブジェクトも、それらを(コピーするのではなく)そのコンストラクター関数のみを指しているため、影響を受けます。 。
Md。Zubaer Ahammed 2016年

@balajeercの例:function Person(firstname, lastname) { this.firstname = firstname; this.lastname = lastname; } Person.prototype.fullname = function() { console.log(this.firstname + ' ' + this.lastname); } var zubaer = new Person('Zubaer', 'Ahammed'); var john = new Person('John', 'Doe'); zubaer.fullname(); // Zubaer Ahammed john.fullname(); // John Doe zubaer.constructor.prototype.fullname = function() { console.log( 'Hello ' + this.firstname); } zubaer.fullname(); // Hello Zubaer john.fullname(); // Hoello John
Md。Zubaer Ahammed '11

9

また、一部のO'Really JavaScriptブックによると...(引用)

Objectコンストラクターとは対照的にリテラルを使用するもう1つの理由は、スコープ解決がないためです。同じ名前のローカルコンストラクターを作成した可能性があるため、インタープリターは、Object()を呼び出している場所から、グローバルオブジェクトコンストラクターが見つかるまで、スコープチェーンを検索する必要があります。


24
O'Reallyはタイプミスなのか、それとも故意のしゃれなのか。彼らは本をマーケティングするためにそれを使うべきです!
Tim Ogilvy

3

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 } ]

これは、コンパイラーが{}大括弧で混乱し、label:ステートメント構造でn: iあると考えているためです。セミコロンはオプションであるため、不満はありません。

オブジェクトに別のプロパティを追加すると、最終的にエラーがスローされます。

$ 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 :

4
アロー関数を使用することもできます。ブレースとリターンを追加するだけ[1, 2, 3].map(v => { return {n: v}; });です。同じ結果が得られます...
Heretic Monkey

もちろん、通常の矢印関数を使用することもできます。私が話していたのは、短縮形、つまりと、この場合のparam => return_valueとの違いです。{}new Object()
Andrei Simionescu 2016

11
短縮形と通常の矢印関数は引き続き使用できます。:{:V n}は、括弧の対とちょうどラップ[1, 2, 3].map(v => ({n: v}));
スティーブンC

1

2019アップデート

OSX High Sierra 10.13.6ノードバージョン10.13.0で@rjlouraと同じコードを実行しました。これらは結果です

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');


Testing Array:
using[]: 117.613ms
using new: 117.168ms
Testing Object:
using{}: 117.205ms
using new: 118.644ms

-2

1万個のインスタンスを作成すると、メモリ使用量は異なります。 new Object()1部のみを保持し、1 {}万部を保持します。


7
new新しいオブジェクトを作成します。どちらも同じ量のメモリを使用します。
Artyer 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.