2010-01-07 1 views
59

Есть ли у объектов или переменных JavaScript какой-то уникальный идентификатор? Как и Ruby, есть object_id. Я не имею в виду атрибут DOM id, а скорее какой-то адрес памяти.JavaScript Идентификатор объекта

+2

Вы хотите сравнить объекты с помощью object_id? – Upperstage

+0

См. Http://stackoverflow.com/questions/1997661/unique-object-identifier-in-javascript –

ответ

36

Нет, объекты не имеют встроенного идентификатора, хотя вы можете добавить его, изменив прототип объекта. Вот пример того, как вы могли бы сделать это:

(function() { 
    var id = 0; 

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

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

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

     return newId; 
    }; 
})(); 

Тем не менее, в общем случае изменения объекта прототипа считается очень плохой практикой. Вместо этого я рекомендовал бы вам вручную назначить идентификатор объектам по мере необходимости или использовать функцию touch, как предложили другие.

+0

ActionScript 3 имеет объект Dictionary, который использует строгое равенство для сравнения ключей, поэтому можно использовать объекты в качестве ключей. Есть ли эквивалент в JavaScript или вам нужно вручную создавать уникальные идентификаторы для каждого объекта (либо через Object.prototype, либо вручную добавить идентификатор для выбора объектов)? – Triynko

+0

К сожалению, javascript не имеет ничего подобного. Похоже, вам нужно будет предоставить идентификатор объектов, а затем использовать эти id как ключи в объекте, как вы предложили. Тем не менее, если вы действительно хотите быть умными, вы можете реализовать «объекты id», переопределив метод toString и используя их как этот id = new Id(); cache [id] = obj'. Это немного орехи, но довольно интересно. Вот статья, которую я написал, которая объясняет эту технику более подробно: http://xavi.co/articles/fun-with-tostring-in-javascript – Xavi

+0

Хорошо, я только что узнал, почему. jQuery также переопределяет идентификатор, и как-то моя страница сломалась, когда я его переопределил. Хах. Хорошо. Так. Я просто избегу проблем с именами и скрещиваю пальцы. – Lodewijk

8

На самом деле, вам не нужно модифицировать прототип object. Следующее должно работать, чтобы «получить» уникальные идентификаторы для любого объекта, достаточно эффективно.

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

Просто имейте в виду, что это НЕ будет хорошо работать с большинством способов копирования объектов, если вы ожидаете, что объекты будут иметь разные идентификаторы впоследствии. –

+0

Действительно, вам понадобится специальная функция «copyObject», которая учитывает этот __obj_id. Вы также должны быть уверены, что нет конфликтов с использованием «__obj_id» в других библиотеках. Это намного проще в ActionScript, объект Dictionary которого использует строгое сравнение сравнений по ключам, включая объекты, используемые в качестве ключей. Фактически, вы, вероятно, могли бы написать класс Dictionary в JS, который автоматически привязывает идентификаторы таким образом к объектам, которые добавляются к нему в виде ключей. Это как квантово-механические идентификаторы JavaScript; они не существуют, пока вы не попытаетесь наблюдать их с помощью этой функции, ха-ха. – Triynko

1

Я только что наткнулся на это и подумал, что добавлю свои мысли. Как и другие предложили, я бы рекомендовал вручную добавлять идентификаторы, но если вы действительно хотите что-то близкое к тому, что вы описали, вы могли бы использовать это:

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; 
})(); 

Вы можете получить идентификатор любого объекта путем вызова objectId(obj). Тогда, если вы хотите, чтобы идентификатор быть свойством объекта, вы можете либо расширить прототип:

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

или вы можете вручную добавить идентификатор к каждому объекту, добавив аналогичную функцию в качестве метода.

Главное предостережение заключается в том, что это предотвратит уничтожение сборщика мусора, когда они выйдут из сферы действия ... они никогда не выйдут из области массива allObjects, так что вы можете обнаружить утечку памяти. Если ваш набор использует этот метод, вы должны сделать это только для целей отладки. При необходимости вы можете сделать objectId.clear(), чтобы очистить allObjects и дать GC выполнить свою работу (но с этой точки все объекты будут сброшены).

+0

Я считаю, что это медленно, но-надежное решение, и может быть немного улучшилось: '' ' вар ObjectId = (функция() { вар MEM = []; вар е = функция (OBJ) { вар г = mem.indexOf (OBJ); , если (г === -1) { г = mem.length; mem.push (OBJ); } возвращение г; }; f.reset = ( return mem = []; }; '' ' – luochen1990

+0

@ luochen1990, я думаю, вы будете удивлены его быстротой. (Но вы правы, лучше применить значение indexOf() в переменную, хотя я бы сказал, что это с точки зрения СУХОЙ, а не с оптимизацией.) Пока проблема GC может быть эффективно решена, я думаю, d должны иметь множество объектов, чтобы заметить какое-либо значительное влияние на производительность. –

21

Если вы хотите для поиска/связать объект с уникальным идентификатором, не изменяя основной объект, вы можете использовать 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 

Использование WeakMap гарантирует, что объекты по-прежнему может быть сборщиком мусора.

+0

Лучший ответ! Использует память O (n), где n - количество объектов, чьи идентификаторы вам интересны (а не n = все объекты) и не влияют на сбор мусора. –