Dovrei usare letterali oggetto o funzioni di costruzione?


94

Mi sto confondendo su come dovrei creare un oggetto in javascript. Sembra che ci siano almeno due modi. Uno consiste nell'usare la notazione letterale dell'oggetto mentre l'altro utilizza le funzioni di costruzione. C'è un vantaggio dell'uno sull'altro?


1
La risposta migliore: stackoverflow.com/questions/4597926/… - In sintesi, puoi impostare una funzione per creare istanze anche dalla notazione letterale. In questo modo ogni istanza trasporta tutti i metodi, mentre con un costruttore tutte le istanze si riferiscono ai metodi del prototipo. Cioè il costruttore ha prestazioni di memoria migliori.
Federico

Se la memoria non è un problema, l'accesso alle proprietà dei valori letterali degli oggetti è molto più veloce - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Risposte:


131

Se non hai un comportamento associato a un oggetto (cioè se l'oggetto è solo un contenitore per dati / stato), userei un oggetto letterale.

var data = {
    foo: 42,
    bar: 43
};

Applica il principio KISS . Se non hai bisogno di nient'altro che un semplice contenitore di dati, vai con un semplice letterale.

Se vuoi aggiungere un comportamento al tuo oggetto, puoi andare con un costruttore e aggiungere metodi all'oggetto durante la costruzione o dare alla tua classe un prototipo.

function MyData(foo, bar) {
    this.foo = foo;
    this.bar = bar;

    this.verify = function () {
        return this.foo === this.bar;
    };
}

// or:
MyData.prototype.verify = function () {
    return this.foo === this.bar;
};

Una classe come questa agisce anche come uno schema per il tuo oggetto dati: ora hai una sorta di contratto (tramite il costruttore) sulle proprietà che l'oggetto inizializza / contiene. Un letterale libero è solo un ammasso di dati amorfo.

Potresti anche avere una verifyfunzione esterna che agisce su un semplice vecchio oggetto dati:

var data = {
    foo: 42,
    bar: 43
};

function verify(data) {
    return data.foo === data.bar;
}

Tuttavia, questo non è favorevole per quanto riguarda l'incapsulamento: idealmente, tutti i dati + il comportamento associati a un'entità dovrebbero convivere.


12
Ottima spiegazione, ma per quanto riguarda l'inserimento di funzioni in un oggetto letterale? L'ho visto fare prima. In realtà il post qui sotto ha un esempio di questo.
chobo

23
Se includi le definizioni di funzione come parte del valore letterale dell'oggetto o utilizzi l' this.fn = function ...approccio in un costruttore, ciascuna delle istanze dell'oggetto avrà le proprie copie delle funzioni. Utilizzando l'approccio del prototipo, colleghi ogni funzione una sola volta: saranno ereditate dalle istanze attraverso l'ereditarietà prototipale.
Ates Goral

14
Credo che ti sia perso una cosa importante. solo la funzione di costruzione può fornire membri privati ​​e membri pubblici (incapsulamento). nell'oggetto letterale - sono tutti pubblici.
Royi Namir

Quale sarebbe un modo migliore per ottenere un motore di gioco? Ho usato il metodo del costruttore ma i miei prototipi non hanno accesso ai dati del costruttore.
zachdyer

90

Essenzialmente si riduce a se hai bisogno di più istanze del tuo oggetto o meno; oggetto definito con un costruttore consente di avere più istanze di quell'oggetto. I letterali oggetto sono fondamentalmente singoli con variabili / metodi che sono tutti pubblici.

// define the objects:
var objLit = {
  x: 0,
  y: 0,
  z: 0,
  add: function () {
    return this.x + this.y + this.z;
  }
};

var ObjCon = function(_x, _y, _z) {
  var x = _x; // private
  var y = _y; // private
  this.z = _z; // public
  this.add = function () {
    return x + y + this.z; // note x, y doesn't need this.
  };
};

// use the objects:
objLit.x = 3; 
objLit.y = 2; 
objLit.z = 1; 
console.log(objLit.add());    

var objConIntance = new ObjCon(5,4,3); // instantiate an objCon
console.log(objConIntance.add());
console.log((new ObjCon(7,8,9)).add()); // another instance of objCon
console.log(objConIntance.add()); // same result, not affected by previous line

1
Questo è un ottimo punto da tenere a mente quando si decide. Grazie.
zkent

Nella mia esperienza questo è esattamente ciò che fa la differenza. Ottimo esempio chiaro.
Air

9

Un altro modo per creare oggetti in modo uniforme è usare una funzione che restituisce un oggetto:

function makeObject() {
    var that = {
        thisIsPublic: "a public variable"
        thisIsAlsoPublic: function () {
            alert(that.thisIsPublic);
        }
    };

    var secret = "this is a private variable"

    function secretFunction() { // private method
        secret += "!"; // can manipulate private variables
        that.thisIsPublic = "foo";     
    }

    that.publicMethod = function () {
        secret += "?"; // this method can also mess with private variables
    }

    that.anotherPublicVariable = "baz";

    return that; // this is the object we've constructed
}

makeObject.static = "This can be used to add a static varaible/method";

var bar = makeObject();
bar.publicMethod(); // ok
alert(bar.thisIsPublic); // ok
bar.secretFunction(); // error!
bar.secret // error!

Poiché le funzioni in JavaScript sono chiusure, possiamo usare variabili e metodi privati ​​ed evitare new.

Da http://javascript.crockford.com/private.html sulle variabili private in JavaScript.


7

Il codice seguente mostra tre metodi per creare un oggetto, la sintassi Object Literal, un costruttore di funzioni e Object.create(). La sintassi letterale dell'oggetto crea semplicemente un oggetto al volo e come tale __prototype__è l' Objectoggetto e avrà accesso a tutte le proprietà e metodi di Object. Strettamente dal punto di vista del modello di progettazione, è necessario utilizzare un semplice valore letterale Object per archiviare una singola istanza di dati.

Il costruttore di funzioni ha una proprietà speciale denominata .prototype. Questa proprietà diventerà l'elemento __prototype__di tutti gli oggetti creati dal costruttore della funzione. Tutte le proprietà e i metodi aggiunti alla .prototypeproprietà di un costruttore di funzioni saranno disponibili per tutti gli oggetti che crea. È necessario utilizzare un costruttore se sono necessarie più istanze dei dati o se si richiede un comportamento dall'oggetto. Si noti che il costruttore di funzioni è anche meglio utilizzato quando si desidera simulare un modello di sviluppo privato / pubblico. Ricordarsi di mettere tutti i metodi condivisi su in .prototypemodo che non vengano creati in ogni istanza di oggetto.

La creazione di oggetti con Object.create()utilizza un oggetto letterale come __prototype__per gli oggetti creati con questo metodo. Tutte le proprietà e i metodi aggiunti all'oggetto letterale saranno disponibili per tutti gli oggetti creati da esso tramite una vera eredità prototipale. Questo è il mio metodo preferito.

//Object Example

//Simple Object Literal
var mySimpleObj = {
    prop1 : "value",
    prop2 : "value"
}

// Function Constructor
function PersonObjConstr()  {
    var privateProp = "this is private";
    this.firstname = "John";
    this.lastname = "Doe";
}
PersonObjConstr.prototype.greetFullName = function()    {
    return "PersonObjConstr says: Hello " + this.firstname + 
    " " + this.lastname;
};

// Object Literal
var personObjLit = {
    firstname : "John",
    lastname: "Doe",
    greetFullName : function() {
        return "personObjLit says: Hello " + this.firstname +
        ", " + this.lastname;
    }
} 

var newVar = mySimpleObj.prop1;
var newName = new PersonObjConstr();
var newName2 = Object.create(personObjLit);

1
Poiché hai dichiarato la funzione all'interno di un oggetto letterale. Ciò significa che quando crei un oggetto utilizzando Object.createla funzione all'interno del letterale sarà univoco per istanza?
JohnnyQ

6

Dipende da quello che vuoi fare. Se si desidera utilizzare variabili o funzioni (semi) private nel proprio oggetto, una funzione di costruzione è il modo per farlo. Se il tuo oggetto contiene solo proprietà e metodi, un oggetto letterale va bene.

function SomeConstructor(){
    var x = 5;
    this.multiply5 = function(i){
        return x*i;
    }
}
var myObj = new SomeConstructor;

var SomeLiteral = {
    multiply5: function(i){ return i*5; }
}

Ora il metodo multiply5in myObje SomeLiteralfare esattamente la stessa cosa. L'unica differenza è che myObj utilizza una variabile privata. Quest'ultimo può essere utile in alcuni casi. La maggior parte delle volte un valore letterale Object è sufficiente ed è un modo carino e pulito per creare un oggetto JS.


Qual è la differenza tra una funzione e un metodo? Vengo da ac # background quindi per me una funzione è autonoma e un metodo è solo una funzione che fa parte di una classe.
chobo

1
Non c'è molta differenza, vedi ad esempio web-source.net/javascript_tutorial/… . In realtà, in DOMscripting (js lato client in un browser), tutte le funzioni diventano metodi dell'oggetto finestra (lo spazio dei nomi globale) direi (puoi indirizzare tutte le funzioni 'autonome' come finestra. [Qualche funzione].
KooiInc

5

inserisci qui la descrizione dell'immagine

Vuoi una singola istanza dell'oggetto per la pagina - Letterale.

Vuoi solo trasferire dati come oggetti DTO semplici GET SET: - Letterale

Vuoi creare oggetti reali con comportamenti di metodo, istanze multiple - Funzione Costruttore, Segui principi OOP, ereditarietà: - Funzioni Costruttore.

Di seguito è riportato il video di YouTube che spiega in dettaglio cosa è letterale, cosa sono le funzioni del costruttore e come differiscono tra loro.

https://www.youtube.com/watch?v=dVoAq2D3n44


1

Vai con l'oggetto letterale, è più coerente e si espande meglio con l'introduzione dei valori iniziali.


Come si creano variabili private in un oggetto letterale?
EhevuTov

Non puoi davvero, non è pertinente alla domanda originale, quindi ti darò un link: javascript.crockford.com/private.html
Tom

1
In realtà, è rilevante perché dove c'è una differenza c'è un motivo per usare l'uno o l'altro a seconda di determinate situazioni; in questo caso sarebbe se vuoi o meno variabili private. Puoi creare variabili private in un letterale creando prima una funzione di chiusura nel tuo letterale, ma è molto più brutto secondo me e difficile da leggere.
EhevuTov

Sono corretto, la mia lettura originale della domanda era che chobo chiedeva come passare le variabili a un costruttore come nell'elenco dei parametri rispetto al parametro letterale del singolo oggetto.
Tom



0

In realtà, penso, possiamo avere metodi privati ​​in letterali oggetto. Considera il codice seguente:

var myObject = {

   publicMethod: function () {
      privateMethod1();
      privateMethod2(); 
      function privateMethod1(){
          console.log('i am privateMethod1');
      } 
      function privateMethod2(){
          console.log('i am privateMethod2');
      } 
   }

}

Questione di gusti, ma preferisco usare oggetti letterali dove è possibile.


-1

// Object Literal e Object costruttore

function MyData(foo, bar) {
        this.foo = foo;
        this.bar = bar;

    }
MyData.prototype.verify = function () {
        return this.foo === this.bar;
    };

//add property using prototype

var MD  = new MyData;//true.
var MD = new MyData();//true.
MD.verify// return only the function structure.
MD.verify(); //return the verify value and in this case return true coz both value is null. 
var MD1  = new MyData(1,2); // intialized the value at the starting. 
MD1.verify// return only the function structure.
MD1.verify(); // return false coz both value are not same.
MD1.verify(3,3);// return false coz this will not check this value intialized at the top 
MyData.prototype.verify = function (foo,bar) {
    return this.foo === this.bar;
};
var MD1  = new MyData(1,2);
MD1.verify();
MD1.verify(3,3);// return false coz this keyword used with foo and bar that will check parent data 

1
Dove nel tuo esempio viene dichiarato il valore letterale Object?
JohnnyQ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.