OLOO Pattern di Kyle Simpson vs Prototype Design Pattern


109

Il pattern "OLOO (Objects Linking to Other Objects)" di Kyle Simpson differisce in qualche modo dal modello di progettazione del prototipo? Oltre a coniarlo con qualcosa che indica specificamente "collegamento" (il comportamento dei prototipi) e chiarire che non c'è "copia" che accade qui (un comportamento di classi), cosa introduce esattamente il suo modello?

Ecco un esempio del modello di Kyle dal suo libro, "You Don't Know JS: this & Object Prototypes":

var Foo = {
    init: function(who) {
        this.me = who;
    },
    identify: function() {
        return "I am " + this.me;
    }
};

var Bar = Object.create(Foo);

Bar.speak = function() {
    alert("Hello, " + this.identify() + ".");
};

var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");

b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."

2
Puoi almeno collegarti a una descrizione del modello di cui stai chiedendo. Ancora meglio sarebbe mostrarne un esempio in codice nella tua domanda.
jfriend00

4
Getify è su Stackoverflow a volte. Gli ho twittato questa domanda :)
punta

Risposte:


155

cosa introduce esattamente il suo modello?

OLOO abbraccia la catena dei prototipi così com'è, senza bisogno di sovrapporre altre semantiche (confuse da IMO) per ottenere il collegamento.

Quindi, questi due frammenti hanno lo stesso risultato ESATTO, ma ci arrivano in modo diverso.

Modulo Costruttore:

function Foo() {}
Foo.prototype.y = 11;

function Bar() {}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.z = 31;

var x = new Bar();
x.y + x.z;  // 42

Modulo OLOO:

var FooObj = { y: 11 };

var BarObj = Object.create(FooObj);
BarObj.z = 31;

var x = Object.create(BarObj);
x.y + x.z;  // 42

In entrambi gli snippet, un xoggetto è [[Prototype]]collegato a un oggetto ( Bar.prototypeo BarObj), che a sua volta è collegato al terzo oggetto ( Foo.prototypeoFooObj ).

Le relazioni e la delega sono identiche tra gli snippet. L'utilizzo della memoria è identico tra gli snippet. La capacità di creare molti "figli" (ovvero molti oggetti come x1through x1000, ecc.) È identica tra gli snippet. Le prestazioni della delega ( x.ye x.z) sono identiche tra gli snippet. Le prestazioni di creazione degli oggetti sono più lente con OLOO, ma la sanità lo controlla rivela che le prestazioni più lente non sono davvero un problema.

Quello che sostengo offre OLOO è che è molto più semplice esprimere semplicemente gli oggetti e collegarli direttamente, piuttosto che collegarli indirettamente attraverso il costruttore / newmeccanismi. Quest'ultimo finge di essere sulle classi ma in realtà è solo una terribile sintassi per esprimere la delega ( nota a margine : così è la classsintassi ES6 !).

OLOO sta solo eliminando l'intermediario.

Ecco un altro confronto tra classvs OLOO.


2
Ho trovato davvero interessante la tua risposta e l'idea di OLOO descritta nei tuoi libri, vorrei avere il tuo feedback su questa domanda: stackoverflow.com/questions/40395762/… Specialmente se hai trovato corretta questa implementazione e come risolvere il problema relativo all'accesso membro privato. Grazie per il tuo tempo in anticipo e congratulazioni per il tuo ultimo libro.
GibboK

Ma Object.create(...)è molte volte più lento di new. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/…
Pier

3
@ Pier la performance non è in realtà un gran problema. risolto il collegamento interrotto del post sul blog relativo al controllo della sanità mentale delle prestazioni della creazione di oggetti, che spiega come pensarci correttamente.
Kyle Simpson,

2
E jQuery è più lento dell'API DOM, giusto? Ma è l'anno in corso, amico - preferisco scrivere in modo elegante e semplice che preoccuparmi di ottimizzare. Se in seguito avrò bisogno di micro-ottimizzare, me ne preoccuperò quando sarà il momento.
Eirik Birkeland

6
Vorrei aggiungere che ora, poco più di un anno dopo, Object.create () è fortemente ottimizzato in chrome e che jsperf lo mostra: è una delle opzioni più veloci ora. Questo mostra esattamente perché non dovresti preoccuparti di tali micro-ottimizzazioni, e invece scrivere semplicemente codice algoritmicamente valido.
Kyle Baker

25

Ho letto il libro di Kyle e l'ho trovato davvero istruttivo, in particolare i dettagli su come this è rilegato.

Professionisti:

Per me, ci sono un paio di grandi vantaggi di OLOO:

1. Semplicità

OLOO si basa sulla Object.create()creazione di un nuovo oggetto che è [[prototype]]collegato a un altro oggetto. Non devi capire che le funzioni hanno un'estensioneprototype proprietà o preoccuparti di nessuno dei potenziali insidie ​​correlate che derivano dalla sua modifica.

2. Sintassi più pulita

Questo è discutibile, ma penso che la sintassi OLOO sia (in molti casi) più ordinata e concisa dell'approccio javascript "standard", in particolare quando si tratta di polimorfismo ( superchiamate -style).

Contro:

Penso che ci sia un aspetto discutibile del design (uno che in realtà contribuisce al punto 2 sopra), e che ha a che fare con l'ombreggiatura:

Nella delega del comportamento, evitiamo, se possibile, di denominare le cose allo stesso modo a diversi livelli della [[Prototype]]catena.

L'idea alla base di questo è che gli oggetti hanno le loro funzioni più specifiche che poi delegano internamente a funzioni più in basso nella catena. Ad esempio, potresti avere un resourceoggetto con una save()funzione su di esso che invia una versione JSON dell'oggetto al server, ma potresti anche avere un clientResourceoggetto che ha unastripAndSave() funzione, che prima rimuove le proprietà che non dovrebbero essere inviate al server .

Il potenziale problema è: se qualcun altro arriva e decide di creare un specialResourceoggetto, non pienamente consapevole dell'intera catena del prototipo, potrebbe ragionevolmente * decidere di salvare un timestamp per l'ultimo salvataggio sotto una proprietà chiamata save, che oscura la save()funzionalità di base su l' resourceoggetto a due anelli lungo la catena del prototipo:

var resource = {
  save: function () { 
    console.log('Saving');
  }
};

var clientResource = Object.create(resource);

clientResource.stripAndSave = function () {
  // Do something else, then delegate
  console.log('Stripping unwanted properties');
  this.save();
};

var specialResource = Object.create( clientResource );

specialResource.timeStampedSave = function () {
  // Set the timestamp of the last save
  this.save = Date.now();
  this.stripAndSave();
};

a = Object.create(clientResource);
b = Object.create(specialResource);

a.stripAndSave();    // "Stripping unwanted properties" & "Saving".
b.timeStampedSave(); // Error!

Questo è un esempio particolarmente artificioso, ma il punto è che specificamente no ombra altre proprietà può portare ad alcune situazioni imbarazzanti e all'uso pesante di un thesaurus!

Forse un'illustrazione migliore di questo sarebbe un initmetodo, particolarmente toccante poiché OOLO elude le funzioni di tipo costruttore. Poiché ogni oggetto correlato avrà probabilmente bisogno di tale funzione, potrebbe essere un esercizio noioso nominarli in modo appropriato e l'unicità potrebbe rendere difficile ricordare quale utilizzare.

* In realtà non è particolarmente ragionevole ( lastSavedsarebbe molto meglio, ma è solo un esempio).


23
Sono d'accordo sul fatto che il potenziale di collisioni di nomi sia uno svantaggio ... ma in realtà è uno svantaggio del [[Prototype]]sistema stesso, non di OLOO nello specifico.
Kyle Simpson

Forse avrebbe dovuto essere menzionato anche nel libro?
affitta il

Non sono davvero sicuro che questa sia davvero una soluzione al problema descritto da @Ed Hinchliffe poiché sposta semplicemente save () nel proprio spazio dei nomi ma funziona codepen.io/tforward/pen/govEPr?editors=1010
Tristan Forward

Penso che @ ed-hinchliffe intendesse b.timeStampedSave();invece che a.timeStampedSave();sull'ultima riga dello snippet di codice.
amangpt777

1
@ tristan-forward grazie per aver coinvolto Rick e Morty in questo!
Eric Bishard

13

La discussione in "You Don't Know JS: this & Object Prototypes" e la presentazione dell'OLOO sono stimolanti e ho imparato un sacco di cose leggendo il libro. I meriti del pattern OLOO sono ben descritti nelle altre risposte; tuttavia, ho i seguenti reclami per animali domestici con esso (o mi manca qualcosa che mi impedisce di applicarlo in modo efficace):

1

Quando una "classe" "eredita" un'altra "classe" nel modello classico, le due funzioni possono essere dichiarate con sintassi simile ( "dichiarazione di funzione" o "istruzione di funzione" ):

function Point(x,y) {
    this.x = x;
    this.y = y;
};

function Point3D(x,y,z) {
    Point.call(this, x,y);
    this.z = z;
};

Point3D.prototype = Object.create(Point.prototype);

Al contrario, nel pattern OLOO, diverse forme sintattiche utilizzate per definire la base e gli oggetti derivati:

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    }
};


var Point3D = Object.create(Point);
Point3D.init = function(x,y,z) {
    Point.init.call(this, x, y);
    this.z = z;
};

Come puoi vedere nell'esempio sopra, l'oggetto di base può essere definito utilizzando la notazione letterale dell'oggetto, mentre la stessa notazione non può essere utilizzata per l'oggetto derivato. Questa asimmetria mi infastidisce.

2

Nel pattern OLOO, la creazione di un oggetto è composta da due passaggi:

  1. chiamata Object.create
  2. chiama un metodo personalizzato, non standard per inizializzare l'oggetto (che devi ricordare poiché può variare da un oggetto all'altro):

     var p2a = Object.create(Point);
    
     p2a.init(1,1);

Al contrario, nel modello Prototype si utilizza l'operatore standard new:

var p2a = new Point(1,1);

3

Nel modello classico posso creare funzioni di utilità "statiche" che non si applicano direttamente a un "istante" assegnandole direttamente alla funzione "classe" (al contrario della sua .prototype). Ad esempio, come la funzione squarenel codice seguente:

Point.square = function(x) {return x*x;};

Point.prototype.length = function() {
    return Math.sqrt(Point.square(this.x)+Point.square(this.y));
};

Al contrario, nel pattern OLOO tutte le funzioni "statiche" sono disponibili (tramite la catena [[prototype]]) anche sulle istanze dell'oggetto:

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    },
    square: function(x) {return x*x;},
    length: function() {return Math.sqrt(Point.square(this.x)+Point.square(this.y));}
};

2
Non ci sono letterali nel tuo primo esempio di codice. Probabilmente stai abusando del termine "letterale" dandogli un altro significato.
Sto

2
Per quanto riguarda il secondo punto, l'autore sostiene che è una "migliore" separazione di interesse avere la creazione e l'inizializzazione separate e cita che potrebbero esserci alcuni rari casi d'uso in cui questo potrebbe brillare (esempio un pool di oggetti). Trovo l'argomento terribilmente debole.
affitta il

2
Sempre per quanto riguarda il 2 ° punto, con OLOO, puoi creare i tuoi oggetti in una volta, e attendere l'inizializzazione, mentre con il costruttore, devi inizializzare alla creazione, quindi Kyle considera questo un vantaggio.
taco

5

"Ho pensato che questo rendesse ogni oggetto dipendente dall'altro"

Come spiega Kyle, quando due oggetti sono [[Prototype]]collegati, non sono realmente dipendenti l'uno dall'altro; invece sono oggetti individuali. Stai collegando un oggetto all'altro con un [[Prototype]]collegamento che puoi modificare ogni volta che lo desideri. Se prendi due [[Prototype]]oggetti collegati creati tramite lo stile OLOO come dipendenti l'uno dall'altro, dovresti anche pensare lo stesso a quelli creati tramite le constructorchiamate.

var foo= {},
    bar= Object.create(foo),
    baz= Object.create(bar);


console.log(Object.getPrototypeOf(foo)) //Object.prototype

console.log(Object.getPrototypeOf(bar)) //foo

console.log(Object.getPrototypeOf(baz)) //bar

Ora pensa per un secondo pensi a foo barebaz come dipendenti l'uno dall'altro?

Ora facciamo lo stesso questo constructorcodice di stile-

function Foo() {}

function Bar() {}

function Baz() {}

Bar.prototype= Object.create(Foo);
Baz.prototype= Object.create(Bar);

var foo= new Foo(),
    bar= new Bar().
    baz= new Baz();

console.log(Object.getPrototypeOf(foo)) //Foo.prototype
console.log(Object.getPrototypeOf(Foo.prototype)) //Object.prototype

console.log(Object.getPrototypeOf(bar)) //Bar.prototype
console.log(Object.getPrototypeOf(Bar.prototype)) //Foo.prototype

console.log(Object.getPrototypeOf(baz)) //Baz.prototype
console.log(Object.getPrototypeOf(Baz.prototype)) //Bar.prototype

L'unica differenza b / w quest'ultimo e il primo codice è che in quest'ultimo foo, bar, bazbbjects sono collegate fra di loro attraverso oggetti arbitrari della loro constructorfunzione ( Foo.prototype, Bar.prototype, Baz.prototype) ma in quella precedente ( OLOOstile) sono legati direttamente. Entrambi i modi si sta solo collegamento foo, bar, bazcon l'altro, proprio di quella precedente e, indirettamente, nel secondo quella. Ma in entrambi i casi gli oggetti sono indipendenti l'uno dall'altro perché in realtà non è come un'istanza di una classe che, una volta istanziata, non può essere fatta ereditare da un'altra classe. Puoi sempre modificare anche l'oggetto che un oggetto deve delegare.

var anotherObj= {};
Object.setPrototypeOf(foo, anotherObj);

Quindi sono tutti indipendenti l'uno dall'altro.

"Speravo OLOOche risolvesse il problema in cui ogni oggetto non sa nulla dell'altro."

Sì, è davvero possibile

Usiamo Techcome oggetto di utilità-

 var Tech= {
     tag: "technology",
     setName= function(name) {
              this.name= name;
}
}

crea tutti gli oggetti che desideri collegati a Tech-

var html= Object.create(Tech),
     css= Object.create(Tech),
     js= Object.create(Tech);

Some checking (avoiding console.log)- 

    html.isPrototypeOf(css); //false
    html.isPrototypeOf(js); //false

    css.isPrototypeOf(html); //false
    css.isPrototypeOf(js); //false

    js.isPrototypeOf(html); //false
    js.isPrototypwOf(css); //false

    Tech.isPrototypeOf(html); //true
    Tech.isPrototypeOf(css); //true
    Tech.isPrototypeOf(js); //true

Pensi html, css, jsgli oggetti sono collegati fra di loro? No, non lo sono. Ora vediamo come avremmo potuto farlo con la constructorfunzione-

function Tech() { }

Tech.prototype.tag= "technology";

Tech.prototype.setName=  function(name) {
              this.name= name;
}

crea tutti gli oggetti che desideri collegati a Tech.proptotype-

var html= new Tech(),
     css= new Tech(),
      js= new Tech();

Alcuni controlli (evitando console.log) -

html.isPrototypeOf(css); //false
html.isPrototypeOf(js); //false

css.isPrototypeOf(html); //false
css.isPrototypeOf(js); //false

js.isPrototypeOf(html); //false
js.isPrototypeOf(css); //false

Tech.prototype.isPrototypeOf(html); //true
Tech.prototype.isPrototypeOf(css); //true
Tech.prototype.isPrototypeOf(js); //true

Come pensi che questi constructoroggetti -style ( html, css, js) oggetti differiscono dal OLOOCodice in stile? In effetti servono allo stesso scopo. In OLOOuno stile gli oggetti delegano a Tech(la delega era impostata esplicitamente) mentre in constructoruno stile gli oggetti delegano a Tech.prototype(la delega era impostata in modo implicito). Alla fine si finisce per collegare i tre oggetti, non avendo alcun collegamento tra loro, a un oggetto, usando direttamente OLOO-style, usando indirettamente constructor-style.

"Così com'è, ObjB deve essere creato da ObjA .. Object.create (ObjB) ecc"

No, ObjBqui non è come un'istanza (nei linguaggi classici) di nessuna classe ObjA. Si potrebbe dire che l' objBoggetto viene reso delegato ObjAall'oggetto al momento della sua creazione " . Se avessi usato il costruttore, avresti fatto lo stesso" accoppiamento ", sebbene indirettamente utilizzando .prototypes.


3

@Marcus @bholben

Forse possiamo fare qualcosa del genere.

    const Point = {

        statics(m) { if (this !== Point) { throw Error(m); }},

        create (x, y) {
            this.statics();
            var P = Object.create(Point);
            P.init(x, y);
            return P;
        },

        init(x=0, y=0) {
            this.x = x;
            this.y = y;
        }
    };


    const Point3D = {

        __proto__: Point,

        statics(m) { if (this !== Point3D) { throw Error(m); }},

        create (x, y, z) {
            this.statics();
            var P = Object.create(Point3D);
            P.init(x, y, z);
            return P;
        },

        init (x=0, y=0, z=0) {
            super.init(x, y);
            this.z = z;
        }
    }; 

Ovviamente, creare un oggetto Point3D che si collega al prototipo di un oggetto Point2D è un po 'sciocco, ma non è questo il punto (volevo essere coerente con il tuo esempio). Comunque, per quanto riguarda le lamentele:

  1. L'asimmetria può essere risolta con Object.setPrototypeOf di ES6 o il più disapprovato __proto__ = ...che uso. Ora possiamo anche usare super su oggetti normali, come visto in Point3D.init(). Un altro modo sarebbe fare qualcosa di simile

    const Point3D = Object.assign(Object.create(Point), {  
        ...  
    }   

    anche se non mi piace particolarmente la sintassi.


  1. Possiamo sempre solo avvolgere p = Object.create(Point)e poi p.init()in un costruttore. ad es Point.create(x,y). Usando il codice sopra possiamo creare una Point3D"istanza" nel modo seguente.

    var b = Point3D.create(1,2,3);
    console.log(b);                         // { x:1, y:2, z:3 }
    console.log(Point.isPrototypeOf(b));    // true
    console.log(Point3D.isPrototypeOf(b))   // true

  1. Ho appena escogitato questo trucco per emulare metodi statici in OLOO. Non sono sicuro se mi piaccia o no. Richiede la chiamata di una proprietà speciale all'inizio di qualsiasi metodo "statico". Ad esempio, ho reso il Point.create()metodo statico.

        var p = Point.create(1,2);
        var q = p.create(4,1);          // Error!  

In alternativa, con i simboli ES6 puoi estendere in modo sicuro le classi di base Javascript. Quindi potresti salvarti del codice e definire la proprietà speciale su Object.prototype. Per esempio,

    const extendedJS = {};  

    ( function(extension) {

        const statics = Symbol('static');

        Object.defineProperty(Object.prototype, statics, {
            writable: true,
            enumerable: false,
            configurable: true,
            value(obj, message) {
                if (this !== obj)
                    throw Error(message);
            }
        });

        Object.assign(extension, {statics});

    })(extendedJS);


    const Point = {
        create (x, y) {
            this[extendedJS.statics](Point);
            ...


2

@ james emanon - Quindi, ti riferisci all'ereditarietà multipla (discussa a pagina 75 nel libro "You Don't Know JS: this & Object Prototypes"). E quel meccanismo che possiamo trovare nella funzione di sottolineatura "estendere" per esempio. I nomi degli oggetti che hai affermato nel tuo esempio sono un po 'mescolando mele, arance e caramelle, ma capisco il punto dietro. Dalla mia esperienza questa sarebbe la versione OOLO:

var ObjA = {
  setA: function(a) {
    this.a = a;
  },
  outputA: function() {
    console.log("Invoking outputA - A: ", this.a);
  }
};

// 'ObjB' links/delegates to 'ObjA'
var ObjB = Object.create( ObjA );

ObjB.setB = function(b) {
   this.b = b;
}

ObjB.setA_B = function(a, b) {
    this.setA( a ); // This is obvious. 'setA' is not found in 'ObjB' so by prototype chain it's found in 'ObjA'
    this.setB( b );
    console.log("Invoking setA_B - A: ", this.a, " B: ", this.b);
};

// 'ObjC' links/delegates to 'ObjB'
var ObjC = Object.create( ObjB );

ObjC.setC = function(c) {
    this.c = c;  
};

ObjC.setA_C = function(a, c) {
    this.setA( a ); // Invoking 'setA' that is clearly not in ObjC shows that prototype chaining goes through ObjB all the way to the ObjA
    this.setC( c );
    console.log("Invoking setA_C - A: ", this.a, " C: ", this.c);
};

ObjC.setA_B_C = function(a, b, c){
    this.setA( a ); // Invoking 'setA' that is clearly not in ObjC nor ObjB shows that prototype chaining got all the way to the ObjA
    this.setB( b );
    this.setC( c );
    console.log("Invoking setA_B_C - A: ", this.a, " B: ", this.b, " C: ", this.c);
};

ObjA.setA("A1");
ObjA.outputA(); // Invoking outputA - A:  A1

ObjB.setA_B("A2", "B1"); // Invoking setA_B - A:  A2  B:  B1

ObjC.setA_C("A3", "C1"); // Invoking setA_C - A:  A3  C:  C1
ObjC.setA_B_C("A4", "B2", "C1"); // Invoking setA_B_C - A:  A4  B:  B2  C:  C1

È un semplice esempio, ma il punto mostrato è che stiamo solo concatenando oggetti insieme in una struttura / formazione piuttosto piatta e abbiamo ancora la possibilità di utilizzare metodi e proprietà da più oggetti. Otteniamo le stesse cose dell'approccio class / "copia delle proprietà". Sommato da Kyle (pagina 114, "this & Object Prototypes"):

In altre parole, il meccanismo effettivo, l'essenza di ciò che è importante per la funzionalità che possiamo sfruttare in JavaScript, riguarda il collegamento di oggetti ad altri oggetti .

Capisco che il modo più naturale per te sarebbe quello di dichiarare tutti gli oggetti "genitore" (attento :)) in un unico luogo / chiamata di funzione piuttosto che modellare l'intera catena.

Ciò che richiede è un cambiamento nel pensiero e nel modellare i problemi nelle nostre applicazioni in base a ciò. Mi sto anche abituando. Spero che aiuti e il verdetto finale dello stesso Kyle sarebbe fantastico. :)


Sì - grazie - ma speravo di allontanarmi da questa metodologia perché il modo in cui lo hai e il modo in cui ho pensato di farlo rende ogni oggetto dipendente dall'altro .. Speravo che OLOO risolvesse il problema in cui ogni oggetto non sa niente dell'altro. Così com'è, objB deve essere creato da ObjA .. Object.create (ObjB) ecc .. che è troppo accoppiato. qualche idea?
james emanon

-1

@Marcus, proprio come te, sono stato appassionato di OLOO e non mi piace anche l'asimmetria come descritto nel tuo primo punto. Ho giocato con un'astrazione per riportare la simmetria. Potresti creare una link()funzione che viene utilizzata al posto di Object.create(). Quando viene utilizzato, il codice potrebbe essere simile a questo ...

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    }
};


var Point3D = link(Point, {
    init: function(x,y,z) {
        Point.init.call(this, x, y);
        this.z = z;
    }
});

Ricorda che Object.create()ha un secondo parametro che può essere passato. Ecco la funzione di collegamento che sfrutta il secondo parametro. Permette anche un po 'di configurazione personalizzata ...

function link(delegate, props, propsConfig) {
  props = props || {};
  propsConfig = propsConfig || {};

  var obj = {};
  Object.keys(props).forEach(function (key) {
    obj[key] = {
      value: props[key],
      enumerable: propsConfig.isEnumerable || true,
      writable: propsConfig.isWritable || true,
      configurable: propsConfig.isConfigurable || true
    };
  });

  return Object.create(delegate, obj);
}

Ovviamente, penso che @Kyle non approverebbe l'ombreggiatura della init()funzione nell'oggetto Point3D. ;-)


Guardando indietro a questo, ora penso che combinandolo Object.assign()con Object.create(), possiamo notevolmente semplificare la link()funzione sopra. Al suo posto, potremmo usare questo: function create(delegate, props) { return Object.assign(Object.create(delegate), props); }. O meglio ancora, possiamo usare sottolineatura o Lodash per renderlo veramente conciso: _.create(delegate, props).
bholben

-1

C'è un modo per OLOO più di "due" oggetti .. tutti gli esempi sono costituiti dall'esempio basato (vedi l'esempio di OP). Diciamo che abbiamo i seguenti oggetti, come possiamo creare un "quarto" oggetto che abbia gli attributi degli "altri" tre? ala ...

var Button = {
     init: function(name, cost) {
       this.buttonName = name;
       this.buttonCost = cost;
     }
}

var Shoe = {
     speed: 100
}

var Bike = {
     range: '4 miles'
}

questi oggetti sono arbitrari e potrebbero comprendere tutti i tipi di comportamenti. Ma il succo è che abbiamo un numero n di oggetti e il nostro nuovo oggetto ha bisogno di qualcosa da tutti e tre.

invece degli esempi forniti ala:

var newObj = Object.create(oneSingularObject);
    newObj.whatever..

MA, il nostro nuovo oggetto = (Button, Bike, Shoe) ...

Qual è lo schema per farlo funzionare in OLOO?


1
Suona come "privilegiare la composizione sull'ereditarietà" - un'ottima strategia. In ES6 puoi usare Object.assign(): developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Se scrivi in ​​ES5, puoi usare Underscore _.extend()o Lodash _.assign(). Ecco un ottimo video per spiegare ... youtu.be/wfMtDGfHWpA . Se hai proprietà in collisione, vince l'ultima, quindi l'ordine è importante.
bholben
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.