recorrer objetos objeto new lista ejemplos crear array javascript function-prototypes

objetos - ¿Cómo establecer el prototipo de un objeto JavaScript que ya ha sido instanciado?



prototype javascript ejemplos (11)

Supongamos que tengo un objeto foo en mi código JavaScript. foo es un objeto complejo y se genera en otro lugar. ¿Cómo puedo cambiar el prototipo del objeto foo ?

Mi motivación es establecer prototipos apropiados para objetos serializados de literales .NET a JavaScript.

Supongamos que he escrito el siguiente código JavaScript dentro de una página ASP.NET.

var foo = <%=MyData %>;

Supongamos que MyData es el resultado de invocar .NET JavaScriptSerializer en un objeto Dictionary<string,string> .

En tiempo de ejecución, esto se convierte en lo siguiente:

var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}];

Como puede ver, foo convierte en una matriz de objetos. Me gustaría poder inicializar foo con un prototipo apropiado. No quiero modificar Object.prototype ni Array.prototype . ¿Cómo puedo hacer esto?



No hay forma de realmente heredar de Array o "subclase".

Lo que puede hacer es esto ( ADVERTENCIA: ADMINISTRAR EL CÓDIGO POR ADELANTADO ):

function Foo(arr){ [].push.apply(this, arr) } Foo.prototype = [] Foo.prototype.something = 123 var foo = new Foo(<%=MyData %>) foo.length // => 2 foo[0] // => {"A":"1","B":"2"} foo.something // => 123

Esto funciona, pero causará ciertos problemas para cualquiera que cruce su camino (parece una matriz, pero las cosas saldrán mal si intenta manipularlo).

¿Por qué no recorre la ruta correcta y agrega métodos / propiedades directamente a foo , o utiliza un constructor y guarda su matriz como una propiedad?

function Foo(arr){ this.items = arr } Foo.prototype = { someMethod : function(){ ... } //... } var foo = new Foo(<%=MyData %>) foo.items // => [{"A":"1","B":"2"},{"X":"7","Y":"8"}]


No puede cambiar el prototipo de un objeto JavaScript que ya se ha instanciado de forma cruzada. Como otros han mencionado, sus opciones incluyen:

  1. cambiando la propiedad __proto__ no estándar / cross browser
  2. Copie las propiedades de Objetos a un nuevo objeto

Ninguno de los dos es particularmente bueno, especialmente si tienes que recorrer recursivamente un objeto en objetos internos para cambiar efectivamente un prototipo completo de elementos.

Solución alternativa a la pregunta

Voy a echar un vistazo más abstracto a la funcionalidad que parece que deseas.

Básicamente, los prototipos / métodos solo permiten una forma de agrupar funciones basadas en un objeto.
En lugar de escribir

function trim(x){ /* implementation */ } trim('' test '');

usted escribe

'' test ''.trim();

La sintaxis anterior se acuñó con el término OOP debido a la sintaxis object.method (). Algunas de las principales ventajas de OOPs sobre la programación funcional tradicional incluyen:

  1. Nombres cortos de métodos y menos variables obj.replace(''needle'',''replaced'') versus tener que recordar nombres como str_replace ( ''foo'' , ''bar'' , ''subject'') y la ubicación de las diferentes variables
  2. método de encadenamiento ( string.trim().split().join() ) es una función potencialmente más fácil de modificar y escribir y luego join(split(trim(string)) funciones join(split(trim(string))

Desafortunadamente en JavaScript (como se muestra arriba) no se puede modificar un prototipo ya existente. De forma ideal, podría modificar Object.prototype solo para el Objeto dado anterior, pero desafortunadamente la modificación de Object.prototype potencialmente rompería las secuencias de comandos (lo que Object.prototype colisión de propiedad y anulación).

No existe un término medio comúnmente utilizado entre estos 2 estilos de programación y ninguna forma de OOP para organizar funciones personalizadas.

UnlimitJS proporciona un término medio que le permite definir métodos personalizados. Evita:

  1. Choque de propiedad, porque no extiende prototipos de Objetos
  2. Todavía permite una sintaxis de encadenamiento OOP
  3. Se trata de un script de navegador cruzado de 450 bytes (IE6 +, Firefox 3.0 +, Chrome, Opera, Safari 3.0+) que muestra la gran cantidad de problemas de colisión de propiedad de JavaScript de Unlimit

Usando su código anterior, simplemente crearía un espacio de nombres de las funciones que pretende llamar en contra del objeto.

Aquí hay un ejemplo:

var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}]; // define namespace with methods var $ = { log:function(){ console.log(this); return this; }[Unlimit](), alert:function(){ alert(''''+this); }[Unlimit]() } foo[$.log]() [$.log]() [$.alert]();

Puedes leer más de los ejemplos aquí UnlimitJS . Básicamente, al invocar [Unlimit]() en una función, permite llamar a la función como método en un objeto. Es como un término medio entre el OOP y las carreteras funcionales.


No se puede cambiar la referencia [[prototype]] de los objetos ya construidos, hasta donde yo sé. Podría alterar la propiedad del prototipo de la función constructora original pero, como ya ha comentado, ese constructor es un Object , y la alteración de las construcciones del núcleo JS es una cosa mala.

Sin embargo, podría crear un objeto proxy del objeto construido que implemente la funcionalidad adicional que necesita. También puede poner en parche los métodos y comportamientos adicionales asignando directamente al objeto en cuestión.

Quizás puedas obtener lo que quieres de otra manera, si estás dispuesto a acercarte desde un ángulo diferente: ¿Qué necesitas hacer que involucre jugar con el prototipo?


Puede definir su función de constructor proxy y luego crear una nueva instancia y copiar todas las propiedades desde el objeto original a ella.

// your original object var obj = { ''foo'': true }; // your constructor - "the new prototype" function Custom(obj) { for ( prop in obj ) { if ( obj.hasOwnProperty(prop) ) { this[prop] = obj[prop]; } } } // the properties of the new prototype Custom.prototype.bar = true; // pass your original object into the constructor var obj2 = new Custom(obj); // the constructor instance contains all properties from the original // object and also all properties inherited by the new prototype obj2.foo; // true obj2.bar; // true

Demostración en vivo: http://jsfiddle.net/6Xq3P/

El constructor Custom representa el nuevo prototipo, ergo, su objeto Custom.prototype contiene todas las nuevas propiedades que le gustaría usar con su objeto original.

Dentro del constructor Custom , solo copia todas las propiedades desde el objeto original al nuevo objeto instancia.

Este nuevo objeto de instancia contiene todas las propiedades del objeto original (se copiaron dentro del constructor) y también todas las nuevas propiedades definidas dentro de Custom.prototype (porque el nuevo objeto es una instancia Custom ).



Puede usar constructor en una instancia de un objeto para alterar el prototipo de un objeto in situ. Creo que esto es lo que estás pidiendo que hagas.

Esto significa que si tienes foo que es una instancia de Foo :

function Foo() {} var foo = new Foo();

Puede agregar una bar propiedades a todas las instancias de Foo haciendo lo siguiente:

foo.constructor.prototype.bar = "bar";

Aquí hay un violín que muestra la prueba de concepto: http://jsfiddle.net/C2cpw/ . No estoy muy seguro de cómo les va a pasar a los navegadores más antiguos usando este enfoque, pero estoy bastante seguro de que esto debería hacer el trabajo bastante bien.

Si su intención es mezclar funcionalidad en objetos, este fragmento debería hacer el trabajo:

function mix() { var mixins = arguments, i = 0, len = mixins.length; return { into: function (target) { var mixin, key; if (target == null) { throw new TypeError("Cannot mix into null or undefined values."); } for (; i < len; i += 1) { mixin = mixins[i]; for (key in mixin) { target[key] = mixin[key]; } // Take care of IE clobbering `toString` and `valueOf` if (mixin && mixin.toString !== Object.prototype.toString) { target.toString = mixin.toString; } else if (mixin && mixin.valueOf !== Object.prototype.valueOf) { target.valueOf = mixin.valueOf; } } return target; } }; };


Si conoce el prototipo, ¿por qué no inyectarlo en el código?

var foo = new MyPrototype(<%= MyData %>);

Entonces, una vez que los datos son serializados, obtienes

var foo = new MyPrototype([{"A":"1","B":"2"},{"X":"7","Y":"8"}]);

ahora solo necesitas un constructor que tome una matriz como argumento.


si quieres crear un prototipo sobre la marcha, este es uno de los caminos

function OntheFlyProto (info){ this.items = info; this.y =-1; for(var i = 0; i < this.items.length ; i++){ OntheFlyProto.prototype["get"+this.items[i].name] = function (){ this.y++; return this.items[this.y].value; } } } var foo = [{name:"one", value:1},{name:"two", value:2}]; v = new OntheFlyProto(foo);


EDITAR Feb. 2012: la respuesta a continuación ya no es precisa. __proto__ se está agregando a ECMAScript 6 como "normativo opcional", lo que significa que no es necesario implementarlo, pero si lo es, debe seguir el conjunto de reglas dado. Esto no está resuelto actualmente, pero al menos será oficialmente parte de la especificación de JavaScript.

Esta pregunta es mucho más complicada de lo que parece en la superficie, y más allá del grado de pago de la mayoría de las personas en lo que respecta al conocimiento de las partes internas de Javascript.

La propiedad prototype de un objeto se usa al crear nuevos objetos secundarios de ese objeto. Cambiarlo no se refleja en el objeto en sí, sino que se refleja cuando ese objetado se utiliza como un constructor para otros objetos, y no sirve para cambiar el prototipo de un objeto existente.

function myFactory(){}; myFactory.prototype = someOtherObject; var newChild = new myFactory; newChild.__proto__ === myFactory.prototype === someOtherObject; //true

Los objetos tienen una propiedad interna [[prototipo]] que apunta al prototipo actual. La forma en que funciona es siempre que se llame a una propiedad de un objeto, se iniciará en el objeto y luego irá por la cadena [[prototipo]] hasta que encuentre una coincidencia, o fallará después del prototipo raíz del Objeto. Así es como Javascript permite construir y modificar objetos en tiempo de ejecución; tiene un plan para buscar lo que necesita.

La propiedad __proto__ existe en algunas implementaciones (mucho ahora): cualquier implementación de Mozilla, todas las webkit que conozco, algunas otras. Esta propiedad apunta a la propiedad interna [[prototipo]] y permite la modificación posterior a la creación en los objetos. Cualquier propiedad y función cambiará instantáneamente para que coincida con el prototipo debido a esta búsqueda encadenada.

Esta característica, aunque está estandarizada ahora, todavía no es una parte requerida de JavaScript, y en los idiomas que la soportan tiene una alta probabilidad de derribar su código en la categoría "no optimizada". Los motores JS deben hacer todo lo posible para clasificar el código, especialmente el código " __proto__ " al que se accede con mucha frecuencia, y si está haciendo algo como modificar __proto__ no optimizarán su código.

Esta publicación https://bugzilla.mozilla.org/show_bug.cgi?id=607863 trata específicamente las implementaciones actuales de __proto__ y las diferencias entre ellas. Cada implementación lo hace diferente, porque es un problema difícil de resolver. Todo en Javascript es mutable excepto a.) La sintaxis b.) Objetos de host (el DOM existe fuera de Javascript técnicamente) y c.) __proto__ . El resto está completamente en manos de usted y de cualquier otro desarrollador, por lo que puede ver por qué __proto__ sobresale como un pulgar dolorido.

Hay una cosa que __proto__ permite que sea imposible de hacer: la designación de un prototipo de objetos en tiempo de ejecución separado de su constructor. Este es un caso de uso importante y es una de las razones principales por las que __proto__ no está muerto. Es lo suficientemente importante que ha sido un punto de discusión serio en la formulación de Harmony, o que pronto se conocerá como ECMAScript 6. La capacidad de especificar el prototipo de un objeto durante la creación será una parte de la próxima versión de Javascript y será la campana que indica los días de __proto__ está formalmente numerada.

En el corto plazo, puedes usar __proto__ si estás apuntando a navegadores que lo soporten (no IE, y ningún IE lo hará). Es probable que funcione en webkit y moz durante los próximos 10 años, ya que ES6 no se finalizará hasta 2013.

Brendan Eich - re: Enfoque de nuevos métodos de Objeto en ES5 :

Lo sentimos, pero el __proto__ configurable, aparte del caso de uso del inicializador de objetos (es decir, en un objeto nuevo aún no accesible, análogo al Object.create de ES5), es una idea terrible. Escribo esto habiendo diseñado e implementado __proto__ configurable __proto__ más de 12 años.

... la falta de estratificación es un problema (considere los datos JSON con la clave "__proto__" ). Y lo que es peor, la mutabilidad significa que las implementaciones deben verificar las cadenas de prototipos cíclicos para evitar el ilooping. [se requieren controles constantes para la recursión infinita]

Finalmente, mutar __proto__ en un objeto existente puede romper métodos no genéricos en el nuevo objeto prototipo, que posiblemente no pueda funcionar en el objeto receptor (directo) cuyo __proto__ se está configurando. Esto es simplemente una mala práctica, una forma de confusión de tipo intencional, en general.


foo.prototype.myFunction = function(){alert("me");}