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."
javascript
design-patterns
shmuli
la source
la source
Réponses:
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:
Formulaire OLOO:
Dans les deux extraits, un
x
objet est[[Prototype]]
lié à un objet (Bar.prototype
ouBarObj
), qui à son tour est lié au troisième objet (Foo.prototype
ouFooObj
).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
x1
throughx1000
, etc.) est identique entre les extraits. Les performances de la délégation (x.y
etx.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 /
new
mé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
class
vs OLOO.la source
Object.create(...)
est plusieurs fois plus lent quenew
. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructorJ'ai lu le livre de Kyle et je l'ai trouvé très instructif, en particulier le détail de la
this
reliure.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 uneprototype
proprié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 (
super
appels -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:
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
resource
objet avec unesave()
fonction qui envoie une version JSON de l'objet au serveur, mais vous pouvez également avoir unclientResource
objet qui a unestripAndSave()
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
specialResource
objet, 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éesave
, ce qui occulte lasave()
fonctionnalité de base sur l'resource
objet deux maillons dans la chaîne de prototypes: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
init
mé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
lastSaved
serait beaucoup mieux, mais ce n'est qu'un exemple.)la source
[[Prototype]]
système lui-même, pas d'OLOO en particulier.b.timeStampedSave();
au lieu dea.timeStampedSave();
sur la dernière ligne de l'extrait de code.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" ):
En revanche, dans le pattern OLOO, différentes formes syntaxiques permettent de définir la base et les objets dérivés:
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:
Object.create
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):
En revanche, dans le modèle Prototype, vous utilisez l'opérateur standard
new
: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 similairesquare
dans le code ci-dessous:En revanche, dans le modèle OLOO, toutes les fonctions "statiques" sont également disponibles (via la chaîne [[prototype]]) sur les instances d'objet:
la source
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 desconstructor
appels.Maintenant , pensez à un deuxième pensez - vous
foo
bar
etbaz
comme étant dépendants les uns des -autres?Maintenant, faisons la même chose avec ce
constructor
code de style-La seule différence b / w celui - ci et l'ancien code est que dans ce dernier une
foo
,bar
,baz
bbjects sont reliés entre-eux par des objets quelconques de leurconstructor
fonction (Foo.prototype
,Bar.prototype
,Baz.prototype
) , mais dans l'ex - one (OLOO
modèle) , ils sont directement liés. Les deux façons dont vous êtes juste reliantfoo
,bar
,baz
entre 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.Ils sont donc tous indépendants les uns des autres.
Oui c'est en effet possible-
Utilisons
Tech
comme un objet utilitaire-créer autant d'objets que vous souhaitez liés à
Tech
-Pensez - vous que
html
,css
, lesjs
objets sont reliés l'un à-autre? Non, ils ne le sont pas. Voyons maintenant comment nous aurions pu faire cela avec laconstructor
fonction-créer autant d'objets que vous souhaitez liés à
Tech.proptotype
-Quelques vérifications (en évitant console.log) -
Comment pensez-vous ces
constructor
objets -style (html
,css
,js
) Les objets diffèrent duOLOO
Code de style? En fait, ils servent le même objectif. DansOLOO
-style one objets délègue àTech
(la délégation a été définie explicitement) tandis que dansconstructor
-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 directementOLOO
-style, indirectement en utilisantconstructor
-style.Non,
ObjB
ce n'est pas comme une instance (dans les langages classiques) d'une classe quelconqueObjA
. On pourrait dire que l'objB
objet est rendu délégué à l'ObjA
objet au moment de sa création . " Si vous avez utilisé constructeur, vous auriez fait le même 'couplage', bien qu'indirectement en utilisant.prototype
s.la source
@Marcus @bholben
Peut-être pouvons-nous faire quelque chose comme ça.
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:
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 dansPoint3D.init()
. Une autre façon serait de faire quelque chose commebien que je n'aime pas particulièrement la syntaxe.
Nous pouvons toujours simplement envelopper
p = Object.create(Point)
et ensuitep.init()
dans un constructeur. par exemplePoint.create(x,y)
. En utilisant le code ci-dessus, nous pouvons créer unePoint3D
"instance" de la manière suivante.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.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,
la source
@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:
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"):
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. :)
la source
@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 deObject.create()
. Lorsqu'il est utilisé, votre code pourrait ressembler à ceci ...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 ...Bien sûr, je pense que @Kyle n'approuverait pas l'observation de la
init()
fonction dans l'objet Point3D. ;-)la source
Object.assign()
avecObject.create()
, nous pouvons grandement simplifier lalink()
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)
.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 ...
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:
MAIS, notre newObject = (Button, Bike, Shoe) ......
Quel est le modèle pour y parvenir dans OLOO?
la source
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.