2011-11-22 17 views
9

que consigo un resultado inesperado con el siguiente código:Javascript propiedad prototipo no funciona como se esperaba con los campos de objeto y matriz

var TestModel, u, u2; 

function TestModel() {} 
TestModel.prototype.a = null; 
TestModel.prototype.b = []; 

u = new TestModel(); 
u.a = 1; 
u.b.push(1); 

u2 = new TestModel(); 
u2.a = 2; 
u2.b.push(2); 

console.log(u.a, u.b);  // outputs: 1 [1,2] 
console.log(u2.a, u2.b); // outputs: 2 [1,2] 

Me resulta sorprendente que u.b y u2.b contienen los mismos valores a pesar de que cada instancia de TestModel debería tener sus propias variables de instancia según cómo configuré el prototipo. Así que esta es la salida que estaba esperando:

console.log(u.a, u.b);  // expecting: 1 [1] 
console.log(u2.a, u2.b); // expecting: 2 [2] 

Lo mismo sucede si fijo b ser un objeto y establecer claves en él en lugar de utilizarlo como una matriz. ¿Qué no estoy entendiendo aquí?

Respuesta

1

La matriz es en ambos casos la misma matriz, es decir, la que configura para el prototipo. Esto significa que ambos .push llamadas están actuando en esa matriz, de manera que todos estos son [1, 2]:

TestModel.prototype.b 
u.b 
u2.b 

Todos ellos se refieren a la misma propiedad.

El prototipo se usa generalmente para funciones, de modo que todas las instancias comparten esas mismas funciones. Si va a modifique las propiedades del prototipo, entonces también se reflejarán para todas las instancias, lo que en este caso probablemente sea indeseable. Si las instancias deben tener una matriz personalizada, entonces también declare una personalizada para cada instancia en lugar de a través de un prototipo.

13

Hay una diferencia entre la asignación de valores y referencia a ellos.

u.a = 1; 

va a crear un nuevo a propiedad en el objeto referido por u. Antes de la asignación, u.a se referirá a TestModel.prototype.a, pero la asignación de un nuevo valor realmente crea una nueva propiedad en el objeto real:

enter image description here

Después de la misión:

enter image description here

Por otro mano,

u.b.push(1); 

no crear una nueva propiedad. Hará referencia a la propiedad existente, la matriz, que es TestModel.prototype.b.

a pesar de que cada instancia de TestModel debe tener sus propias variables de instancia de acuerdo a cómo he configurar el prototipo

Referencia Todos los casos el mismo prototipo, por lo tanto, hacen referencia a las mismas propiedades que el prototipo haya. Puede ver fácilmente eso porque TestMode.prototype === u.b, TestMode.prototype === u2.b y u.b === u2.b todos rinden true.

Funcionaría si asigna un nuevo valor, así que u.b y u2.b así:

u.b = []; 

que normalmente se hace en el constructor:

function TestModel() { 
    this.b = []; 
} 
+0

Muchas gracias! No estaba al tanto de esa sutil diferencia. Básicamente, debería inicializar todas mis variables de "instancia" en mi constructor antes de manipularlas en otro lugar. – hiddentao

+0

@hiddentao: Exactamente. Está bien asignar tipos primitivos a las propiedades del prototipo, como valores predeterminados, pero los objetos y las matrices deben inicializarse en el constructor si son "por instancia". Normalmente sigo definiendo la propiedad en el prototipo, pero la inicializo con 'null' (como lo hizo con' TestModel.prototype.a'). –

+0

@Felix, ¿qué herramienta usaste para obtener ese buen cuadro de los valores en TestModel? –

3

propiedades del prototipo son exactamente lo opuesto de cada instancia que tiene sus propias variables, el punto del prototipo es que todas las instancias comparten automáticamente las mismas propiedades de prototipo, por lo que no es necesario redefinir las funciones para cada instancia.

desea que cada instancia de tener su propia serie como esta:

function TestModel() { 
this.a = null; 
this.b = []; 
} 
Cuestiones relacionadas