Kyle Simpsons OLOO-Muster gegen Prototyp-Entwurfsmuster

109

Unterscheidet sich Kyle Simpsons "OLOO-Muster (Objekte, die mit anderen Objekten verknüpft sind)" in irgendeiner Weise vom Prototyp-Entwurfsmuster? Was genau führt sein Muster ein, außer es durch etwas zu prägen, das speziell auf "Verknüpfen" (das Verhalten von Prototypen) hinweist und klarstellt, dass hier kein "Kopieren" stattfindet (ein Verhalten von Klassen)?

Hier ist ein Beispiel für Kyles Muster aus seinem Buch "Sie kennen JS nicht: 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."
shmuli
quelle
2
Können Sie zumindest einen Link zu einer Beschreibung des Musters erstellen, nach dem Sie fragen? Noch besser wäre es, in Ihrer Frage ein Codebeispiel dafür zu zeigen.
jfriend00
4
Getify ist manchmal auf Stackoverflow. Ich habe ihm diese Frage getwittert :)
Pointy

Antworten:

155

Was genau führt sein Muster ein?

OLOO umfasst die Prototypkette unverändert, ohne dass eine andere (IMO verwirrende) Semantik erforderlich ist, um die Verknüpfung herzustellen.

Diese beiden Schnipsel haben also genau das gleiche Ergebnis, kommen aber unterschiedlich dahin.

Konstruktorform:

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

OLOO Form:

var FooObj = { y: 11 };

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

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

In beiden Snippets ist ein xObjekt [[Prototype]]mit einem Objekt ( Bar.prototypeoder BarObj) verknüpft, das wiederum mit dem dritten Objekt ( Foo.prototypeoder FooObj) verknüpft ist .

Die Beziehungen und die Delegierung sind zwischen den Snippets identisch. Die Speichernutzung ist zwischen den Snippets identisch. Die Fähigkeit, viele "Kinder" zu erstellen (auch bekannt als viele Objekte wie " x1Durch" x1000usw.), ist zwischen den Snippets identisch. Die Leistung der Delegierung ( x.yund x.z) ist zwischen den Snippets identisch. Die Leistung bei der Objekterstellung ist mit OLOO langsamer, aber die Überprüfung der Integrität zeigt, dass die langsamere Leistung wirklich kein Problem darstellt.

Ich behaupte, OLOO bietet an, dass es viel einfacher ist, die Objekte einfach auszudrücken und direkt zu verknüpfen, als sie indirekt über den Konstruktor / die newMechanismen zu verknüpfen . Letzteres gibt vor, über Klassen zu sein, ist aber wirklich nur eine schreckliche Syntax zum Ausdrücken von Delegierung ( Randnotiz: ES6- classSyntax auch!).

OLOO schneidet gerade den Mittelsmann aus.

Hier ist ein weiterer Vergleich von classvs OLOO.

Kyle Simpson
quelle
2
Ich fand Ihre Antwort und die in Ihren Büchern beschriebene Idee von OLOO sehr interessant. Ich hätte gerne Ihr Feedback zu dieser Frage: stackoverflow.com/questions/40395762/… Insbesondere, wenn Sie diese Implementierung für richtig befunden haben und wie Sie Probleme im Zusammenhang mit dem Zugriff lösen können privates Mitglied. Vielen Dank für Ihre Zeit im Voraus und herzlichen Glückwunsch zu Ihrem neuesten Buch.
GibboK
Ist aber Object.create(...)um ein Vielfaches langsamer als new. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/…
Pier
3
@Pier die Leistung ist eigentlich kein so großes Problem. Der defekte Blog-Post-Link zur Überprüfung der Leistung der Objekterstellung wurde behoben, in dem erklärt wird, wie man richtig darüber nachdenkt.
Kyle Simpson
2
Und jQuery ist langsamer als die DOM-API, oder? Aber es ist das aktuelle Jahr, Mann - ich würde lieber elegant und einfach schreiben, als mir Gedanken über die Optimierung zu machen. Wenn ich später eine Mikrooptimierung durchführen muss, mache ich mir zu gegebener Zeit Sorgen.
Eirik Birkeland
6
Ich möchte hinzufügen, dass Object.create () jetzt, etwas mehr als ein Jahr später, stark in Chrom optimiert ist und dass jsperf es zeigt - es ist jetzt eine der schnellsten Optionen. Dies zeigt genau, warum Sie sich nicht mit solchen Mikrooptimierungen befassen sollten, sondern nur algorithmisch fundierten Code schreiben sollten.
Kyle Baker
25

Ich habe Kyles Buch gelesen und fand es sehr informativ, insbesondere die Details darüber, wie thises gebunden ist.

Vorteile:

Für mich gibt es ein paar große Profis von OLOO:

1. Einfachheit

OLOO Object.create()erstellt ein neues Objekt, das [[prototype]]mit einem anderen Objekt verknüpft ist . Sie müssen nicht verstehen, dass Funktionen eine prototypeEigenschaft haben oder sich über mögliche Fallstricke Gedanken machen, die sich aus ihrer Änderung ergeben.

2. Sauberere Syntax

Dies ist fraglich, aber ich bin der Meinung, dass die OLOO-Syntax (in vielen Fällen) übersichtlicher und prägnanter ist als der "Standard" -Javascript-Ansatz, insbesondere wenn es um Polymorphismus ( superAufrufe im Stil) geht.

Nachteile:

Ich denke, es gibt ein fragwürdiges Stück Design (eines, das tatsächlich zu Punkt 2 oben beiträgt), und das hat mit Schatten zu tun:

Bei der Verhaltensdelegierung vermeiden wir, dass die Namen auf verschiedenen Ebenen der [[Prototype]]Kette möglichst gleich sind .

Die Idee dahinter ist, dass Objekte ihre eigenen spezifischeren Funktionen haben, die dann intern an Funktionen weiter unten in der Kette delegieren. Beispielsweise haben Sie möglicherweise ein resourceObjekt mit einer save()Funktion, die eine JSON-Version des Objekts an den Server sendet, aber Sie haben möglicherweise auch ein clientResourceObjekt mit einer stripAndSave()Funktion, die zuerst Eigenschaften entfernt, die nicht an den Server gesendet werden sollen .

Das potenzielle Problem ist: Wenn jemand anderes vorbeikommt und beschließt, ein specialResourceObjekt zu erstellen, das die gesamte Prototypenkette nicht vollständig kennt, kann er sich vernünftigerweise dazu entschließen, einen Zeitstempel für den letzten Speichervorgang unter einer aufgerufenen Eigenschaft zu speichern save, die die save()Basisfunktionalität überschattet Das resourceObjekt zwei Glieder entlang der Prototypenkette:

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!

Dies ist ein besonders konstruiertes Beispiel, aber der Punkt ist , dass speziell nicht Shadowing andere Eigenschaften auf einige unangenehme Situationen und schweren Einsatz eines Thesaurus führen!

Eine bessere Illustration hierfür wäre möglicherweise eine initMethode - besonders ergreifend, da OOLO Konstruktortypfunktionen umgeht. Da wahrscheinlich jedes verwandte Objekt eine solche Funktion benötigt, kann es eine mühsame Übung sein, sie angemessen zu benennen, und die Einzigartigkeit kann es schwierig machen, sich zu merken, welche zu verwenden sind.

* Eigentlich ist es nicht besonders vernünftig ( lastSavedwäre viel besser, aber es ist nur ein Beispiel.)

Ed Hinchliffe
quelle
23
Ich bin damit einverstanden, dass das Potenzial für Namenskollisionen ein Nachteil ist ... aber tatsächlich ist es ein Nachteil des [[Prototype]]Systems selbst, nicht speziell von OLOO.
Kyle Simpson
Vielleicht hätte das auch im Buch erwähnt werden sollen?
Mieten
Ich bin mir nicht sicher, ob dies wirklich eine Lösung für das Problem ist, das @Ed Hinchliffe beschreibt, da es save () nur in seinen eigenen Namespace verschiebt, aber es funktioniert codepen.io/tforward/pen/govEPr?editors=1010
Tristan Forward
Ich denke, @ ed-hinchliffe meinte b.timeStampedSave();statt in der a.timeStampedSave();letzten Zeile des Code-Snippets.
amangpt777
1
@ tristan-forward Danke, dass du Rick und Morty dazu gebracht hast!
Eric Bishard
13

Die Diskussion in "Sie kennen JS nicht: this & Object Prototypes" und die Präsentation des OLOO regen zum Nachdenken an und ich habe eine Menge gelernt, die durch das Buch gegangen sind. Die Vorzüge des OLOO-Musters sind in den anderen Antworten gut beschrieben. Ich habe jedoch die folgenden Beschwerden über Haustiere (oder es fehlt etwas, das mich daran hindert, es effektiv anzuwenden):

1

Wenn eine "Klasse" "eine andere" Klasse "im klassischen Muster erbt, können die beiden Funktionen als ähnliche Syntax deklariert werden ( " Funktionsdeklaration "oder" Funktionsanweisung " ):

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

Im Gegensatz dazu werden im OLOO-Muster verschiedene syntaktische Formen verwendet, um die Basis und die abgeleiteten Objekte zu definieren:

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;
};

Wie Sie im obigen Beispiel sehen können, kann das Basisobjekt mithilfe der Objektliteralnotation definiert werden, während dieselbe Notation nicht für das abgeleitete Objekt verwendet werden kann. Diese Asymmetrie nervt mich.

2

Im OLOO-Muster besteht das Erstellen eines Objekts aus zwei Schritten:

  1. Anruf Object.create
  2. Rufen Sie eine benutzerdefinierte, nicht standardmäßige Methode auf, um das Objekt zu initialisieren (an die Sie sich erinnern müssen, da sie von Objekt zu Objekt unterschiedlich sein kann):

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

Im Gegensatz dazu verwenden Sie im Prototypmuster den Standardoperator new:

var p2a = new Point(1,1);

3

Im klassischen Muster kann ich "statische" Dienstprogrammfunktionen erstellen, die nicht direkt auf einen "Augenblick" angewendet werden, indem ich sie direkt der "Klassen" -Funktion (im Gegensatz zu ihrer .prototype) zuweise. ZB wie Funktion squareim folgenden Code:

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

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

Im Gegensatz dazu sind im OLOO-Muster alle "statischen" Funktionen (über die [[Prototyp]] - Kette) auch für die Objektinstanzen verfügbar:

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));}
};
Marcus Junius Brutus
quelle
2
Ihr erstes Codebeispiel enthält keine Literale. Sie missbrauchen wahrscheinlich den "wörtlichen" Begriff, der ihm eine andere Bedeutung gibt.
Ich
2
In Bezug auf den zweiten Punkt argumentiert der Autor, dass es eine "bessere" Trennung von Bedenken ist, Erstellung und Initialisierung getrennt zu haben, und führt an, dass es einige seltene Anwendungsfälle geben könnte, in denen dies glänzen könnte (z. B. ein Objektpool). Ich finde das Argument furchtbar schwach.
Mieten
2
Auch in Bezug auf den zweiten Punkt können Sie mit OLOO Ihre Objekte gleichzeitig erstellen und auf die Initialisierung warten, während Sie beim Konstruktor beim Erstellen initialisieren müssen, sodass Kyle dies als Vorteil betrachtet.
Taco
5

"Ich dachte, es macht jedes Objekt vom anderen abhängig."

Wie Kyle erklärt, sind zwei Objekte, wenn sie miteinander [[Prototype]]verbunden sind, nicht wirklich voneinander abhängig. stattdessen sind sie einzelne Objekte. Sie verknüpfen ein Objekt mit dem anderen über eine [[Prototype]]Verknüpfung, die Sie jederzeit ändern können. Wenn Sie zwei [[Prototype]]verknüpfte Objekte, die im OLOO-Stil erstellt wurden, als voneinander abhängig betrachten, sollten Sie auch die Objekte berücksichtigen, die durch constructorAufrufe erstellt wurden.

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

Jetzt denken für eine Sekunde denken Sie über foo barund bazwie bei jedem anderen-abhängig zu sein?

Jetzt machen wir dasselbe mit diesem constructorStilcode-

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

Der einzige Unterschied b / w der letzteren und dem ersteren Code ist , dass in letzterer ein foo, bar, bazbbjects zu jedem-seitig durch beliebige Objekte ihrer verknüpft sind constructorFunktion ( Foo.prototype, Bar.prototype, Baz.prototype) , aber in dem früheren eine ( OLOOArt) sie direkt miteinander verbunden sind. Beide Wege Sie nur die Verknüpfung foo, bar, bazmiteinander, direkt in der ehemaligen ein und indirekt in letzterem ein. In beiden Fällen sind die Objekte jedoch unabhängig voneinander, da es sich nicht wirklich um eine Instanz einer Klasse handelt, die nach der Instanziierung nicht von einer anderen Klasse geerbt werden kann. Sie können jederzeit ändern, welches Objekt ein Objekt auch delegieren soll.

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

Sie sind also alle unabhängig voneinander.

"Ich hatte gehofft OLOO, das Problem zu lösen, bei dem jedes Objekt nichts über das andere weiß."

Ja das ist ja möglich-

Verwenden wir Techals Utility-Objekt-

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

erstellen Sie so viele Objekte wie Sie verknüpft werden soll 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

Glaubst du html, css, jsverbunden sind Objekte an alle-andere? Nein, das sind sie nicht. Nun wollen wir sehen, wie wir das mit constructorfunction- hätten machen können.

function Tech() { }

Tech.prototype.tag= "technology";

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

erstellen Sie so viele Objekte wie Sie verknüpft werden soll Tech.proptotype-

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

Einige Überprüfungen (Vermeidung von 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

Wie denken Sie , diese constructor-Stil Objects ( html, css, js) unterscheiden sich Objekte aus dem OLOO-Stil Code? Tatsächlich dienen sie demselben Zweck. Im OLOOStil delegieren ein Objekt an Tech(Delegierung wurde explizit festgelegt), während im constructorStil ein Objekt an delegiert wird Tech.prototype(Delegierung wurde implizit festgelegt). Letztendlich verknüpfen Sie die drei Objekte, die keine Verknüpfung miteinander haben, mit einem Objekt, indem Sie direkt OLOO-style und indirekt constructor-style verwenden.

"Wie es ist, muss ObjB aus ObjA erstellt werden. Object.create (ObjB) etc"

Nein, ObjBhier ist nicht wie eine Instanz (in der klassischen basierten Sprachen) jede Klasse ObjA. Es sollte gesagt werden, dass das objBObjekt zum ObjAZeitpunkt der Erstellung an das Objekt delegiert wird. " Wenn Sie den Konstruktor verwendet hätten, hätten Sie dieselbe 'Kopplung' durchgeführt, allerdings indirekt unter Verwendung von .prototypes.

Abhishek Sachan
quelle
3

@Marcus @bholben

Vielleicht können wir so etwas tun.

    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;
        }
    }; 

Natürlich ist das Erstellen eines Point3D-Objekts, das mit dem Prototyp eines Point2D-Objekts verknüpft ist, etwas albern, aber das ist nicht der Punkt (ich wollte mit Ihrem Beispiel übereinstimmen). Sowieso, soweit die Beschwerden gehen:

  1. Die Asymmetrie kann mit Object.setPrototypeOf von ES6 oder mit dem verpönten , __proto__ = ...das ich verwende , behoben werden . Wir können jetzt auch Super für normale Objekte verwenden, wie in zu sehen Point3D.init(). Ein anderer Weg wäre, so etwas zu tun

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

    obwohl mir die Syntax nicht besonders gefällt.


  1. Wir können immer nur einwickeln p = Object.create(Point)und dann p.init()in einen Konstruktor. zB Point.create(x,y). Mit dem obigen Code können wir eine Point3D"Instanz" auf folgende Weise erstellen .

    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. Ich habe mir gerade diesen Hack ausgedacht, um statische Methoden in OLOO zu emulieren. Ich bin mir nicht sicher, ob es mir gefällt oder nicht. Es erfordert den Aufruf einer speziellen Eigenschaft am Anfang aller "statischen" Methoden. Zum Beispiel habe ich die Point.create()Methode statisch gemacht.

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

Alternativ können Sie mit ES6- Symbolen Javascript-Basisklassen sicher erweitern. Sie können sich also Code sparen und die spezielle Eigenschaft für Object.prototype definieren. Beispielsweise,

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

Andrew Szymczak
quelle
2

@james emanon - Sie beziehen sich also auf Mehrfachvererbung (siehe Seite 75 im Buch "Sie kennen JS nicht: This & Object Prototypes"). Und diesen Mechanismus finden wir zum Beispiel in der Funktion "Erweitern" des Unterstrichs. Die Namen der Objekte, die Sie in Ihrem Beispiel angegeben haben, sind ein bisschen Mischen von Äpfeln, Orangen und Süßigkeiten, aber ich verstehe den Punkt dahinter. Nach meiner Erfahrung wäre dies die OOLO-Version:

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

Es ist ein einfaches Beispiel, aber der gezeigte Punkt ist, dass wir nur Objekte in einer eher flachen Struktur / Formation miteinander verketten und dennoch die Möglichkeit haben, Methoden und Eigenschaften von mehreren Objekten zu verwenden. Wir erreichen die gleichen Dinge wie beim Klassen- / "Kopieren der Eigenschaften" -Ansatz. Zusammengefasst von Kyle (Seite 114, "this & Object Prototypes"):

Mit anderen Worten, der eigentliche Mechanismus, das Wesentliche für die Funktionalität, die wir in JavaScript nutzen können, besteht darin, dass Objekte mit anderen Objekten verknüpft werden .

Ich verstehe, dass es für Sie natürlicher wäre, alle "übergeordneten" (vorsichtigen :)) Objekte an einem Ort / Funktionsaufruf anzugeben, anstatt die gesamte Kette zu modellieren.

Was es erfordert, ist eine Verschiebung der Denk- und Modellierungsprobleme in unseren Anwendungen entsprechend. Ich gewöhne mich auch daran. Hoffe es hilft und das endgültige Urteil von Kyle selbst wäre großartig. :) :)

NenadPavlov
quelle
Ja - danke - aber ich hatte gehofft, mich von dieser Methodik zu entfernen, weil die Art und Weise, wie Sie sie haben und wie ich sie mir vorgestellt habe, jedes Objekt vom anderen abhängig macht. Ich hatte gehofft, OLOO würde das Problem lösen, in dem Jedes Objekt weiß nichts über das andere. Wie es ist, muss objB aus ObjA .. Object.create (ObjB) etc .. erstellt werden, das zu gekoppelt ist. irgendwelche Ideen?
James Emanon
-1

@Marcus, genau wie Sie, ich war scharf auf OLOO und mag auch nicht die Asymmetrie, wie in Ihrem ersten Punkt beschrieben. Ich habe mit einer Abstraktion gespielt, um die Symmetrie zurückzubringen. Sie können eine link()Funktion erstellen , die anstelle von verwendet wird Object.create(). Bei Verwendung könnte Ihr Code ungefähr so ​​aussehen ...

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

Denken Sie daran, dass Object.create()ein zweiter Parameter übergeben werden kann. Hier ist die Verknüpfungsfunktion, die den zweiten Parameter nutzt. Es ermöglicht auch ein wenig benutzerdefinierte Konfiguration ...

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

Natürlich denke ich, dass @Kyle das Abschatten der init()Funktion im Point3D-Objekt nicht unterstützen würde . ;-);

bholben
quelle
Wenn ich zurückblicke, denke ich jetzt, dass wir durch die Kombination Object.assign()mit Object.create()die link()obige Funktion erheblich vereinfachen können. An seiner Stelle könnten wir dies verwenden : function create(delegate, props) { return Object.assign(Object.create(delegate), props); }. Oder noch besser, wir können Underscore oder Lodash verwenden, um es wirklich kurz zu machen : _.create(delegate, props).
Bholben
-1

Gibt es eine Möglichkeit, mehr als "zwei" Objekte zu OLOO zu machen? Alle Beispiele, die ich habe, bestehen aus dem basierten Beispiel (siehe Beispiel von OP). Nehmen wir an, wir hatten die folgenden Objekte. Wie können wir ein "viertes" Objekt erstellen, das die Attribute der "anderen" drei hat? ala ...

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

var Shoe = {
     speed: 100
}

var Bike = {
     range: '4 miles'
}

Diese Objekte sind willkürlich und können alle Arten von Verhaltensweisen umfassen. Aber das Wesentliche ist, wir haben 'n' Anzahl von Objekten und unser neues Objekt braucht etwas von allen drei.

anstelle der angegebenen Beispiele ala:

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

ABER unser neues Objekt = (Knopf, Fahrrad, Schuh) ......

Was ist das Muster, um dies in OLOO in Gang zu bringen?

James Emanon
quelle
1
Das klingt nach "Komposition gegenüber Vererbung bevorzugen" - eine großartige Strategie. In ES6 können Sie Object.assign()- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… verwenden . Wenn Sie in ES5 schreiben, können Sie Unterstriche _.extend()oder Lodashs verwenden _.assign(). Hier ist ein exzellentes Video zur Erklärung ... youtu.be/wfMtDGfHWpA . Wenn Sie kollidierende Eigenschaften haben, gewinnt die letzte - also ist die Reihenfolge wichtig.
Bholben