2010-01-07 8 views
59

Czy obiekty/zmienne JavaScript mają jakiś unikalny identyfikator? Podobnie jak Ruby ma object_id. Nie mam na myśli atrybutu DOMID, ale raczej jakiegoś rodzaju adresu pamięci.Identyfikator obiektu JavaScript

+2

Czy chcesz porównać obiekty przy użyciu id_obiektu? – Upperstage

+0

Zobacz http://stackoverflow.com/questions/1997661/unique-object-identifier-in-javascript –

Odpowiedz

36

Nie, obiekty nie mają wbudowanego identyfikatora, ale można go dodać, modyfikując prototyp obiektu. Oto przykład tego, jak można to zrobić:

(function() { 
    var id = 0; 

    function generateId() { return id++; }; 

    Object.prototype.id = function() { 
     var newId = generateId(); 

     this.id = function() { return newId; }; 

     return newId; 
    }; 
})(); 

To powiedziawszy, w ogóle modyfikując prototyp obiekt jest za bardzo złą praktyką. Zamiast tego zaleciłbym ręczne przypisanie identyfikatora do obiektów w razie potrzeby lub użycie funkcji touch, tak jak sugerowali inni.

+0

ActionScript 3 ma obiekt Dictionary, który używa ścisłej równości do porównywania kluczy, więc można używać obiektów jako kluczy. Czy istnieje odpowiednik w JavaScript, czy musiałbyś ręcznie skonstruować unikatowe identyfikatory dla każdego obiektu (poprzez Object.prototype lub ręcznie dodając identyfikator do wybranych obiektów)? – Triynko

+0

Niestety javascript nie ma czegoś takiego. Wygląda na to, że będziesz musiał podać id obiektów, a następnie użyć tych identyfikatorów jako kluczy w obiekcie, tak jak sugerujesz. To powiedziawszy, jeśli naprawdę chcesz być sprytny, możesz zaimplementować "obiekty id" poprzez przesłonięcie metody 'toString' i użycie ich w ten sposób' id = new Id(); cache [id] = obj'. To trochę orzechowe, ale całkiem interesujące. Oto artykuł, który napisałem, który wyjaśnia tę technikę bardziej szczegółowo: http://xavi.co/articles/fun-with-tostring-in-javascript – Xavi

+0

OK, właśnie dowiedziałem się, dlaczego. jQuery nadpisuje również ID i jakoś moja strona się zepsuła, kiedy ją przejąłem. Hah. W porządku. Więc. Po prostu uniknę problemów z nazywaniem i przekreślam palce. – Lodewijk

8

W rzeczywistości nie trzeba modyfikować prototypu object. Następujące rzeczy powinny działać, aby "uzyskać" niepowtarzalne identyfikatory dla dowolnego obiektu, wystarczająco skutecznie.

var __next_objid=1; 
function objectId(obj) { 
    if (obj==null) return null; 
    if (obj.__obj_id==null) obj.__obj_id=__next_objid++; 
    return obj.__obj_id; 
} 
+6

Pamiętaj, że to NIE będzie dobrze grać z większością sposobów kopiowania obiektów, jeśli spodziewasz się, że obiekty będą później miały różne identyfikatory. –

+0

Rzeczywiście, potrzebowałbyś specjalnej funkcji "copyObject", która bierze to pod uwagę __obj_id specjalnie. Trzeba też mieć pewność, że nie ma konfliktów w korzystaniu z "__obj_id" w innych bibliotekach. Jest to znacznie łatwiejsze w języku ActionScript, którego obiekt Dictionary używa ścisłego porównania równości na kluczach, w tym obiektach używanych jako klucze. W rzeczywistości prawdopodobnie można napisać klasę Dictionary w JS, która automatycznie dołącza ids w ten sposób do obiektów, które są do niej dodawane jako klucze. To jak kwantowe mechanizmy JavaScript ID; nie istnieją, dopóki nie spróbujesz ich obserwować z tą funkcją, haha. – Triynko

1

Właśnie się z tym spotkałem i pomyślałem, że dodam swoje myśli. Jak inni sugerują, polecam ręczne dodawanie identyfikatorów, ale jeśli naprawdę chcesz coś podobnego do tego, co opisałeś, można użyć to:

var objectId = (function() { 
    var allObjects = []; 

    var f = function(obj) { 
     if (allObjects.indexOf(obj) === -1) { 
      allObjects.push(obj); 
     } 
     return allObjects.indexOf(obj); 
    } 
    f.clear = function() { 
     allObjects = []; 
    }; 
    return f; 
})(); 

można uzyskać identyfikator dowolnego obiektu poprzez wywołanie objectId(obj). Następnie, jeśli chcesz, id być właściwością obiektu, można przedłużyć prototype:

Object.prototype.id = function() { 
    return objectId(this); 
} 

lub można ręcznie dodać identyfikator dla każdego obiektu poprzez dodanie podobną funkcję jako metodę.

Najważniejszym zastrzeżeniem jest to, że zapobiegnie to niszczeniu obiektów przez przedmioty znajdujące się w odpadach podczas ich opuszczania ... nigdy nie znikną one z zakresu tablicy allObjects, więc może być problem z wyciekami pamięci. Jeśli twój zestaw używa tej metody, powinieneś zrobić to tylko dla celów debugowania. W razie potrzeby możesz wykonać objectId.clear(), aby wyczyścić allObjects i pozwolić GC wykonać swoje zadanie (ale od tego momentu wszystkie identyfikatory obiektów zostaną zresetowane).

+0

myślę jest powolny, ale odpornego rozwiązanie i może być poprawiona trochę: '' var objectid = (funkcja() { var mem = []; var f = funkcja (obj) { var R = mem.indexOf (obj) if (R === 1) {R = mem.length; mem.push (obj) } powrotnym R; }; f.reset = function() { return mem = []; }; return f; })(); '' ' – luochen1990

+0

@ luochen1990, Myślę, że byłbyś zaskoczony szybkością tego. (Ale masz rację, lepiej jest umieścić indeks indexOf() w zmiennej, chociaż argumentowałbym to raczej z perspektywy DRY niż optymalizacji). Tak długo, jak kwestię GC można skutecznie zarządzać, myślę, że " Musimy mieć dużo przedmiotów, aby zauważyć jakikolwiek znaczący wpływ na wydajność. –

21

Jeśli chcesz odnośnika/skojarzyć obiekt z unikalnym identyfikatorem bez modyfikowania podstawowych obiektów, można użyć WeakMap:

// Note that object must be an object or array, 
// NOT a primitive value like string, number, etc. 
var objIdMap=new WeakMap, objectCount = 0; 
function objectId(object){ 
    if (!objIdMap.has(object)) objIdMap.set(object,++objectCount); 
    return objIdMap.get(object); 
} 

var o1={}, o2={}, o3={a:1}, o4={a:1}; 
console.log(objectId(o1)) // 1 
console.log(objectId(o2)) // 2 
console.log(objectId(o1)) // 1 
console.log(objectId(o3)) // 3 
console.log(objectId(o4)) // 4 
console.log(objectId(o3)) // 3 

Używanie WeakMap zapewnia, że ​​obiekty mogą być nadal śmieci zebrane.

+0

Najlepsza odpowiedź! Używa pamięci O (n), gdzie n jest liczbą obiektów, których identyfikatory Cię interesują (a nie n = wszystkie obiekty) i nie wpływa na odśmiecanie. –