Jaka jest różnica między `new Object ()` a notacją dosłowną obiektu?

199

Jaka jest różnica między tą opartą na konstruktorach składnią tworzenia obiektu:

person = new Object()

... i ta dosłowna składnia:

person = {
    property1 : "Hello"
};

Wygląda na to, że oba robią to samo, chociaż JSLint woli używać notacji dosłownej do obiektów.

Który jest lepszy i dlaczego?

typ
źródło
7
Wszystkie takie same: a = new Object, a = new Object(), a = {}, dosłowny jest znacznie prostsze, a niektóre testy wpadłem przed chwilą powiedzieć, że jest szybciej, nowsze kompilatory mogą powodować moje oświadczenie, że są fałszywe. To samo dotyczy tablic dosłownych
Juan Mendes
8
Mamy nadzieję, że deklarujesz swoje zmienne ze varsłowem kluczowym w kodzie aplikacji, aby uniknąć zanieczyszczenia globalnej przestrzeni nazw i stworzyć potrzebę szukania zmiennych poza bieżącym rekordem w stosie.
Samo
1
Zasadniczo w dowolnym momencie wykonywania programu istnieje stos rekordów lub bloków. Każdy rekord ma listę zmiennych, które zostały utworzone w tym zakresie. W JavaScript, jeśli wyrażenie zawiera zmienną, a interpreter nie może jej znaleźć w rekordzie stosu dla tego zakresu, przejdzie do następnego rekordu, dopóki nie znajdzie zmiennej. Więcej informacji davidshariff.com/blog/…
Samo
2
Unikanie JSLint to pierwszy krok do zostania dobrym programistą. Używanie newjest konwencją, która wykracza poza bezsensowne dręczenie przeciętnego języka. Użyj, newponieważ jego znaczenie jest jasne. W 99,9% przypadków wzrost wydajności nie ma znaczenia.
Hal50000
1
@ Hal50000 mierny język według kogo?
Xam

Odpowiedzi:

124

Obaj robią to samo (chyba że ktoś zrobił coś niezwykłego), poza tym, że twój drugi tworzy obiekt i dodaje do niego właściwość. Ale notacja dosłowna zajmuje mniej miejsca w kodzie źródłowym. To jest wyraźnie rozpoznawalne, co się dzieje, więc korzystanienew Object() , naprawdę piszesz więcej i (teoretycznie, jeśli nie jest zoptymalizowany przez silnik JavaScript), wykonuje niepotrzebne wywołanie funkcji.

Te

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

person = {
    property1 : "Hello"
};

technicznie nie rób tego samego. Pierwszy po prostu tworzy obiekt. Drugi tworzy jeden i przypisuje właściwość. Aby pierwszy był taki sam, potrzebujesz drugiego kroku, aby utworzyć i przypisać właściwość.

„Coś niezwykłego”, co ktoś mógłby zrobić, to ukryć lub przypisać do domyślnego Objectglobalnego:

// Don't do this
Object = 23;

W tym bardzo nietypowym przypadkunew Object zawiedzie, ale{} zadziała.

W praktyce nigdy nie ma powodów, by używać new Objectzamiast {}(chyba, że zrobiłeś coś bardzo niezwykłego).

kemiller2002
źródło
11
Autor wybrał tę odpowiedź jako poprawną, ale jest ona niekompletna. Należy pamiętać, że istnieją różnice między tymi dwiema składniami, jeśli chodzi o przydzielanie pamięci.
newshorts
2
Nie ma różnic. Jeśli odwołujesz się do jednej z odpowiedzi poniżej, jest to nie na temat, ponieważ mówi o prototypowym modelu obiektowym i dziedziczeniu (tam kod konfiguruje klasę Obj, która dziedziczy po zwykłym obiekcie). To pytanie nie dotyczy tworzenia instancji jakiejś klasy niestandardowej - dotyczy tworzenia instancji Object, a poprawna odpowiedź na to pytanie brzmi: „nie ma różnicy”.
dos
FYI również () new Object()nie jest wymagane. (mówiąc o niepotrzebnych rzeczach)
Royi Namir,
Myślę, że nie musimy używać nowego z obecnej specyfikacji. Daj mi znać, co myślisz @kevin
Vamsi Pavan Mahesh
1
Możesz także użyć opcji Utwórz obiekt i przekaż null, jeśli chcesz, aby obiekt nie dziedziczył z łańcucha dziedziczenia. Nie są one równe i mają odpowiednio użyteczne cele.
Aaron
234

Prosty obiekt nie ma różnicy bez metod jak w twoim przykładzie. Jest jednak duża różnica, gdy zaczynasz dodawać metody do swojego obiektu.

Dosłowny sposób:

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

Prototypowy sposób:

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

Oba sposoby pozwalają na tworzenie takich instancji Obj:

var foo = new Obj( "hello" ); 

Jednak dosłownie przenosisz kopię sayHellometody w każdej instancji twoich obiektów. Natomiast w sposób prototypowy metoda jest zdefiniowana w prototypie obiektu i współdzielona między wszystkimi instancjami obiektów. Jeśli masz wiele obiektów lub wiele metod, dosłowny sposób może prowadzić do dość dużych strat pamięci.

Rémy DAVID
źródło
39
Dla mnie pytanie dotyczyło raczej różnic między używaniem new Object()vs {}do tworzenia pustych obiektów.
Peter
11
@Lobabob Poza pierwszym zdaniem ta odpowiedź nie zawiera żadnych informacji na temat pytania OP. Nigdzie nie zawiera nawet „nowego obiektu ()”. Szczerze mówiąc, myślę, że pan David źle zrozumiał pytanie.
JLRishe
17
Kiedy to opublikowałem, zaakceptowana odpowiedź już tam była i została zaakceptowana. I doskonale odpowiada na pytanie OP, więc nie zamierzałem powtarzać tego samego. Odpowiedzi zamieściłem głównie po to, aby poszerzyć temat poza puste / proste obiekty. W takim przypadku nie jest istotna różnica o której warto wspomnieć.
Rémy DAVID
3
Ta odpowiedź jest nie na temat. W twoim kodzie Obj jest osobną klasą dziedziczącą po Object. Kiedy używasz notacji dosłownej do obiektu, używasz klasy Object, a nie Obj. Oczywiście skonfigurowanie klasy z metodą w jej prototypie spowoduje, że pamięć pozostanie mniejsza niż tworzenie wielu zwykłych Obiektów i dodanie metody jako ich właściwości, ale nie ma to żadnego związku z postawionym tutaj pytaniem. Prawidłowa odpowiedź na to pytanie brzmi: „nie, absolutnie nie ma różnicy (może poza czytelnością)”.
dos
3
Przyszedłem po tę odpowiedź, opierając się na pytaniu podobnym do mojego, ale ostatecznie dowiedziałem się dokładnie, co powinienem wiedzieć. Dziękuję Ci.
Pat Migliaccio,
55

W JavaScript możemy zadeklarować nowy pusty obiekt na dwa sposoby:

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

Nie znalazłem niczego, co sugerowałoby, że istnieje jakakolwiek znacząca różnica między tymi dwoma, jeśli chodzi o sposób, w jaki działają za kulisami (proszę mnie poprawić, jeśli się mylę - chciałbym wiedzieć). Jednak druga metoda (wykorzystująca notację dosłowną obiektu) ma kilka zalet.

  1. Jest krótszy (dokładnie 10 znaków)
  2. Łatwiejsze i bardziej uporządkowane jest tworzenie obiektów w locie
  3. Nie ma znaczenia, czy jakiś bufor przypadkowo nadpisał obiekt

Rozważ nowy obiekt, który zawiera elementy Nazwa i numer telefonu. Korzystając z nowej konwencji Object (), możemy stworzyć ją w następujący sposób:

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

Te właściwości EXPANDO cechą JavaScript pozwala nam tworzyć nowych członków w ten sposób na bieżąco, i osiągnąć to, co zostało zamierza. Jednak ten sposób nie jest zbyt ustrukturyzowany ani zamknięty. Co by było, gdybyśmy chcieli określić członków podczas tworzenia, bez konieczności polegania na właściwościach expando i zadaniu po utworzeniu?

W tym przypadku literalna notacja obiektowa może pomóc:

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

Tutaj osiągnęliśmy ten sam efekt w jednym wierszu kodu i znacznie mniej znaków.

Dalszą dyskusję na temat powyższych metod budowy obiektów można znaleźć na stronie: JavaScript i programowanie obiektowe (OOP).

I w końcu, co z idiotą, który przesłonił Object? Myślałeś, że to niemożliwe? Cóż, ten JSFiddle dowodzi, że jest inaczej. Użycie literalnej notacji przedmiotowej zapobiega popełnianiu przez nas tego zboczenia.

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

James Wiseman
źródło
1
Co powiesz na Object.Create? Zobacz: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Phil
Jeśli masz zamiar faworyzować literały obiektowe z new Object()powodu możliwości, że coś nadpisało funkcję Object, powinieneś także pisać strażników w dowolnym miejscu, gdy używasz pomocników, Object.keysaby upewnić się, że nie jest niezdefiniowana, co popada w absurd. Zawsze polecałbym ludziom używanie dosłownego zapisu, ale myślę, że ten konkretny argument rozpada się, gdy myślisz o konsekwencjach takiego myślenia.
philraj
41

Na moim komputerze za pomocą Node.js uruchomiłem następujące:

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

Uwaga: jest to rozszerzenie tego, co można znaleźć tutaj: Dlaczego arr = [] jest szybszy niż arr = new Array?

mój wynik był następujący:

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

więc wyraźnie {} i [] są szybsze niż używanie nowych do tworzenia pustych obiektów / tablic.

rjloura
źródło
3
Wydaje mi się, że to odpowiedź, której tak naprawdę szukało pytanie, choć chciałbym zobaczyć to dodatkowo przetestowane na obiekcie o kilku właściwościach, aby się upewnić.
Chase Sandmann
2
Ciekawe liczby Są ludzie, którzy muszą być tego świadomi, ale zdaję sobie sprawę, że przydzielenie nawet skromnych 200 000 obiektów będzie kosztować mnie tylko 5,6 ms, więc nie będę się tym martwić.
W węźle 10.13.0 ZMIENIONO Tablica testowa: przy użyciu []: 117.178ms przy użyciu nowego: 116,947ms Obiekt testowy: przy użyciu {}: 116,252ms przy użyciu nowego: 115,910ms
PirateApp
31

Wszyscy tutaj mówią o podobieństwach tych dwóch. Wskażę różnice.

  1. Używanie new Object()pozwala mi przekazać kolejny obiekt. Oczywistym rezultatem jest to, że nowo utworzony obiekt zostanie ustawiony na to samo odwołanie. Oto przykładowy kod:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. Użycie nie jest ograniczone do obiektów jak w obiektach OOP. Można do niego również przekazać inne typy. Funkcja odpowiednio ustawi typ. Na przykład, jeśli przekażemy mu liczbę całkowitą 1, zostanie dla nas utworzony obiekt typu numer.

    var obj = new Object(1);
    typeof obj // "number"
  3. Obiekt utworzony za pomocą powyższej metody ( new Object(1)) zostanie przekonwertowany na typ obiektu, jeśli zostanie do niego dodana właściwość.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. Jeśli obiekt jest kopią podrzędnej klasy obiektu, możemy dodać właściwość bez konwersji typu.

    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
źródło
3
jestem bardzo zdezorientowany co do dwóch ostatnich wierszy .. Dlaczego, jeśli przypiszesz do str. a wartość 1, str. a jest niezdefiniowany? .. @Jermin Bazazin
Andrea Scarafoni
3
@AndreaScarafoni, ponieważ strjest typu, stringwięc nie można przypisać do niego właściwości. jsfiddle.net/grq6hdx7/1
Chris Bier
1
Czy zmieniła się odpowiedź na 4? Robię się fałszywy, nieprawda, w najnowszym Chrome 53 var obj = new Object("foo"); typeof obj; obj === "foo" // true
William Hilton
21

W rzeczywistości istnieje kilka sposobów tworzenia obiektów w JavaScript. Gdy chcesz po prostu utworzyć obiekt, tworzenie obiektów „ opartych na konstruktorze ” nie jest korzystne przy użyciu operatora „ nowy ”. To samo, co tworzenie obiektu przy użyciu składni „ dosłowny obiekt ”. Ale obiekty „ oparte na konstruktorach ” utworzone za pomocą „ nowego ” operatora stają się niezwykle przydatne, gdy myślisz o „ dziedziczeniu prototypowym ”. Nie można utrzymać łańcucha dziedziczenia z obiektami utworzonymi w dosłownej składni. Ale możesz utworzyć funkcję konstruktora , dołączyć właściwości i metody do jej prototypu."zwróci obiekt, który będzie miał dostęp do wszystkich metod i właściwości dołączonych do prototypu tej funkcji konstruktora.

Oto przykład tworzenia obiektu za pomocą funkcji konstruktora (patrz objaśnienie kodu na dole):

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

Teraz możesz utworzyć dowolną liczbę obiektów, tworząc instancję funkcji budowy Osoby, a wszystkie z nich odziedziczą po niej fullname ().

Uwaga: słowo kluczowe „ this ” będzie odnosić się do pustego obiektu w funkcji konstruktora i za każdym razem, gdy utworzysz nowy obiekt z Person za pomocą operatora „ new ”, automatycznie zwróci obiekt zawierający wszystkie właściwości i metody powiązane ze słowem kluczowym „ this ” . Obiekt ten z pewnością odziedziczy metody i właściwości związane z prototypem funkcji konstruktora Person (co jest główną zaletą tego podejścia).

Nawiasem mówiąc, jeśli chcesz uzyskać tę samą funkcjonalność ze składnią „ dosłowny obiekt ”, musisz utworzyć pełną nazwę () na wszystkich obiektach, takich jak poniżej:

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

Na koniec, jeśli teraz zapytacie, dlaczego powinienem używać podejścia funkcji konstruktora zamiast dosłowności obiektowej :

*** Dziedziczenie prototypowe umożliwia prosty łańcuch dziedziczenia, który może być niezwykle użyteczny i potężny.

*** Oszczędza pamięć, dziedzicząc typowe metody i właściwości zdefiniowane w prototypie funkcji konstruktora. W przeciwnym razie będziesz musiał kopiować je w kółko we wszystkich obiektach.

Mam nadzieję, że to ma sens.

Md. Zubaer Ahammed
źródło
Dzięki! Karla za dodanie brakującego „tego” do literału obiektu. To był okropny błąd. Nie powinienem był popełniać tego rodzaju błędu.
Md. Zubaer Ahammed
„Nie można dziedziczyć po obiekcie utworzonym w dosłownej składni”. - Nieprawda (wierzę). W razie potrzeby możesz używać Object.create(<object defined using literal notation>)lub new Object(<object defined using literal notation>)tworzyć łańcuchy spadkowe.
balajeerc
@balajeerc Dzięki za komentarz. Właściwie powinno to brzmieć: „Nie można utrzymać łańcucha dziedziczenia z obiektami utworzonymi w dosłownej składni”. Odpowiedź jest w wielu krokach: 1. Object.create (): Tak, możliwe jest przekazanie literału obiektu i zwróci nowy obiekt, którego prototyp przekaże literał obiektu. Ale nie wie, co to jest funkcja konstruktora, ani nie pamięta tego dosłownego obiektu, z którego został stworzony. Zatem testobj1.constructor zwróci pustą funkcję i nie będzie możliwości dodania właściwości / metod do literału obiektu, ponieważ jest to rodzic / przodek.
Md. Zubaer Ahammed
@balajeerc 2. new Object (): W tym przypadku dzieje się prawie to samo. Co gorsza, jeśli myślisz o pamięci. Zamiast umieszczać właściwości i metody w swoim prototypie, po prostu kopiuje wszystko z literału przekazanego obiektu i umieszcza go w zwróconym obiekcie. To nie jest dobre dla pamięci. Z drugiej strony skupiłem się na łańcuchu prawdziwego dziedziczenia za pomocą funkcji konstruktora, w której możesz edytować metody i właściwości w locie, a także wpływać na inne obiekty utworzone za pomocą metody konstruktora, ponieważ wskazują one tylko na tę funkcję konstruktora (zamiast je kopiować) .
Md. Zubaer Ahammed
@balajeerc Przykład: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

Ponadto, według niektórych książek O'Really javascript .... (cytowany)

Innym powodem używania literałów w przeciwieństwie do konstruktora obiektów jest brak rozdzielczości zakresu. Ponieważ możliwe jest, że utworzono lokalnego konstruktora o tej samej nazwie, interpreter musi wyszukać łańcuch zasięgu od miejsca, w którym wywołujesz Object (), aż do znalezienia globalnego konstruktora Object.

adolfo_isassi
źródło
24
czekać, czy O'Really jest literówką czy celowym kalamburem? Powinny ich używać do marketingu swoich książek!
Tim Ogilvy
3

Znalazłem jedną różnicę dla ES6 / ES2015. Nie można zwrócić obiektu za pomocą składni funkcji skrótu, chyba że obiekt zostanie otoczony 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 } ]

Wynika to z tego, że kompilator jest pomieszany w {}nawiasach i myśli, że n: ijest etykietą: instrukcja konstrukcja; średnik jest opcjonalny, więc nie narzeka.

Jeśli dodasz inną właściwość do obiektu, w końcu wygeneruje błąd.

$ 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
źródło
4
Nadal możesz używać funkcji strzałki, potrzebujesz tylko nawiasów klamrowych, a powrót: [1, 2, 3].map(v => { return {n: v}; });przyniesie ci to samo ...
Heretic Monkey
Oczywiście możesz używać zwykłych funkcji strzałek, o czym mówiłem była wersja skrócona, tj. param => return_valueI różnica między używaniem {}a new Object()w tym przypadku.
Andrei Simionescu,
11
Nadal możesz używać wersji skróconej ORAZ zwykłych funkcji strzałek. Wystarczy owinąć {n: v} parą nawiasów:[1, 2, 3].map(v => ({n: v}));
Stephen C
1

Aktualizacja 2019

Uruchomiłem ten sam kod co @rjloura na moim węźle OSX High Sierra 10.13.6 w wersji 10.13.0 i to są wyniki

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
źródło
-2

Zużycie pamięci jest inne, jeśli utworzysz 10 tysięcy instancji. new Object()zachowa tylko jedną kopię, a {}zachowa 10 000 kopii.

Richard Miao US
źródło
7
newtworzy nowy obiekt. Obie zajmują taką samą ilość pamięci.
Artyer