2009-06-04 21 views
32

Estaba trabajando en una aplicación asp.net habilitada para AJAX. que acaba de añadir algunos métodos para Array.prototype comoagregando funciones personalizadas en Array.prototype

Array.prototype.doSomething = function(){ 
    ... 
} 

Esta solución funcionó para mí, siendo posible la reutilización de código de forma 'bonita'.

Pero cuando lo he probado trabajando con toda la página, tuve problemas ... Teníamos algunos extensores de ajax personalizados, y comenzaron a comportarse como inesperados: algunos controles mostraban 'indefinido' en torno a su contenido o valor .

¿Cuál podría ser la causa de eso? ¿Me falta algo sobre modificar el prototipo de objetos estándar?

Nota: Estoy bastante seguro de que el error comienza cuando modifico el prototipo para Matriz. Debería ser solo compatible con IE.

Respuesta

33

La modificación de los prototipos de objetos integrados puede ser una mala idea en general, ya que siempre tiene el potencial de entrar en conflicto con otros códigos en la misma página.

En el caso del prototipo de objeto Array, es una idea especialmente mala, ya que tiene el potencial de interferir con cualquier código que itere sobre los miembros de cualquier matriz, por ejemplo con for .. in.

Para ilustrar con un ejemplo (tomado de here):

Array.prototype.foo = 1; 

// somewhere deep in other javascript code... 
var a = [1,2,3,4,5]; 
for (x in a){ 
    // Now foo is a part of EVERY array and 
    // will show up here as a value of 'x' 
} 

Sería mejor para que usted pueda crear su propio tipo de constructor de objetos completa con la función doSomething, en lugar de extender la matriz incorporada.

+6

Creo que el constructo "for (x in y)" es para iterar sobre los miembros de un objeto. Para la iteración indexada de una matriz, no creo que sea adecuada. Sin embargo, su punto de interferir con otro código en la página es válido, especialmente si las bibliotecas de terceros están utilizando for-in de esta manera. – harto

+5

Sí, lo inverso es cierto; debe evitar for..in en caso de que n00b haya modificado el prototipo de Array, y debe evitar modificar el prototipo de Array en caso de que algún n00b se haya utilizado para ... in en una matriz. ;) – thomasrutter

+32

la _right_ respuesta en estos días es usar 'Object.defineProperty (Array.prototype, 'method', ...)' que hará que el nuevo método _non-enumerable_. – Alnitak

1

En general, jugar con los objetos javascript del núcleo es una mala idea. Nunca se sabe lo que las bibliotecas de terceros pueden esperar y cambiar los objetos centrales en javascript los cambia para todo.

Si usa Prototype, es especialmente malo porque el prototipo también se mezcla con el alcance global y es difícil saber si va a colisionar o no. En realidad, modificar las partes centrales de cualquier idioma suele ser una mala idea, incluso en javascript.

(Lisp podría ser la pequeña excepción allí)

1

Usted aumentada tipos genéricos por así decirlo. Probablemente haya sobrescrito la funcionalidad de otra lib y por eso dejó de funcionar.

Supongamos que alguna lib está utilizando extends Array con la función Array.remove(). Después de cargar lib, también agrega remove() al prototipo de Array pero con su propia funcionalidad. Cuando lib invoque su función, probablemente funcionará de forma diferente a lo esperado y romperá su ejecución ... Eso es lo que está sucediendo aquí.

8

¡Hay una advertencia! Tal vez usted hizo eso: fiddle demo

digamos una matriz y un método foo que devuelven primer elemento:

var myArray = ["apple","ball","cat"]; 

foo(myArray) // <- 'apple' 

function foo(array){ 
    return array[0] 
} 

lo anterior es aceptable porque las funciones son elevadas a la parte superior durante el tiempo de interpretación.

embargo, esto no funciona: (Debido a que el prototipo no se definned)

myArray.foo() // <- 'undefined function foo' 

Array.prototype.foo = function(){ 
    return this[0] 
} 

Para que esto funcione, basta con definir prototipos en la parte superior:

Array.prototype.foo = function(){ 
    return this[0] 
} 

myArray.foo() // <- 'apple' 

Y sí! ¡Puedes anular prototipos! Está permitido. Incluso puede definir su propio método add para matrices.

25

Mientras que el potencial para chocar con otros fragmentos de código o' la anulación de una función en un prototipo sigue siendo un riesgo, si usted quiere hacer esto con las versiones modernas de JavaScript, puede utilizar el método Object.defineProperty, apagando el bit enumerable, por ejemplo

// functional sort 
Object.defineProperty(Array.prototype, 'sortf', { 
    enumerable: false, 
    value: function(compare) { return [].concat(this).sort(compare); } 
}); 
+1

No es necesario indicar 'enumerable: false' ya que' false' es el valor predeterminado de 'enumerable'. – Noitidart

Cuestiones relacionadas