web-dev-qa-db-ja.com

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

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

person = new Object()

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

person = {
    property1 : "Hello"
};

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

どちらが優れているのですか?

185
ectype

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"
};

技術的には同じことをしないでください。最初はオブジェクトを作成するだけです。 2番目は、1つを作成し、プロパティを割り当てます。最初のものを同じにするには、プロパティを作成して割り当てるための2番目の手順が必要です。

誰かができる「異常な」ことは、シャドウするか、デフォルトのObjectグローバルに割り当てることです。

// Don't do this
Object = 23;

その非常に珍しい場合、new Objectは失敗しますが、{}は機能します。

実際には、new Objectではなく{}を使用する理由はありません(非常に珍しいことをやった場合を除きます)。

115
kemiller2002

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

リテラルの方法:

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

220
Rémy DAVID

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

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

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

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

メンバー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行のコードで同じ効果を達成し、文字数を大幅に削減しています。

上記のオブジェクト構築方法の詳細については、次のURLをご覧ください。 JavaScriptおよびオブジェクト指向プログラミング(OOP)。

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

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

53
James Wiseman

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を使用するよりも、明らかに{}と[]の方が高速です。

39
rjloura

ここの誰もが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
    
29
Jermin Bazazian

実際、JavaScriptでオブジェクトを作成する方法はいくつかあります。オブジェクトを作成したいだけの場合、「constructor-based」オブジェクトを「new」演算子を使用して作成してもメリットはありません。 「object literal」構文を使用してオブジェクトを作成するのと同じです。しかし、「constructor-based」オブジェクトを「new」演算子で作成すると、「prototypal inheritance」について考えているときに信じられないほど使用できます。リテラル構文で作成されたオブジェクトで継承チェーンを維持することはできません。ただし、constructor functionを作成し、そのプロトタイプにプロパティとメソッドを添付できます。次に、「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コンストラクター関数のprototypeでアタッチされたメソッドとプロパティを継承します(これがこのアプローチの主な利点です)。

ところで、 "object literal"構文で同じ機能を取得したい場合は、以下のようにすべてのオブジェクトで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();

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

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

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

これが理にかなっていることを願っています。

17

また、いくつかのO'Really javascriptブックによると...(引用)

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

8
adolfo_isassi

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: ilabel: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 :
3

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
0
PirateApp