2009-03-26 19 views
126

Con una matriz de JavaScript, puedo restablecer a un estado vacío con una sola asignación:¿Cómo borrar rápidamente un objeto de JavaScript?

array.length = 0; 

Esto hace que la matriz "parecen" vacíos y listos para volver a utilizar, y por lo que yo entiendo es una sola " operación "- es decir, tiempo constante.

¿Hay alguna manera similar de borrar un objeto JS? Sé que puedo iterar sus campos eliminándolos:

for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } } 

pero esto tiene una complejidad lineal.

que puede también acaba de lanzar el objeto de distancia y crear una nueva:

obj = {}; 

Pero "promiscua" creación de nuevos objetos conduce a problemas con la recolección de elementos en IE6. (As described here)

+2

"array.length == 0 ... es una sola 'operación' - es decir, tiempo constante" - Lo dudo. – Miles

+1

No creo que borre ninguno de los contenidos, simplemente hace que cosas como push() funcionen como si la matriz estuviera vacía. ¿Tiene alguna referencia de que lo opuesto sea cierto? – levik

+2

@derobert: Eso es un poco presuntuoso. El problema de la Colección de basura IE6 está bien documentado. – levik

Respuesta

40

La respuesta corta a su pregunta, creo, es no (puede crear un objeto nuevo).

  1. En este ejemplo, creo que establecer la longitud en 0 aún deja todos los elementos para la recolección de basura.

  2. Puede agregar esto a Object.prototype si es algo que usaría con frecuencia. Sí, es lineal en complejidad, pero cualquier cosa que no haga la recolección de basura más tarde será.

  3. Esta es la mejor solución. Sé que no está relacionado con su pregunta, pero ¿por cuánto tiempo tenemos que seguir dando soporte a IE6? Hay muchas campañas para descontinuar su uso.

No dude en corregirme si hay algo incorrecto arriba.

+4

Algunas empresas tienen que admite IE6 como una cuestión de política, y lo hará mientras tenga una cuota de mercado de dos dígitos. El problema de IE GC no es que las cosas no se recojan, es que la colección ejecuta cada asignación de X, y lleva más tiempo cada vez. Por lo tanto, la necesidad de reutilizar objetos. – levik

+0

Sí, hay muchos casos en que todavía se usa debido a la política de la compañía/etc. Estaba fuera del tema ranking por despecho :) Entonces, ¿cómo eliminar obj.prop; realizar cuando la propiedad es en sí misma un objeto? No sé si ganas mucha eficiencia allí. – jthompson

+2

pobre GC significa que IE6 funcionará más despacio, lo que significa que hay aún más incentivo para actualizar. Aún lo estás apoyando, es solo que funcionará lento. – nickf

5

Así que para recapitular su pregunta: desea evitar, en la medida de lo posible, problemas con el error IE6 GC. Ese error tiene dos causas:

  1. Recolección de basura se produce una vez cada tantos asignaciones; por lo tanto, cuantas más asignaciones hagas, más se ejecutará el GC;
  2. Cuantos más objetos tenga 'en el aire', más tiempo tardará cada ejecución de recolección de basura (ya que recorrerá toda la lista de objetos para ver cuáles están marcados como basura).

La solución para causar 1 parece ser: mantener el número de asignaciones hacia abajo; asignar nuevos objetos y cadenas lo menos posible.

Parece que la solución para causar 2 es: mantener baja la cantidad de objetos "activos"; borre sus cadenas y objetos tan pronto como ya no los necesite y créelos de nuevo cuando sea necesario.

Hasta cierto punto, estas soluciones son contradictorias: mantener el número de objetos en la memoria bajo implicará más asignaciones y desasignaciones. Por el contrario, reutilizar constantemente los mismos objetos podría significar tener más objetos en la memoria de lo estrictamente necesario.


Ahora para su pregunta. Ya sea que restablezca un objeto creando uno nuevo o eliminando todas sus propiedades: eso dependerá de lo que quiera hacer con él más adelante.

es probable que desee asignar nuevas propiedades a la misma:

  • Si lo hace inmediatamente, entonces sugiero que la asignación de las nuevas propiedades de inmediato, y vaya borrando o limpiando primero. (¡Sin embargo, asegúrese de que todas las propiedades se sobrescriben o borren!)
  • Si el objeto no se usará inmediatamente, pero se volverá a llenar en una etapa posterior, le sugiero que lo elimine o lo asigne nulo, y crea uno nuevo más tarde.

No hay una forma rápida y fácil de usar para borrar un objeto JScript para su reutilización como si se tratara de un objeto nuevo, sin crear uno nuevo. Lo que significa que la respuesta corta a su pregunta es 'No', como dice jthompson.

82

Bueno, a riesgo de hacer las cosas demasiado fáciles ...

for (var member in myObject) delete myObject[member]; 

... parece ser muy eficaz en la limpieza del objeto en una línea de código con un mínimo de soportes de miedo. Todos los miembros serán verdaderamente eliminados en lugar de ser dejados como basura.

Obviamente, si desea eliminar el objeto en sí, igual tendrá que hacer una eliminación por separado() para eso.

+0

La eliminación solo rompe la referencia, p. hace que myObject [member] evalúe como undefined, y técnicamente deja el objeto como basura a menos que exista otra referencia al objeto. –

+0

Esta respuesta es muy responsable. Si se aplica a todos los objetos gestionados en una fase de eliminación, generalmente se ocupará de muchas de las cadenas de objetos accidentales. rock on Wytze – deepelement

+1

El OP sugiere usar 'hasOwnProperty' en este ciclo. He leído los documentos, pero todavía estoy tratando de entender qué riesgos existen, si los hay, si omitimos la comprobación 'hasOwnProperty()'? – logidelic

0

Puede eliminar los puntales, pero no eliminar variables. delete abc; no es válido en ES5 (y tira con uso estricto).

Puede asignarlo a null para configurarlo para su eliminación al GC (no lo hará si tiene otras referencias a las propiedades)

Configuración length propiedad sobre un objeto no cambia nada. (solo, bueno, establece la propiedad)

+0

Para ser claros, al establecer 'length' en 0 en una matriz (que es un tipo específico de objeto; si no me cree, intente ejecutar' typeof [] '), no solo establecerá la propiedad, de hecho, limpiará el contenido de la matriz. Consulte http://stackoverflow.com/questions/1232040/how-do-i-empty-an-array-in-javascript#comment7533900_1234337 –

3

Algo nuevo para pensar en Object.observe en ES7 y con el enlace de datos en general. Considere:

var foo={ 
    name: "hello" 
}; 

Object.observe(foo, function(){alert('modified');}); // bind to foo 

foo={}; // You are no longer bound to foo but to an orphaned version of it 
foo.name="there"; // This change will be missed by Object.observe() 

Por lo tanto, bajo esa circunstancia, # 2 puede ser la mejor opción.

+0

Si usa frameworks como AngularJS que pueden vincular objetos a vistas (enlace de una o dos vías) , el borrado de objetos con 'obj = {}' hará que framework desconozca cualquier cambio adicional al objeto, por lo tanto, sus plantillas no se renderizarán correctamente. La opción n. ° 2, sin embargo, funcionará correctamente. –

+0

Buen punto. Necesito mantener el mismo objeto Heap, y esto demuestra otra razón por la que querría mantener la misma referencia. – Cody

-3

Basta con hacer:

myObject = {}; 

Esto borrará objeto de la misma de valores.

+14

Esto romperá cualquier referencia al objeto. – weltschmerz

+10

Para aclarar el comentario de dchacke: \t 'myObject = {}' crea un nuevo objeto y deja el objeto original como está. Esto hace una diferencia cuando hay otras referencias al objeto original: 'var myObject = {a: 5, b: 4}; var otherRef = myObject; myObject = {}; 'Al final,' otherRef' sigue siendo '{a: 5, b4}' y ** no ** '{}' como cabría esperar. – Ignitor

3

Puede intentar esto. La función a continuación establece todos los valores de las propiedades del objeto en indefinido. Funciona también con objetos anidados.

var clearObjectValues = (objToClear) => { 
    Object.keys(objToClear).forEach((param) => { 
     if ((objToClear[param]).toString() === "[object Object]") { 
      clearObjectValues(objToClear[param]); 
     } else { 
      objToClear[param] = undefined; 
     } 
    }) 
    return objToClear; 
}; 
14

ES5

ES5 solución puede ser:

// for enumerable properties 
Object.keys(obj).forEach(function (prop) { 
    delete obj[prop]; 
}); 

// for all properties 
Object.getOwnPropertyNames(obj).forEach(function (prop) { 
    delete obj[prop]; 
}); 

ES6

Y ES6 solución puede ser:

// for enumerable properties 
for (const prop of Object.keys(obj)) { 
    delete obj[prop]; 
} 

// for all properties 
for (const prop of Object.getOwnPropertyNames(obj)) { 
    delete obj[prop]; 
} 

Rendimiento

Independientemente de las especificaciones, las soluciones más rápidas por lo general serán:

// for enumerable properties 
var props = Object.keys(obj); 
for (var i = 0; i < props.length; i++) { 
    delete obj[props[i]]; 
} 

// for all properties of an object with proto chain 
var props = Object.getOwnPropertyNames(obj); 
for (var i = 0; i < props.length; i++) { 
    delete obj[props[i]]; 
} 

// for all properties of shallow/plain object 
for (var key in obj) { 
    // this check can be safely omitted in modern JS engines 
    // if (obj.hasOwnProperty(key)) 
    delete obj[key]; 
} 

La razón por la for..in se debe realizar solamente en el objeto superficial o llana es que atraviesa las propiedades que se prototípica heredan, no sólo a las propiedades propias eso puede ser eliminado Si no se sabe con certeza si un objeto es simple, for con Object.getOwnPropertyNames es una mejor opción.

Cuestiones relacionadas