¿El "patrón OLOO (objetos enlazados con otros objetos)" de Kyle Simpson se diferencia de alguna manera del patrón de diseño del prototipo? Aparte de acuñarlo con algo que indique específicamente "vinculación" (el comportamiento de los prototipos) y aclarar que no hay nada de "copiar" sucediendo aquí (un comportamiento de clases), ¿qué introduce exactamente su patrón?
Aquí hay un ejemplo del patrón de Kyle de su libro, "No conoces JS: esto y prototipos de objetos":
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
fuente
fuente

Respuestas:
OLOO adopta la cadena de prototipos tal como está, sin necesidad de aplicar otras semánticas (confusas en mi opinión) para obtener el enlace.
Entonces, estos dos fragmentos tienen el mismo resultado EXACTO, pero llegan de manera diferente.
Forma de constructor:
Formulario OLOO:
En ambos fragmentos, un
xobjeto es[[Prototype]]vinculado a un objeto (Bar.prototypeoBarObj), que a su vez está vinculado al tercer objeto (Foo.prototypeoFooObj).Las relaciones y la delegación son idénticas entre los fragmentos. El uso de memoria es idéntico entre los fragmentos. La capacidad de crear muchos "niños" (también conocidos como muchos objetos como
x1throughx1000, etc.) es idéntica entre los fragmentos. La actuación de la delegación (x.yyx.z) es idéntico entre los fragmentos. El rendimiento de creación de objetos es más lento con OLOO, pero la comprobación de la cordura que revela que el rendimiento más lento no es realmente un problema.Lo que sostengo que ofrece OLOO es que es mucho más simple simplemente expresar los objetos y vincularlos directamente, que vincularlos indirectamente a través del constructor /
newmecanismos. Este último pretende ser sobre clases, pero en realidad es una sintaxis terrible para expresar delegación ( nota al margen: ¡también lo es laclasssintaxis de ES6 !).OLOO simplemente está eliminando al intermediario.
Aquí hay otra comparación de
classvs OLOO.fuente
Object.create(...)es muchas veces más lento quenew. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/…Leí el libro de Kyle y lo encontré realmente informativo, particularmente los detalles sobre cómo
thisestá encuadernado.Pros:
Para mí, hay un par de grandes ventajas de OLOO:
1. Sencillez
OLOO confía en
Object.create()crear un nuevo objeto que está[[prototype]]vinculado a otro objeto. No es necesario que comprenda que las funciones tienen unprototypepropiedad o preocuparse por cualquiera de los posibles errores relacionados que surgen de su modificación.2. Sintaxis más limpia
Esto es discutible, pero creo que la sintaxis de OLOO es (en muchos casos) más ordenada y concisa que el enfoque javascript 'estándar', particularmente cuando se trata de polimorfismo (
superllamadas de estilo).Contras:
Creo que hay un poco de diseño cuestionable (uno que en realidad contribuye al punto 2 anterior), y eso tiene que ver con el sombreado:
La idea detrás de esto es que los objetos tienen sus propias funciones más específicas que luego delegan internamente a funciones más abajo en la cadena. Por ejemplo, puede tener un
resourceobjeto con unasave()función en él que envía una versión JSON del objeto al servidor, pero también puede tener unclientResourceobjeto que tiene unstripAndSave()función, que primero elimina las propiedades que no deberían enviarse al servidor. .El problema potencial es: si alguien más llega y decide hacer un
specialResourceobjeto, sin estar completamente al tanto de toda la cadena del prototipo, podría razonablemente * decidir guardar una marca de tiempo para el último guardado bajo una propiedad llamadasave, que oculta lasave()funcionalidad base en elresourceobjeto dos eslabones hacia abajo en la cadena del prototipo:Este es un ejemplo particularmente elaborado, pero el punto es que específicamente no sombrear otras propiedades puede llevar a algunas situaciones incómodas y al uso intensivo de un diccionario de sinónimos.
Quizás una mejor ilustración de esto sería un
initmétodo, particularmente conmovedor ya que OOLO evita las funciones de tipo constructor. Dado que todos los objetos relacionados probablemente necesitarán dicha función, puede ser un ejercicio tedioso nombrarlos adecuadamente, y la singularidad puede hacer que sea difícil recordar cuál usar.* En realidad, no es particularmente razonable (
lastSavedsería mucho mejor, pero es solo un ejemplo).fuente
[[Prototype]]sistema en sí, no OLOO específicamente.b.timeStampedSave();lugar dea.timeStampedSave();en la última línea del fragmento de código.La discusión en "You Don't Know JS: this & Object Prototypes" y la presentación de OLOO es estimulante y he aprendido mucho leyendo el libro. Los méritos del patrón OLOO están bien descritos en las otras respuestas; sin embargo, tengo las siguientes quejas de mascotas (o me falta algo que me impide aplicarlo de manera efectiva):
1
Cuando una "clase" "hereda" otra "clase" en el patrón clásico, las dos funciones pueden declararse con sintaxis similar ( "declaración de función" o "declaración de función" ):
Por el contrario, en el patrón OLOO, se utilizan diferentes formas sintácticas para definir la base y los objetos derivados:
Como puede ver en el ejemplo anterior, el objeto base se puede definir usando la notación literal de objeto, mientras que la misma notación no se puede usar para el objeto derivado. Esta asimetría me molesta.
2
En el patrón OLOO, la creación de un objeto consta de dos pasos:
Object.createLlame a algún método personalizado no estándar para inicializar el objeto (que debe recordar, ya que puede variar de un objeto a otro):
Por el contrario, en el patrón de prototipo, utiliza el operador estándar
new:3
En el patrón clásico, puedo crear funciones de utilidad "estáticas" que no se aplican directamente a un "instante" asignándolas directamente a la función de "clase" (a diferencia de su
.prototype). Por ejemplo, como funciónsquareen el siguiente código:Por el contrario, en el patrón OLOO todas las funciones "estáticas" están disponibles (a través de la cadena [[prototype]]) en las instancias del objeto también:
fuente
Como explica Kyle cuando dos objetos están
[[Prototype]]vinculados, en realidad no dependen el uno del otro; en cambio, son objeto individual. Está vinculando un objeto a otro con un[[Prototype]]vínculo que puede cambiar en cualquier momento que desee. Si toma dos[[Prototype]]objetos vinculados creados a través del estilo OLOO como dependientes entre sí, también debe pensar lo mismo sobre los creados a través deconstructorllamadas.Ahora piensa por un segundo, ¿piensas
foobarybazcomo dependientes el uno del otro?Ahora hagamos lo mismo con este
constructorcódigo de estilo.La única diferencia b / w este último y el código anterior es que en este último uno
foo,bar,bazbbjects están vinculados a cada-otra a través de objetos arbitrarios de suconstructorfunción (Foo.prototype,Bar.prototype,Baz.prototype), pero en el anterior (OLOOestilo) que están vinculados directamente. Ambas formas que sólo va a asociarfoo,bar,bazuno con el otro, situado en la anterior e indirectamente en el último. Pero, en ambos casos, los objetos son independientes entre sí porque no es realmente como una instancia de ninguna clase que, una vez instanciada, no se puede hacer heredar de alguna otra clase. Siempre puede cambiar qué objeto debe delegar un objeto también.Entonces todos son independientes entre sí.
Sí, eso es posible
Usemos
Techcomo un objeto de utilidadcree tantos objetos como desee vinculados
Tech-¿Cree que
html,css,jsobjetos están conectados entre sí-? No, no lo son. Ahora veamos cómo pudimos haber hecho eso con laconstructorfuncióncree tantos objetos como desee vinculados
Tech.proptotype-Algunas comprobaciones (evitando console.log) -
¿Cómo cree que estas
constructoral estilo de objetos (html,css,js) objetos difieren delOLOOcódigo de estilo? De hecho, tienen el mismo propósito. En elOLOOestilo uno los objetos delegan aTech(la delegación se estableció explícitamente) mientras que en elconstructorestilo uno los objetos delegan aTech.prototype(la delegación se estableció implícitamente). En última instancia, termina vinculando los tres objetos, sin ningún vínculo entre sí, con un objeto, usando directamenteOLOO-style, indirectamente usandoconstructor-style.No,
ObjBaquí no es como una instancia (en lenguajes de base clásica) de ninguna claseObjA. Debería decirse que elobjBobjeto se hace delegado aObjAobjeto en el momento de su creación " . Si hubiera usado el constructor, habría hecho el mismo 'acoplamiento', aunque indirectamente haciendo uso de.prototypes.fuente
@Marcus @bholben
Quizás podamos hacer algo como esto.
Por supuesto, crear un objeto Point3D que se vincule al prototipo de un objeto Point2D es un poco tonto, pero eso no viene al caso (quería ser coherente con su ejemplo). De todos modos, en lo que respecta a las quejas:
La asimetría se puede arreglar con Object.setPrototypeOf de ES6 o el más mal visto
__proto__ = ...que yo uso. También podemos usar super en objetos regulares ahora, como se ve enPoint3D.init(). Otra forma sería hacer algo comoaunque no me gusta particularmente la sintaxis.
Siempre podemos simplemente envolver
p = Object.create(Point)y luegop.init()en un constructor. ejPoint.create(x,y). Usando el código anterior podemos crear unaPoint3D"instancia" de la siguiente manera.Se me ocurrió este truco para emular métodos estáticos en OLOO. No estoy seguro de si me gusta o no. Requiere llamar a una propiedad especial en la parte superior de cualquier método "estático". Por ejemplo, hice que el
Point.create()método fuera estático.Alternativamente, con los símbolos ES6 puede extender de forma segura las clases base de Javascript. Así que podría guardarse algo de código y definir la propiedad especial en Object.prototype. Por ejemplo,
fuente
@james emanon - Entonces, te refieres a la herencia múltiple (discutida en la página 75 en el libro "No conoces JS: esto y prototipos de objetos"). Y ese mecanismo lo podemos encontrar en la función "extender" de subrayado, por ejemplo. Los nombres de los objetos que mencionaste en tu ejemplo son una mezcla de manzanas, naranjas y dulces, pero entiendo el punto detrás. Desde mi experiencia, esta sería la versión OOLO:
Es un ejemplo simple, pero el punto que se muestra es que solo estamos encadenando objetos en una estructura / formación bastante plana y todavía tenemos la posibilidad de usar métodos y propiedades de múltiples objetos. Logramos lo mismo que con el enfoque de clase / "copiar las propiedades". Resumido por Kyle (página 114, "esto y prototipos de objetos"):
Entiendo que la forma más natural para usted sería establecer todos los objetos "padre" (cuidado :)) en un lugar / llamada de función en lugar de modelar toda la cadena.
Lo que requiere es un cambio en el pensamiento y el modelado de problemas en nuestras aplicaciones de acuerdo con eso. También me estoy acostumbrando. Espero que ayude y el veredicto final del propio Kyle sería genial. :)
fuente
@Marcus, al igual que tú, me ha gustado OLOO y tampoco me gusta la asimetría descrita en tu primer punto. He estado jugando con una abstracción para recuperar la simetría. Puede crear una
link()función que se utilice en lugar deObject.create(). Cuando se usa, su código podría verse así ...Recuerde que
Object.create()tiene un segundo parámetro que se puede pasar. Aquí está la función de enlace que aprovecha el segundo parámetro. También permite un poco de configuración personalizada ...Por supuesto, creo que @Kyle no respaldaría el sombreado de la
init()función en el objeto Point3D. ;-)fuente
Object.assign()conObject.create(), podemos simplificar enormemente lalink()función anterior. En su lugar, se podría utilizar esto:function create(delegate, props) { return Object.assign(Object.create(delegate), props); }. O mejor aún, podemos usar subrayado o Lodash para que sea realmente concisa:_.create(delegate, props).¿Hay alguna manera de OLOO más de "dos" objetos ... todos los ejemplos consisten en el ejemplo basado (ver el ejemplo de OP). Digamos que tenemos los siguientes objetos, ¿cómo podemos crear un "cuarto" objeto que tenga los atributos de los "otros" tres? ala ...
estos objetos son arbitrarios y pueden abarcar todo tipo de comportamientos. Pero la esencia es que tenemos 'n' número de objetos, y nuestro nuevo objeto necesita algo de los tres.
en lugar de los ejemplos dados ala:
PERO, nuestro newObject = (Botón, Bicicleta, Zapato) ......
¿Cuál es el patrón para que esto funcione en OLOO?
fuente
Object.assign()- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Si escribe en ES5, puede utilizar Underscore's_.extend()o Lodash's_.assign(). Aquí hay un excelente video para explicar ... youtu.be/wfMtDGfHWpA . Si tiene propiedades en colisión, gana la última, por lo que el orden es importante.