objetos - prototype javascript ejemplos
¿Cómo obtener referencias de objetos javascript o recuento de referencias? (2)
Cómo obtener el recuento de referencia de un objeto
- ¿Es posible determinar si un objeto javascript tiene múltiples referencias a él?
- ¿O si tiene referencias además del con el que estoy accediendo ?
- ¿O incluso solo para obtener el recuento de referencia en sí?
- ¿Puedo encontrar esta información de javascript, o tendré que hacer un seguimiento de mis propios contadores de referencia.
Obviamente, debe haber al menos una referencia para que mi código acceda al objeto. Pero lo que quiero saber es si hay otras referencias a él, o si mi código es el único lugar al que se accede. Me gustaría poder eliminar el objeto si nada más está haciendo referencia a él.
Si conoce la respuesta, no hay necesidad de leer el resto de esta pregunta. A continuación hay solo un ejemplo para aclarar las cosas.
Caso de uso
En mi aplicación, tengo una instancia de objeto Repository
llamada contacts
que contiene una matriz de TODOS mis contactos. También hay varias instancias de objetos de Collection
, como la colección de friends
y una colección de coworkers
. Cada colección contiene una matriz con un conjunto diferente de elementos del Repository
contacts
.
Código de muestra
Para hacer que este concepto sea más concreto, considere el siguiente código. Cada instancia del objeto Repository
contiene una lista de todos los elementos de un tipo particular. Es posible que tenga un repositorio de Contactos y un repositorio de Eventos por separado. Para mantenerlo simple, puede obtener, agregar y eliminar elementos, y agregar muchos a través del constructor.
var Repository = function(items) {
this.items = items || [];
}
Repository.prototype.get = function(id) {
for (var i=0,len=this.items.length; i<len; i++) {
if (items[i].id === id) {
return this.items[i];
}
}
}
Repository.prototype.add = function(item) {
if (toString.call(item) === "[object Array]") {
this.items.concat(item);
}
else {
this.items.push(item);
}
}
Repository.prototype.remove = function(id) {
for (var i=0,len=this.items.length; i<len; i++) {
if (items[i].id === id) {
this.removeIndex(i);
}
}
}
Repository.prototype.removeIndex = function(index) {
if (items[index]) {
if (/* items[i] has more than 1 reference to it */) {
// Only remove item from repository if nothing else references it
this.items.splice(index,1);
return;
}
}
}
Tenga en cuenta la línea en remove
con el comentario. Solo quiero eliminar el elemento de mi repositorio principal de objetos si ningún otro objeto tiene una referencia al elemento. Aquí está la Collection
:
var Collection = function(repo,items) {
this.repo = repo;
this.items = items || [];
}
Collection.prototype.remove = function(id) {
for (var i=0,len=this.items.length; i<len; i++) {
if (items[i].id === id) {
// Remove object from this collection
this.items.splice(i,1);
// Tell repo to remove it (only if no other references to it)
repo.removeIndxe(i);
return;
}
}
}
Y luego este código usa Repository
y Collection
:
var contactRepo = new Repository([
{id: 1, name: "Joe"},
{id: 2, name: "Jane"},
{id: 3, name: "Tom"},
{id: 4, name: "Jack"},
{id: 5, name: "Sue"}
]);
var friends = new Collection(
contactRepo,
[
contactRepo.get(2),
contactRepo.get(4)
]
);
var coworkers = new Collection(
contactRepo,
[
contactRepo.get(1),
contactRepo.get(2),
contactRepo.get(5)
]
);
contactRepo.items; // contains item ids 1, 2, 3, 4, 5
friends.items; // contains item ids 2, 4
coworkers.items; // contains item ids 1, 2, 5
coworkers.remove(2);
contactRepo.items; // contains item ids 1, 2, 3, 4, 5
friends.items; // contains item ids 2, 4
coworkers.items; // contains item ids 1, 5
friends.remove(4);
contactRepo.items; // contains item ids 1, 2, 3, 5
friends.items; // contains item ids 2
coworkers.items; // contains item ids 1, 5
Observe cómo coworkers.remove(2)
no eliminó la identificación 2 de contactRepo? Esto se debe a que todavía se hace referencia a ellos desde friends.items
. Sin embargo, friends.remove(4)
hace que id 4 se elimine de contactRepo
, porque ninguna otra colección se está refiriendo a él.
Resumen
Lo anterior es lo que quiero hacer. Estoy seguro de que hay formas en que puedo hacer esto haciendo un seguimiento de mis propios contadores de referencia y demás. Pero si hay una forma de hacerlo utilizando la administración de referencias integrada de JavaScript, me gustaría saber cómo usarlo.
No no no no; y sí, si realmente necesita contar las referencias tendrá que hacerlo manualmente. JS no tiene interfaz para esto, GC o referencias débiles.
Si bien podría implementar una lista de objetos contados por referencia manual, es cuestionable si todos los gastos generales adicionales (en términos de rendimiento, pero más importante, la complejidad del código) valen la pena.
En su código de ejemplo, parecería más simple olvidar el Repository
, usar una Array
simple para sus listas y dejar que la recolección de basura estándar elimine a las personas que no se utilizan. Si necesitara obtener una lista de todas las personas en uso, simplemente concat
las listas de friends
y coworkers
(y las clasificaría / uniquificaría si fuera necesario).
Puede interesarle observar funciones de reducción y funciones de array.map. el mapa se puede usar para ayudar a identificar dónde se cruzan sus colecciones, o si hay una intersección en absoluto. Una función de reducción definida por el usuario podría usarse como una fusión (como anular el operador de suma para que pueda aplicar operación a objetos, o combinar todas las colecciones en "id" si así es como define su función de reducción - luego asigne el resultado a su matriz de referencia maestra, recomiendo mantener una matriz de sombras que contenga todos los objetos / valores raíz en caso de que desee REBOBINAR o algo así). Nota: uno debe tener cuidado con las cadenas de prototipos al reducir un objeto o matriz. La función de mapa será muy útil en este caso.
Sugeriría que no elimine el objeto o registro que está en su repositorio, ya que es posible que desee volver a consultarlo más adelante. Mi enfoque sería crear un ShadowRepository que refleje todos los registros / objetos que tengan al menos una "Referencia". A partir de su descripción y código presentados aquí, parece que está inicializando todos los datos y almacenando la referencia a 1,2,4,5 como aparece en su código.
var contactRepo = new Repository([
{id: 1, name: "Joe"},
{id: 2, name: "Jane"},
{id: 3, name: "Tom"},
{id: 4, name: "Jack"},
{id: 5, name: "Sue"}
]);
var friends = new Collection(contactRepo,[
contactRepo.get(2),
contactRepo.get(4)
]);
var coworkers = new Collection(contactRepo,[
contactRepo.get(1),
contactRepo.get(2),
contactRepo.get(5)
]);
Desde la inicialización del Repositorio y las colecciones, lo que está preguntando "Eliminar elemento del repositorio si no hay referencias" debería eliminarse inmediatamente. Sin embargo, puede rastrear las referencias de diferentes formas.
He considerado usar Object.observe para una situación similar. Sin embargo, Object.observe no funciona en todos los navegadores. Recientemente he recurrido a WatchJS
Estoy trabajando en la comprensión del código detrás de Watch.JS para permitir que una lista de observadores sobre un objeto se cree dinámicamente, esto también me permite eliminar un elemento que ya no se mira, aunque sugiero que se elimine la referencia en el punto de acceso - Lo que quiero decir es que una variable que comparte el alcance léxico inmediato con un objeto que ha dado un único punto de referencia a su hermano se puede eliminar haciendo que ya no sea accesible fuera del objeto que expuso el registro / elemento / propiedad / objeto de su hermano. Con la referencia de la que dependen todas sus otras referencias, se detiene el acceso eliminado a los datos subyacentes. Estoy generando una identificación única para las referencias de origen para evitar reutilizar accidentalmente la misma.
Gracias por compartir su pregunta y la estructura que está utilizando, me ha ayudado a considerar uno de mis casos específicos en el que estaba generando referencias identificadas de forma única a un hermano léxico. Estos identificadores únicos se guardaron en el objeto ONE que tenía alcance. Después de leer aquí lo he reconsiderado y he decidido exponer solo una referencia y luego asignar esa referencia a un nombre de variable donde sea que se necesite, como al crear un observador u otra Colección.