2009-12-01 17 views
33

he añadido un simple archivo de .js a mi página que tiene algunos bastante mundano-tarea común tipo de funciones añadidas a los Object y Array prototipos.Prototipo Objeto en Javascript rompe jQuery?

A través de ensayo y error, he descubierto que la adición de cualquier función para Object.prototype, sin importar su nombre o lo que hace provoca errores de Javascript en jQuery:

El culpable?

Object.prototype.foo = function() { 
    /*do nothing and break jQuery*/ 
}; 

El error que estoy recibiendo la línea 1056 de jquery-1.3.2.js, en el attr: {} la función de declaración:

/*Object doesn't support this property or method*/ 
name = name.replace(/-([a-z])/ig, function(all, letter) { 
      return letter.toUpperCase(); 
     }); 

Al parecer G.replace no está definido.

Si bien es evidente que hay algo que no estoy envolver mi cabeza alrededor de la creación de prototipos, estoy fracasando rotundamente a averiguar lo que es.

Para ser claro, no estoy buscando una solución, lo he manejado ... lo que estoy buscando es una respuesta a ¿Por qué?. ¿Por qué agregar una función a Object.prototype rompe este bit de código?

+3

Puede obtener un error más significativo si cambia al archivo jquery completo (no minificado). De esta forma, podrá ver con mayor claridad qué código está teniendo problemas. –

+0

es un error conocido: http://dev.jquery.com/ticket/2721 –

+0

@ El enlace de CrescentFresh está desactualizado. Actualización: https://bugs.jquery.com/ticket/2721 – WoodrowShigeru

Respuesta

19

Nunca se debe extender Object.prototype. Hace mucho más que romper jQuery; rompe por completo la función "objeto como hashtables" de Javascript. No lo hagas

Puede pedir John Resig, y él le dirá el same thing.

+19

Extender 'Object.prototype' está bien. La advertencia es usar 'hasOwnProperty' en los bucles' for..in'. Es compatible con todos los principales navegadores, incluido Safari desde 2.0. Es solo la pereza que jQuery no lo hace en sus loops 'for..in'. El impacto en el rendimiento es insignificante, y Resig lo sabe: http://osdir.com/ml/jquery-dev/2009-02/msg00543.html Solo mi opinión, sin embargo. –

+0

Cosas interesantes. Gracias. Me pregunto por qué rompe la cosa de "objetos como hashtables" ... hmmm. –

+3

@Crescent Es mucho más profundo que eso. Claro que puedes evitar el problema con 'for 'in' loops, pero tener object-as-hashtables en Javascript hace muchas otras cosas. Por ejemplo, 'toString',' valueOf' y otros no están enumerados. Esto * does * tiene un impacto. Además, cuando eres el desarrollador principal de una biblioteca utilizada por miles de personas, no puedes culpar a su decisión de la pereza. Creo que una mejor palabra sería cautelosa. –

-1

Dudo que la adición de una función para Object.prototype rompe directamente jQuery. Sólo asegúrese de que cada bucle for..in usted tiene en todo su sitio está envuelto en un cheque hasOwnProperty, puesto que ya has añadir la función a nivel mundial y el resultado de la iteración en que no es previsible:

Object.prototype.foo = function() {};  
var myObject = {m1: "one", m2: "two" }; 

for(var i in myObject) { if(myObject.hasOwnProperty(i)) { 
    // Do stuff... but not to Object.prototype.foo 
}} 
+0

Bueno, si comento la declaración Object.prototype.foo, todo funciona bien. Además, en el punto en que se está rompiendo, ni siquiera ha llegado a ninguno de mis códigos más allá de esa declaración foo. –

+1

¡Tiene razón, no rompe jQuery directamente, rompe Javascript! –

+0

Depende de cómo lo mires. Lo ideal es que puedas ampliar Object sin ningún problema, pero en realidad, sí, es una mala idea y rara vez hay una buena razón para ello. Crockford ve la enumeración de las funciones añadidas al prototipo como un "error en el lenguaje", por lo que la mejor práctica es estar a la defensiva y SIEMPRE agregar hasOwnProperty a for..in loops. Apesta, pero lo hago religiosamente;) – jshalvi

5

estoy de acuerdo, añadiendo algo a Object.prototype demandas precaución y debe ser evitado. Busque otras soluciones como:

Agregándola a Object y luego accediéndola con call o apply, según sea necesario. Por ejemplo:

Object.foo = function() { return this.whatever()} 

Luego llamada que sobre un objeto por:

Object.foo.call(Objname); // this invokes the function as though it were a 
          // method of Objname. That is, its like Objname.foo() 

Para la diversión, se puede añadir lo siguiente (sí, sé que es un poco peligroso ...):

Function.using = Function.call; // syntactic sugar 

Ahora puede escribir Object.foo.using(Objname) y se lee como una representación.

Pero, por regla general, evite alterar cualquiera de los grandes prototipos.

34

Si es simplemente un caso de desorden para ... en bucles, ¿no puedes usar Object.defineProperty para agregar tu fn sin que sea enumerable?

Así:

Object.defineProperty(Object.prototype, "foo", { 
    value: function() { 
     // do stuff 
    }, 
    enumerable : false 
}); 

parece funcionar para mí. ¿Esto todavía se consideraría mala forma?

+1

No sé ... Sería bueno saber si ** está ** en mal estado, pero esto está funcionando bien para mí. – DataHerder

+2

Podría, pero para ... los bucles fueron * diseñados * para enumerar las prototipos de extensiones. Así es como exploras la cadena de prototipos. No se rompe para ... en los bucles se rompe el código erróneo que ciegamente asume que los valores iterados siempre serán de cierto tipo, mientras que, como la cadena Object.prototype puede incluir funciones, el código entre llaves puede arrojar una excepción cuando solo esperan escalares y objetos. –

+0

Funciona sin definir enumerable: 'Object.defineProperty (Object.prototype," foo ", { value: function() {} });' –

0

Me golpeé la cabeza en torno a este problema, ya que deseaba poner en práctica la orientación "real" objeto en todos mis objetos, como este:

interface Object 
{ 
    GetType:() => string; 
    ToString:() => string; 
    GetHashcode:() => number; 
    Equals: (obj: any) => boolean; 
} 

Desde Object.prototype rompe jQuery, que por defecto en la solución antes mencionada para hacer uso de defineProperty pero eso no toma ningún argumento.

La buena noticia es que puede hackear defineProperty y aceptar los parámetros. Aquí está mi implementación:

Object.defineProperty(Object.prototype, "Equals", 
    { 
     value: function (obj: any) 
     { 
      return obj == null && this == null 
        ? true 
        : obj != null && this == null 
         ? false 
         : obj == null && this != null 
          ? false 
          : this.GetHashcode() == obj.GetHashcode(); 
     }, 
     enumerable: false 
    }); 

Esto funciona y no entra en conflicto con JQuery.

Cuestiones relacionadas