Modèle OLOO de Kyle Simpson vs modèle de conception de prototype

109

Le «modèle OLOO (objets liés à d'autres objets)» de Kyle Simpson diffère-t-il en quelque sorte du modèle de conception du prototype? À part l'inventer par quelque chose qui indique spécifiquement «lier» (le comportement des prototypes) et clarifier qu'il n'y a pas de «copie» qui se passe ici (un comportement de classes), qu'est-ce que son modèle introduit exactement?

Voici un exemple du modèle de Kyle tiré de son livre, "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."
shmuli
la source
2
Pouvez-vous au moins créer un lien vers une description du modèle que vous demandez. Encore mieux serait d'en montrer un exemple de code dans votre question.
jfriend00
4
Getify est parfois sur Stackoverflow. Je lui ai tweeté cette question :)
Pointy

Réponses:

155

qu'est-ce que son modèle introduit exactement?

OLOO embrasse la chaîne de prototypes telle quelle, sans avoir besoin de superposer une autre sémantique (déroutante IMO) pour obtenir le lien.

Donc, ces deux extraits ont le même résultat EXACT, mais y parviennent différemment.

Formulaire constructeur:

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

Formulaire OLOO:

var FooObj = { y: 11 };

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

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

Dans les deux extraits, un xobjet est [[Prototype]]lié à un objet ( Bar.prototypeou BarObj), qui à son tour est lié au troisième objet ( Foo.prototypeou FooObj).

Les relations et la délégation sont identiques entre les extraits. L'utilisation de la mémoire est identique entre les extraits. La possibilité de créer de nombreux "enfants" (c'est-à-dire de nombreux objets comme x1through x1000, etc.) est identique entre les extraits. Les performances de la délégation ( x.yet x.z) sont identiques entre les extraits. Les performances de création d'objet sont plus lentes avec OLOO, mais une vérification de cohérence qui révèle que les performances plus lentes ne sont vraiment pas un problème.

Ce que je soutiens qu'OLOO offre, c'est qu'il est beaucoup plus simple d'exprimer simplement les objets et de les lier directement, que de les lier indirectement via le constructeur / newmécanismes. Ce dernier fait semblant de parler de classes mais n'est en réalité qu'une terrible syntaxe pour exprimer la délégation ( note latérale: laclass syntaxe ES6 aussi !).

OLOO est juste en train d'éliminer les intermédiaires.

Voici une autre comparaison de classvs OLOO.

Kyle Simpson
la source
2
J'ai trouvé vraiment intéressant votre réponse et l'idée d'OLOO décrite dans vos livres, j'aimerais avoir vos commentaires sur cette question: stackoverflow.com/questions/40395762/... Surtout si vous avez trouvé cette implémentation correcte et comment résoudre le problème lié à l'accès membre privé. Merci pour votre temps à l'avance et félicitations pour votre dernier livre.
GibboK
Mais Object.create(...)est plusieurs fois plus lent que new. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor
Pier
3
@Pier, les performances ne sont pas vraiment un problème. Correction du lien de publication de blog cassé sur la vérification de la cohérence des performances de la création d'objets, ce qui explique comment bien réfléchir à cela.
Kyle Simpson
2
Et jQuery est plus lent que l'API DOM, non? Mais, c'est l'année en cours, mec - je préfère écrire élégamment et simplement que de me soucier de l'optimisation. Si j'ai besoin de micro-optimiser plus tard, je m'en soucierai le moment venu.
Eirik Birkeland
6
Je voudrais ajouter que maintenant, un peu plus d'un an plus tard, Object.create () est fortement optimisé dans Chrome, et que jsperf le montre - c'est l'une des options les plus rapides actuellement. Cela montre exactement pourquoi vous ne devriez pas vous préoccuper de telles micro-optimisations, mais simplement écrire du code algorithmique.
Kyle Baker
25

J'ai lu le livre de Kyle et je l'ai trouvé très instructif, en particulier le détail de la thisreliure.

Avantages:

Pour moi, il y a quelques grands avantages d'OLOO:

1. Simplicité

OLOO s'appuie sur Object.create()pour créer un nouvel objet qui est [[prototype]]lié à un autre objet. Vous n'avez pas à comprendre que les fonctions ont une prototypepropriété ou à vous soucier des pièges potentiels liés à leur modification.

2. Syntaxe plus propre

C'est discutable, mais je pense que la syntaxe OLOO est (dans de nombreux cas) plus claire et plus concise que l'approche javascript «standard», en particulier en ce qui concerne le polymorphisme ( superappels -style).

Les inconvénients:

Je pense qu'il y a un élément de conception discutable (qui contribue en fait au point 2 ci-dessus), et c'est à voir avec l'ombrage:

Dans la délégation de comportement, nous évitons, dans la mesure du possible, de nommer les choses de la même manière à différents niveaux de la [[Prototype]]chaîne.

L'idée derrière cela est que les objets ont leurs propres fonctions plus spécifiques qui sont ensuite déléguées en interne à des fonctions situées plus bas dans la chaîne. Par exemple, vous pouvez avoir un resourceobjet avec une save()fonction qui envoie une version JSON de l'objet au serveur, mais vous pouvez également avoir un clientResourceobjet qui a une stripAndSave()fonction, qui supprime d'abord les propriétés qui ne devraient pas être envoyées au serveur .

Le problème potentiel est le suivant: si quelqu'un d'autre arrive et décide de créer un specialResourceobjet, pas pleinement conscient de toute la chaîne de prototypes, il pourrait raisonnablement * décider d'enregistrer un horodatage pour la dernière sauvegarde sous une propriété appelée save, ce qui occulte la save()fonctionnalité de base sur l' resourceobjet deux maillons dans la chaîne de prototypes:

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!

C'est un exemple particulièrement artificiel, mais le fait est que le fait de ne pas cacher d'autres propriétés peut conduire à des situations délicates et à une utilisation intensive d'un thésaurus!

Une meilleure illustration serait peut-être une initméthode - particulièrement poignante car OOLO évite les fonctions de type constructeur. Étant donné que chaque objet lié aura probablement besoin d'une telle fonction, il peut être fastidieux de les nommer de manière appropriée, et le caractère unique peut rendre difficile de se rappeler lequel utiliser.

* En fait, ce n'est pas particulièrement raisonnable (ce lastSavedserait beaucoup mieux, mais ce n'est qu'un exemple.)

Ed Hinchliffe
la source
23
Je conviens que le potentiel de collision de noms est un inconvénient ... mais en fait c'est un inconvénient du [[Prototype]]système lui-même, pas d'OLOO en particulier.
Kyle Simpson
Peut-être que cela aurait dû être également mentionné dans le livre?
loue
Je ne suis pas vraiment sûr que ce soit vraiment une solution au problème décrit par @Ed Hinchliffe car il déplace simplement save () vers son propre espace de noms, mais cela fonctionne codepen.io/tforward/pen/govEPr?editors=1010
Tristan Forward
Je pense que @ ed-hinchliffe voulait dire b.timeStampedSave();au lieu de a.timeStampedSave();sur la dernière ligne de l'extrait de code.
amangpt777
1
@ tristan-forward merci d'avoir amené Rick et Morty là-dedans!
Eric Bishard
13

La discussion dans «You Don't Know JS: this & Object Prototypes» et la présentation de l'OLOO suscitent la réflexion et j'ai beaucoup appris en parcourant le livre. Les mérites du modèle OLOO sont bien décrits dans les autres réponses; cependant, j'ai les plaintes d'animal suivantes avec lui (ou il me manque quelque chose qui m'empêche de l'appliquer efficacement):

1

Lorsqu'une "classe" "hérite" d'une autre "classe" dans le modèle classique, les deux fonctions peuvent être déclarées avec une syntaxe similaire ( "déclaration de fonction" ou "instruction de fonction" ):

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

En revanche, dans le pattern OLOO, différentes formes syntaxiques permettent de définir la base et les objets dérivés:

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

Comme vous pouvez le voir dans l'exemple ci-dessus, l'objet de base peut être défini en utilisant la notation littérale d'objet, alors que la même notation ne peut pas être utilisée pour l'objet dérivé. Cette asymétrie me dérange.

2

Dans le modèle OLOO, la création d'un objet se fait en deux étapes:

  1. appel Object.create
  2. appelez une méthode personnalisée et non standard pour initialiser l'objet (dont vous devez vous souvenir car elle peut varier d'un objet à l'autre):

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

En revanche, dans le modèle Prototype, vous utilisez l'opérateur standard new:

var p2a = new Point(1,1);

3

Dans le modèle classique, je peux créer des fonctions utilitaires "statiques" qui ne s'appliquent pas directement à un "instant" en les affectant directement à la fonction "classe" (par opposition à la sienne .prototype). Par exemple, une fonction similaire squaredans le code ci-dessous:

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

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

En revanche, dans le modèle OLOO, toutes les fonctions "statiques" sont également disponibles (via la chaîne [[prototype]]) sur les instances d'objet:

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
la source
2
Il n'y a pas de littéraux dans votre premier exemple de code. Vous abusez probablement du terme «littéral» en lui donnant un autre sens. Juste en disant ...
Ivan Kleshnin
2
En ce qui concerne le 2ème point, l'auteur fait valoir que c'est une "meilleure" séparation des préoccupations de séparer la création et l'initialisation et cite qu'il pourrait y avoir un cas d'utilisation rare où cela peut briller (par exemple un pool d'objets). Je trouve l'argument terriblement faible.
loue
2
Encore une fois en ce qui concerne le 2ème point, avec OLOO, vous pouvez créer vos objets en une seule fois et attendre l'initialisation, alors qu'avec le constructeur, vous devez initialiser à la création, donc Kyle considère cela comme un avantage.
taco le
5

"J'ai pensé que cela rendait chaque objet dépendant de l'autre"

Comme l'explique Kyle, lorsque deux objets sont [[Prototype]]liés, ils ne dépendent pas vraiment l'un de l'autre; au lieu de cela, ils sont des objets individuels. Vous liez un objet à l'autre avec un [[Prototype]]lien que vous pouvez modifier à tout moment. Si vous considérez que deux [[Prototype]]objets liés créés via le style OLOO sont dépendants l'un de l'autre, vous devez également penser de la même manière à ceux créés via des constructorappels.

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

Maintenant , pensez à un deuxième pensez - vous foo baret bazcomme étant dépendants les uns des -autres?

Maintenant, faisons la même chose avec ce constructorcode de style-

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

La seule différence b / w celui - ci et l'ancien code est que dans ce dernier une foo, bar, bazbbjects sont reliés entre-eux par des objets quelconques de leur constructorfonction ( Foo.prototype, Bar.prototype, Baz.prototype) , mais dans l'ex - one ( OLOOmodèle) , ils sont directement liés. Les deux façons dont vous êtes juste reliant foo, bar, bazentre eux, directement dans l'ancien et indirectement dans le second. Mais, dans les deux cas, les objets sont indépendants les uns des autres car ce n'est pas vraiment comme une instance d'une classe qui, une fois instanciée, ne peut pas être obligée d'hériter d'une autre classe. Vous pouvez toujours modifier l'objet qu'un objet doit également déléguer.

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

Ils sont donc tous indépendants les uns des autres.

"J'espérais OLOOrésoudre le problème dans lequel chaque objet ne sait rien de l'autre."

Oui c'est en effet possible-

Utilisons Techcomme un objet utilitaire-

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

créer autant d'objets que vous souhaitez liés à 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

Pensez - vous que html, css, les jsobjets sont reliés l'un à-autre? Non, ils ne le sont pas. Voyons maintenant comment nous aurions pu faire cela avec la constructorfonction-

function Tech() { }

Tech.prototype.tag= "technology";

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

créer autant d'objets que vous souhaitez liés à Tech.proptotype-

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

Quelques vérifications (en évitant 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

Comment pensez-vous ces constructorobjets -style ( html, css, js) Les objets diffèrent du OLOOCode de style? En fait, ils servent le même objectif. Dans OLOO-style one objets délègue à Tech(la délégation a été définie explicitement) tandis que dans constructor-style one objets délègue à Tech.prototype(la délégation a été définie implicitement). En fin de compte, vous finissez par lier les trois objets, n'ayant aucun lien les uns avec les autres, à un objet, en utilisant directement OLOO-style, indirectement en utilisant constructor-style.

"En l'état, ObjB doit être créé à partir d'ObjA .. Object.create (ObjB) etc"

Non, ObjBce n'est pas comme une instance (dans les langages classiques) d'une classe quelconque ObjA. On pourrait dire que l' objBobjet est rendu délégué à l' ObjAobjet au moment de sa création . " Si vous avez utilisé constructeur, vous auriez fait le même 'couplage', bien qu'indirectement en utilisant .prototypes.

Abhishek Sachan
la source
3

@Marcus @bholben

Peut-être pouvons-nous faire quelque chose comme ça.

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

Bien sûr, créer un objet Point3D qui renvoie au prototype d'un objet Point2D est un peu idiot, mais ce n'est pas la question (je voulais être cohérent avec votre exemple). Quoi qu'il en soit, en ce qui concerne les plaintes:

  1. L'asymétrie peut être corrigée avec Object.setPrototypeOf d' ES6 ou le plus mal vu __proto__ = ...que j'utilise. Nous pouvons également utiliser super sur des objets réguliers maintenant, comme vu dans Point3D.init(). Une autre façon serait de faire quelque chose comme

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

    bien que je n'aime pas particulièrement la syntaxe.


  1. Nous pouvons toujours simplement envelopper p = Object.create(Point)et ensuite p.init()dans un constructeur. par exemple Point.create(x,y). En utilisant le code ci-dessus, nous pouvons créer une Point3D"instance" de la manière suivante.

    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. Je viens de créer ce hack pour émuler des méthodes statiques dans OLOO. Je ne sais pas si je l'aime ou pas. Cela nécessite d'appeler une propriété spéciale en haut de toute méthode "statique". Par exemple, j'ai rendu la Point.create()méthode statique.

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

Alternativement, avec ES6 Symbols, vous pouvez étendre en toute sécurité les classes de base Javascript. Ainsi, vous pouvez vous sauver du code et définir la propriété spéciale sur Object.prototype. Par exemple,

    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
la source
2

@james emanon - Donc, vous faites référence à l'héritage multiple (discuté à la page 75 dans le livre "You Don't Know JS: this & Object Prototypes"). Et ce mécanisme que nous pouvons trouver dans la fonction "extend" de soulignement par exemple. Les noms d'objets que vous avez indiqués dans votre exemple mélangent un peu des pommes, des oranges et des bonbons, mais je comprends le point derrière. D'après mon expérience, ce serait la version 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

C'est un exemple simple, mais le point montré est que nous enchaînons simplement des objets ensemble dans une structure / formation plutôt plate et avons toujours la possibilité d'utiliser des méthodes et des propriétés à partir de plusieurs objets. Nous obtenons les mêmes résultats qu'avec l'approche de classe / "copie des propriétés". Résumé par Kyle (page 114, "this & Object Prototypes"):

En d'autres termes, le mécanisme réel, l'essence même de ce qui est important pour la fonctionnalité que nous pouvons exploiter dans JavaScript, concerne les objets liés à d'autres objets .

Je comprends qu'une manière plus naturelle pour vous serait de déclarer tous les objets «parents» (attention :)) en un seul endroit / appel de fonction plutôt que de modéliser toute la chaîne.

Ce qu'il faut, c'est un changement de pensée et de modélisation des problèmes dans nos applications en fonction de cela. Je m'y habitue aussi. J'espère que cela aide et que le verdict final du Kyle lui-même serait formidable. :)

NenadPavlov
la source
Oui - merci - mais j'espérais m'éloigner de cette méthodologie parce que la façon dont vous l'avez et la façon dont j'ai pensé le faire rend chaque objet dépendant de l'autre. J'espérais que OLOO résoudrait le problème dans lequel chaque objet ne sait rien de l'autre. Tel quel, objB doit être créé à partir d'ObjA .. Object.create (ObjB) etc. qui est trop couplé. des idées?
james emanon
-1

@Marcus, tout comme vous, j'ai beaucoup aimé OLOO et je n'aime pas non plus l'asymétrie décrite dans votre premier point. J'ai joué avec une abstraction pour ramener la symétrie. Vous pouvez créer une link()fonction qui est utilisée à la place de Object.create(). Lorsqu'il est utilisé, votre code pourrait ressembler à ceci ...

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

N'oubliez pas que Object.create()possède un deuxième paramètre qui peut être transmis. Voici la fonction de liaison qui exploite le deuxième paramètre. Cela permet également un peu de configuration personnalisée ...

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

Bien sûr, je pense que @Kyle n'approuverait pas l'observation de la init()fonction dans l'objet Point3D. ;-)

Bholben
la source
En regardant en arrière, je pense maintenant qu'en combinant Object.assign()avec Object.create(), nous pouvons grandement simplifier la link()fonction ci-dessus. A sa place, nous pourrions utiliser: function create(delegate, props) { return Object.assign(Object.create(delegate), props); }. Ou mieux encore, nous pouvons utiliser ou Souligné Lodash pour le rendre vraiment concis: _.create(delegate, props).
bholben
-1

Y a-t-il un moyen d'OLOO plus de "deux" objets .. tous les exemples que je consiste en l'exemple basé (voir l'exemple d'OP). Disons que nous avons les objets suivants, comment pouvons-nous créer un "quatrième" objet qui a les attributs des trois "autres"? ala ...

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

var Shoe = {
     speed: 100
}

var Bike = {
     range: '4 miles'
}

ces objets sont arbitraires et pourraient englober toutes sortes de comportements. Mais l'essentiel est que nous avons un nombre "n" d'objets, et notre nouvel objet a besoin de quelque chose des trois.

au lieu des exemples donnés ala:

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

MAIS, notre newObject = (Button, Bike, Shoe) ......

Quel est le modèle pour y parvenir dans OLOO?

James Emanon
la source
1
Cela ressemble à «privilégier la composition à l'héritage» - une excellente stratégie. Dans ES6, vous pouvez utiliser Object.assign()- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Si vous écrivez dans ES5, vous pouvez utiliser Underscore _.extend()ou Lodash _.assign(). Voici une excellente vidéo pour expliquer ... youtu.be/wfMtDGfHWpA . Si vous avez des propriétés en conflit, la dernière l'emporte - l'ordre est donc important.
bholben