Pro e contro dei diversi modi per creare oggetti in Javascript [chiuso]

2

Contesto

Sto scrivendo una libreria di JavaScript e sto scoprendo che non so quale sia il modo migliore per supportare la creazione di oggetti . Ho trovato una lista di cose che sto considerando:

var obj = Library.newObj('object-type');
var obj = Library.newObj(Library.ObjectType); // Library.ObjectType is an object containing information about how to create the new object
var obj = Library.newObj(Library.ObjectType); // Library.ObjectType is an integer specifying the type
var obj = new Library('object-type');
var obj = new Library(Library.ObjectType); // Library.ObjectType is an object containing information about how to create the new object
var obj = new Library(Library.ObjectType); // Library.ObjectType is an integer specifying the type
var obj = new Library.ObjectType();

In particolare, questi oggetti dovrebbero anche avere opzioni specificabili. Sembrerebbe quindi

var obj = Library.newObj('object-type', { /* options */ });
var obj = Library.newObj(Library.ObjectType({ /* options */ }));
var obj = Library.newObj(Library.ObjectType, { /* options */ });
var obj = new Library('object-type', { /* options */ });
var obj = new Library(Library.ObjectType({ /* options */ }));
var obj = new Library(Library.ObjectType, { /* options */ });
var obj = new Library.ObjectType({ /* options */ });

// Or, when the user wants to change options separately:
obj.setOptions({ /* options */ });
obj.setOption1(val1).setOption2(val2);

Penso che potrei non voler specificare il tipo di oggetto semplicemente con una stringa o un intero perché potrebbe essere difficile da mantenere e non è molto estensibile .

Domanda

Quali sono i pro e contro di queste varianti? Esiste una best-practice / convention di cui non sono a conoscenza? Dovrei supportare più modi per creare oggetti? (O ci sono altre varianti che non ho considerato?)

Il mio caso specifico

(I particolari della mia situazione sono che voglio consentire agli sviluppatori che usano la libreria di fornire i propri 'modelli di creazione dell'oggetto' che funzionano con la libreria, ma la libreria fornirà anche alcuni 'modelli' predefiniti (come Library.ObjectType ). Inoltre, non voglio esporre più di una cosa (come Library sopra) allo spazio dei nomi globale quando viene usata nel browser, ma vorrei comunque evitare il dot-horror, ad esempio:

Library.objects.objectCreator.createObject(Library.objects.objectTypes.ObjectType1);
    
posta hugabor 09.08.2017 - 01:04
fonte

1 risposta

6

Probabilmente non utilizzare new

Probabilmente non vuoi usare l'operatore new molto spesso in JS a meno che la funzione che stai invocando direttamente sia il costruttore. Chiamando new X(…) esegue questa operazione:

  1. Viene creato un nuovo oggetto.
  2. Questo oggetto eredita da X.prototype .
  3. La funzione di costruzione X(…) viene eseguita con this associato al nuovo oggetto.
  4. Se il costruttore non restituisce nulla, viene invece restituito il nuovo oggetto.

L'operatore new è quindi inadatto o almeno fuorviante quando si chiama una funzione generica di fabbrica anziché un costruttore concreto.

Digitare tag (interi, stringhe o oggetti)

Usando un qualche tipo di tag type, stai creando un sistema molto dinamico. Ciò significa che il sistema è più difficile da ragionare per gli esseri umani e anche più difficile da elaborare per strumenti come linters, type checker e completamento automatico basato su tipo negli IDE. Questi strumenti hanno un valore, quindi renderli meno utili non dovrebbe essere fatto alla leggera.

Alcuni problemi richiedono questa flessibilità. Ma nella maggior parte dei casi, tutto ciò che stai facendo è aggiungere il tuo meccanismo (inutile) per la creazione di oggetti o per le chiamate di metodi oltre al linguaggio corrente.

Una buona ragione per questo è se vuoi un incapsulamento molto chiaro. JavaScript non ha alcun concetto di accessibilità pubblica / privata e le proprietà dell'oggetto possono essere modificate in qualsiasi momento. L'unico modo per nascondere davvero qualcosa è usare le chiusure. Questo tipo di paranoia non è generalmente necessario.

L'utilizzo di stringhe letterali come tag di tipo è abbastanza leggibile, ma è molto suscettibile agli errori di battitura.

L'utilizzo di ID interi come tag di tipo dovrebbe essere evitato perché non sono molto debugabili. Sono effettivamente non tipizzati: se vedi un numero intero da qualche parte non puoi essere sicuro che fosse inteso come tag di tipo, o è solo un numero normale. E potresti avere difficoltà a ricondurre l'ID al tipo.

L'uso di "costanti" per i tag di tipo come Library.newObj(Library.ObjectType, ...) all'inizio sembra ragionevole, ma è molto inutile: se puoi esporre un campo ObjectType , potrebbe essere un costruttore o uno stabilimento: Library.ObjectType(…) o new Library.ObjectType(…) o Library.ObjectType.create(…) .

Dot-Horror? Ti preghiamo di progettare la tua API pubblica

Lamentarsi di dot-horror (o violazione di Law of Demeter) è un po 'un uomo di paglia qui. Hai mostrato questo potenziale esempio:

Library.objects.objectCreator.createObject(Library.objects.objectTypes.ObjectType1);

Questo è sciocco perché gli utenti sono liberi di creare alias parti della tua libreria con un nome che preferiscono:

var LibObjects = Library.objects;
var createLibObject = LibObjects.objectCreator.createObject;
var LibTypes = LibObjects.objectTypes;

...

createLibObject(LibTypes.ObjectType1);

Inoltre, è possibile progettare la libreria per evitare tali problemi. Il simbolo Library esportato non deve essere la "radice" della libreria da cui tutte le classi sono raggiungibili. Invece, è una facciata per la funzionalità della libreria. Gli oggetti ausiliari non hanno posto qui. La struttura pubblicamente visibile della libreria non deve necessariamente corrispondere alla struttura interna. A volte è opportuno dividere i tuoi simboli pubblici in più sotto-oggetti per il namespace, ma non al punto in cui c'è più struttura che sostanza.

Nell'esempio precedente, la funzione createObject avrebbe potuto essere sollevata al livello superiore dello spazio dei nomi della libreria e objectTypes in un sottospazio:

var Library = {
  createObject: function(x) {  // TODO arguments forwarding
    return objects.objectCreator.createObject(x);
  },
  types: objects.objectTypes,
  ...
};

Quindi:

Library.createObject(Library.types.ObjectType1)

che è abbastanza ragionevole. Durante l'assemblaggio della facciata puoi anche eseguire altre trasformazioni, ad esempio aggiungendo una funzione Library.newObjectType() per ogni tag di tipo ObjectType registrato. Anche se utilizzi questi tag tipo internamente, non devono far parte della tua API pubblica.

    
risposta data 09.08.2017 - 11:53
fonte

Leggi altre domande sui tag