Apa perbedaan antara `Objek baru ()` dan notasi literal objek?

199

Apa perbedaan antara sintaksis berbasis konstruktor ini untuk membuat objek:

person = new Object()

... dan sintaks literal ini:

person = {
    property1 : "Hello"
};

Tampaknya keduanya melakukan hal yang sama, meskipun JSLint lebih suka Anda menggunakan notasi objek literal.

Mana yang lebih baik dan mengapa?

ectype
sumber
7
Semua sama: a = new Object, a = new Object(), a = {}, literal jauh lebih sederhana dan beberapa tes aku berlari sambil lalu mengatakan itu adalah lebih cepat, kompiler yang lebih baru mungkin telah menyebabkan pernyataan saya palsu. Hal yang sama berlaku untuk array literal
Juan Mendes
8
Semoga Anda mendeklarasikan variabel Anda dengan varkata kunci dalam kode aplikasi Anda untuk menghindari mencemari namespace global dan menciptakan kebutuhan untuk melihat melampaui catatan saat ini dalam tumpukan untuk variabel Anda.
Samo
1
Pada dasarnya, pada titik mana pun selama pelaksanaan suatu program, ada setumpuk catatan atau blok. Setiap catatan memiliki daftar variabel yang dibuat dalam cakupan itu. Dalam JavaScript, jika ekspresi berisi variabel dan juru bahasa tidak dapat menemukannya di tumpukan catatan untuk cakupan itu, itu akan terus naik ke catatan berikutnya sampai menemukan variabel. Info lebih lanjut davidshariff.com/blog/…
Samo
2
Menghindari JSLint's adalah langkah pertama untuk menjadi pengembang yang baik. Menggunakan newadalah sebuah konvensi yang melampaui nitpicking sia-sia dari bahasa yang biasa-biasa saja. Gunakan newkarena maknanya jelas. Dalam 99,9% kasus, keuntungan kinerja tidak relevan.
Hal50000
1
@ Hal50000 bahasa biasa-biasa saja menurut siapa?
Xam

Jawaban:

124

Mereka berdua melakukan hal yang sama (kecuali seseorang melakukan sesuatu yang tidak biasa), selain itu orang kedua Anda membuat objek dan menambahkan properti ke sana. Tetapi notasi literal membutuhkan lebih sedikit ruang dalam kode sumber. Ini jelas dikenali apa yang terjadi, jadi menggunakan new Object(), Anda benar-benar hanya mengetik lebih banyak dan (secara teori, jika tidak dioptimalkan oleh mesin JavaScript) melakukan pemanggilan fungsi yang tidak perlu.

Ini

person = new Object() /*You should put a semicolon here too.  
It's not required, but it is good practice.*/ 
-or-

person = {
    property1 : "Hello"
};

secara teknis tidak melakukan hal yang sama. Yang pertama hanya menciptakan objek. Yang kedua menciptakan dan menetapkan properti. Agar yang pertama sama, Anda perlu langkah kedua untuk membuat dan menetapkan properti.

"Sesuatu yang tidak biasa" yang bisa dilakukan seseorang adalah membayangi atau menetapkan ke Objectglobal default :

// Don't do this
Object = 23;

Dalam kasus yang sangat tidak biasa itu, new Objectakan gagal tetapi {}akan berhasil.

Dalam praktiknya, tidak pernah ada alasan untuk menggunakan new Objectdaripada {}(kecuali Anda telah melakukan hal yang sangat tidak biasa).

kemiller2002
sumber
11
Penulis memilih jawaban ini sebagai benar, tetapi tidak lengkap. Sadarilah ada perbedaan antara kedua sintaks ketika Anda masuk ke alokasi memori.
newshorts
2
Tidak ada perbedaan. Jika Anda merujuk ke salah satu jawaban di bawah, itu di luar topik, karena berbicara tentang model objek berbasis warisan dan pewarisan (kode di sana membuat kelas Obj yang diwarisi dari Objek biasa). Pertanyaan ini bukan tentang membuat turunan dari beberapa kelas kustom - ini tentang membuat turunan dari Objek, dan jawaban yang benar untuk pertanyaan ini adalah "tidak ada perbedaan".
dos
FYI juga () new Object()tidak diperlukan. (berbicara tentang tidak diperlukan thingy)
Royi Namir
Saya pikir kita tidak perlu menggunakan yang baru pada spesifikasi saat ini. Biarkan aku tahu apa yang kamu pikirkan @kevin
Vamsi Pavan Mahesh
1
Anda juga bisa menggunakan Object create dan pass null jika Anda menginginkan objek yang tidak diwarisi dari rantai pewarisan. Mereka tidak sama dan memiliki tujuan yang bermanfaat masing-masing.
Aaron
234

Tidak ada perbedaan untuk objek sederhana tanpa metode seperti pada contoh Anda. Namun, ada perbedaan besar ketika Anda mulai menambahkan metode ke objek Anda.

Cara literal:

function Obj( prop ) { 
    return { 
        p : prop, 
        sayHello : function(){ alert(this.p); }, 
    }; 
} 

Cara prototipe:

function Obj( prop ) { 
    this.p = prop; 
} 
Obj.prototype.sayHello = function(){alert(this.p);}; 

Kedua cara memungkinkan pembuatan instance Objseperti ini:

var foo = new Obj( "hello" ); 

Namun, dengan cara literal, Anda membawa salinan sayHellometode dalam setiap instance objek Anda. Sedangkan, dengan cara prototipe, metode didefinisikan dalam prototipe objek dan dibagi di antara semua instance objek. Jika Anda memiliki banyak objek atau banyak metode, cara literalnya dapat menyebabkan pemborosan memori yang cukup besar.

Rémy DAVID
sumber
39
Bagi saya pertanyaannya lebih tentang perbedaan antara menggunakan new Object()vs {}untuk membuat objek kosong.
Peter
11
@Lobabob Selain kalimat pertama, jawaban ini tidak benar-benar memberikan informasi tentang pertanyaan OP. Bahkan tidak mengandung 'Objek baru () `di mana pun. Terus terang, saya pikir Pak David salah mengerti pertanyaan itu.
JLRishe
17
Ketika saya memposting ini jawaban yang diterima sudah ada di sana dan diterima. Dan itu dengan sempurna menjawab pertanyaan OP jadi saya tidak akan mengulangi hal yang sama. Saya memposting jawaban saya terutama untuk memperluas subjek di luar objek kosong / sederhana. Dalam hal ini ada adalah perbedaan penting yang layak disebutkan.
Rémy DAVID
3
Jawaban ini di luar topik. Dalam kode Anda, Obj adalah kelas terpisah yang mewarisi dari Objek. Saat Anda menggunakan notasi objek literal, Anda menggunakan kelas objek, bukan Obj. Tentu saja membuat kelas dengan metode dalam prototipenya akan membuat jejak memori lebih kecil daripada membuat banyak Obyek sederhana dan menambahkan metode sebagai propertinya, tetapi itu sama sekali tidak terkait dengan pertanyaan yang diajukan di sini. Jawaban yang benar untuk pertanyaan ini adalah "tidak, sama sekali tidak ada perbedaan (mungkin kecuali keterbacaan)".
dos
3
Saya datang untuk jawaban ini, berdasarkan pertanyaan yang agak mirip dengan saya, tetapi akhirnya belajar persis apa yang perlu saya ketahui. Terima kasih.
Pat Migliaccio
55

Dalam JavaScript, kami dapat mendeklarasikan objek kosong baru dengan dua cara:

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

Saya tidak menemukan apa pun yang menunjukkan bahwa ada perbedaan yang signifikan antara keduanya sehubungan dengan bagaimana mereka beroperasi di belakang layar (tolong perbaiki saya jika saya salah - saya ingin tahu). Namun, metode kedua (menggunakan notasi objek literal) menawarkan beberapa keuntungan.

  1. Itu lebih pendek (tepatnya 10 karakter)
  2. Lebih mudah, dan lebih terstruktur untuk membuat objek dengan cepat
  3. Tidak masalah jika beberapa badut telah secara tidak sengaja menimpa Object

Pertimbangkan objek baru yang berisi Nama anggota dan TelNo. Menggunakan konvensi Object () baru, kita dapat membuatnya seperti ini:

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

Fitur Properti Expando dari JavaScript memungkinkan kami membuat anggota baru dengan cepat, dan kami mencapai apa yang ingin dicapai. Namun, cara ini tidak terlalu terstruktur atau dienkapsulasi. Bagaimana jika kita ingin menentukan anggota berdasarkan kreasi, tanpa harus bergantung pada properti expo dan penugasan pasca kreasi?

Di sinilah objek notasi literal dapat membantu:

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

Di sini kami telah mencapai efek yang sama dalam satu baris kode dan karakter yang jauh lebih sedikit.

Diskusi lebih lanjut metode konstruksi objek di atas dapat ditemukan di: JavaScript dan Pemrograman Berorientasi Objek (OOP).

Dan akhirnya, bagaimana dengan orang idiot yang mengalahkan Object? Apakah Anda pikir itu tidak mungkin? Nah, JSFiddle ini membuktikan sebaliknya. Menggunakan objek notasi literal mencegah kita dari kejatuhan lawak ini.

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

James Wiseman
sumber
1
Bagaimana dengan Object.Create? Lihat: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Phil
Jika Anda akan lebih menyukai objek literal new Object()karena kemungkinan sesuatu menimpa fungsi Objek, Anda juga harus menulis penjaga di semua tempat ketika Anda menggunakan pembantu ingin Object.keysmemastikan itu tidak terdefinisi, yang turun menjadi absurd. Saya selalu merekomendasikan orang menggunakan notasi literal, tetapi saya pikir argumen khusus ini berantakan ketika Anda memikirkan konsekuensi dari berpikir seperti itu.
philraj
41

Di komputer saya menggunakan Node.js, saya menjalankan yang berikut:

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

Catatan, ini merupakan perluasan dari apa yang ditemukan di sini: Mengapa arr = [] lebih cepat dari arr = new Array?

output saya adalah sebagai berikut:

Testing Array:
using[]: 1091ms
using new: 2286ms
Testing Object:
using{}: 870ms
using new: 5637ms

jadi jelas {} dan [] lebih cepat daripada menggunakan baru untuk membuat objek / array kosong.

rlloura
sumber
3
Saya merasa ini adalah jawaban yang pertanyaannya benar-benar cari, walaupun saya ingin melihat ini diuji pada objek dengan beberapa properti untuk memastikan.
Chase Sandmann
2
Angka yang menarik. Ada orang yang perlu menyadari hal ini, tetapi saya mengambil bahwa mengalokasikan bahkan 200.000 objek yang sedikit hanya akan menelan biaya 5,6 ms, jadi saya tidak akan khawatir tentang hal itu.
Pada Node 10.13.0 hal-hal YANG TELAH DIUBAH Pengujian Array: using []: 117.178ms menggunakan yang baru: 116.947ms Objek Pengujian: using {}: 116.252ms menggunakan yang baru: 115.910ms
PirateApp
31

Semua orang di sini berbicara tentang kesamaan keduanya. Saya akan menunjukkan perbedaannya.

  1. Menggunakan new Object()memungkinkan Anda untuk melewati objek lain. Hasil yang jelas adalah bahwa objek yang baru dibuat akan diatur ke referensi yang sama. Berikut ini contoh kode:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. Penggunaannya tidak terbatas pada objek seperti pada objek OOP. Tipe lain juga bisa diteruskan. Fungsi akan mengatur jenis sesuai. Misalnya jika kita meneruskan bilangan bulat 1 ke sana, objek nomor tipe akan dibuat untuk kita.

    var obj = new Object(1);
    typeof obj // "number"
  3. Objek yang dibuat menggunakan metode di atas ( new Object(1)) akan dikonversi ke tipe objek jika properti ditambahkan padanya.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. Jika objek adalah salinan kelas objek anak, kita bisa menambahkan properti tanpa konversi tipe.

    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
Jermin Bazazian
sumber
3
aku sangat bingung tentang dua baris terakhir .. Kenapa jika Anda menetapkan untuk str.a nilai 1, str.a tidak terdefinisi .. @Jermin Bazazin?
Andrea Scarafoni
3
@AndreaScarafoni karena strtipe stringsehingga Anda tidak dapat menetapkan properti untuk itu. jsfiddle.net/grq6hdx7/1
Chris Bier
1
Apakah jawaban ke 4 berubah? Saya salah, tidak benar, di Chrome 53 terbaru var obj = new Object("foo"); typeof obj; obj === "foo" // true
William Hilton
21

Sebenarnya, ada beberapa cara untuk membuat objek dalam JavaScript. Saat Anda hanya ingin membuat objek, tidak ada untungnya membuat objek " berbasis konstruktor " menggunakan operator " baru ". Ini sama dengan membuat objek menggunakan sintaks " objek literal ". Tetapi objek " berbasis konstruktor " yang dibuat dengan operator " baru " mulai digunakan secara luar biasa ketika Anda berpikir tentang " warisan prototypal ". Anda tidak dapat mempertahankan rantai pewarisan dengan objek yang dibuat dengan sintaks literal. Tetapi Anda dapat membuat fungsi konstruktor , melampirkan properti dan metode ke prototipe."Operator, itu akan mengembalikan objek yang akan memiliki akses ke semua metode dan properti yang dilampirkan dengan prototipe fungsi konstruktor itu.

Berikut adalah contoh membuat objek menggunakan fungsi konstruktor (lihat penjelasan kode di bagian bawah):

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

Sekarang, Anda dapat membuat objek sebanyak yang Anda inginkan dengan membuat fungsi konstruksi Person dan semuanya akan mewarisi nama lengkap () darinya.

Catatan: kata kunci " ini " akan merujuk ke objek kosong dalam fungsi konstruktor dan setiap kali Anda membuat objek baru dari Orang yang menggunakan operator " baru ", kata kunci ini akan secara otomatis mengembalikan objek yang berisi semua properti dan metode yang dilampirkan dengan kata kunci " ini " . Dan objek ini pasti akan mewarisi metode dan properti yang dilampirkan dengan prototipe fungsi konstruktor Person (yang merupakan keuntungan utama dari pendekatan ini).

Omong-omong, jika Anda ingin mendapatkan fungsionalitas yang sama dengan sintaks " objek literal ", Anda harus membuat nama lengkap () pada semua objek seperti di bawah ini:

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

Akhirnya, jika Anda sekarang bertanya mengapa saya harus menggunakan pendekatan fungsi konstruktor alih-alih pendekatan objek literal :

*** Warisan prototipe memungkinkan rantai pewarisan sederhana yang bisa sangat berguna dan kuat.

*** Ini menghemat memori dengan mewarisi metode umum dan properti yang didefinisikan dalam prototipe fungsi konstruktor. Jika tidak, Anda harus menyalinnya berulang-ulang di semua objek.

Saya harap ini masuk akal.

Md. Zubaer Ahammed
sumber
Terima kasih! Karl untuk menambahkan "this" yang hilang dalam objek literal. Itu adalah kesalahan yang mengerikan..aku seharusnya tidak membuat kesalahan seperti ini.
Ny. Zubaer Ahammed
"Anda tidak dapat mewarisi dari objek yang dibuat dengan sintaks literal." - Tidak benar (saya percaya). Anda dapat menggunakan Object.create(<object defined using literal notation>)atau new Object(<object defined using literal notation>)dan membuat rantai warisan sesuai kebutuhan.
balajeerc
@balajeerc Terima kasih atas komentar Anda. Sebenarnya seharusnya "Anda tidak dapat mempertahankan rantai pewarisan dengan objek yang dibuat dengan sintaks literal". Penjawab dalam beberapa langkah: 1. Object.create (): Ya, dimungkinkan untuk meneruskan objek literal ke sana dan itu akan mengembalikan objek baru prototipe yang akan melewati objek literal. Tetapi tidak tahu apa itu fungsi konstruktor atau tidak ingat objek literal dari mana ia dibuat. Jadi, testobj1.constructor akan mengembalikan fungsi kosong dan tidak akan ada cara untuk menambahkan properti / metode ke objek literal seperti orang tua / leluhurnya.
Ny. Zubaer Ahammed
@balajeerc 2. Obyek baru (): Hal yang hampir sama terjadi dalam kasus ini. Selain itu, lebih buruk jika Anda berpikir tentang memori. Alih-alih menempatkan properti dan metode ke prototipe itu, itu hanya menyalin segala sesuatu dari objek yang dilewatkan secara literal dan memasukkannya ke objek yang dikembalikan. Ini tidak baik untuk memori. Di sisi lain, saya fokus pada rantai pewarisan sejati dengan fungsi konstruktor di mana Anda dapat mengedit metode dan properti dengan cepat dan objek lain yang dibuat menggunakan metode konstruktor juga terpengaruh karena mereka menunjuk ke fungsi konstruktor saja (alih-alih menyalinnya) .
Ny. Zubaer Ahammed
@balajeerc Contoh: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
9

Juga, menurut beberapa buku javascript O'Really .... (dikutip)

Alasan lain untuk menggunakan literal yang bertentangan dengan konstruktor Obyek adalah bahwa tidak ada resolusi ruang lingkup. Karena mungkin Anda telah membuat konstruktor lokal dengan nama yang sama, penafsir perlu mencari rantai lingkup dari tempat Anda memanggil Object () sepanjang jalan sampai menemukan global Object constructor.

adolfo_isassi
sumber
24
tunggu apakah O'Really benar-benar kesalahan ketik atau pelesetan? Mereka harus menggunakannya untuk memasarkan buku mereka!
Tim Ogilvy
3

Saya telah menemukan satu perbedaan, untuk ES6 / ES2015. Anda tidak dapat mengembalikan objek menggunakan sintaks fungsi panah steno, kecuali jika Anda mengelilingi objek tersebut 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 } ]

Hal ini karena compiler bingung oleh {}kurung dan berpikir n: iadalah label: pernyataan konstruksi; titik koma adalah opsional sehingga tidak mengeluh tentang hal itu.

Jika Anda menambahkan properti lain ke objek itu akhirnya akan menimbulkan kesalahan.

$ 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 :
Andrei Simionescu
sumber
4
Anda masih dapat menggunakan fungsi panah, Anda hanya perlu lebih banyak kawat gigi dan pengembalian: [1, 2, 3].map(v => { return {n: v}; });akan memberikan Anda hal yang sama ...
Heretic Monkey
Tentu saja Anda dapat menggunakan fungsi panah biasa, yang saya bicarakan adalah versi singkat, yaitu param => return_value, dan perbedaan antara menggunakan {}dan new Object()dalam hal ini.
Andrei Simionescu
11
Anda masih dapat menggunakan versi steno DAN fungsi panah biasa. Hanya membungkus {n: v} dengan sepasang tanda kurung:[1, 2, 3].map(v => ({n: v}));
Stephen C
1

Pembaruan 2019

Saya menjalankan kode yang sama dengan @rjloura pada simpul OSX High Sierra 10.13.6 saya versi 10.13.0 dan ini adalah hasilnya

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
PirateApp
sumber
-2

Penggunaan memori berbeda jika Anda membuat 10 ribu instance. new Object()hanya akan menyimpan satu salinan saja sementara {}akan menyimpan 10 ribu salinan.

Richard Miao US
sumber
7
newmenciptakan objek baru. Mereka berdua mengambil jumlah memori yang sama.
Artyer