Есть ли у объектов или переменных JavaScript какой-то уникальный идентификатор? Как и Ruby, есть object_id
. Я не имею в виду атрибут DOM id, а скорее какой-то адрес памяти.JavaScript Идентификатор объекта
ответ
Нет, объекты не имеют встроенного идентификатора, хотя вы можете добавить его, изменив прототип объекта. Вот пример того, как вы могли бы сделать это:
(function() {
var id = 0;
function generateId() { return id++; };
Object.prototype.id = function() {
var newId = generateId();
this.id = function() { return newId; };
return newId;
};
})();
Тем не менее, в общем случае изменения объекта прототипа считается очень плохой практикой. Вместо этого я рекомендовал бы вам вручную назначить идентификатор объектам по мере необходимости или использовать функцию touch
, как предложили другие.
ActionScript 3 имеет объект Dictionary, который использует строгое равенство для сравнения ключей, поэтому можно использовать объекты в качестве ключей. Есть ли эквивалент в JavaScript или вам нужно вручную создавать уникальные идентификаторы для каждого объекта (либо через Object.prototype, либо вручную добавить идентификатор для выбора объектов)? – Triynko
К сожалению, javascript не имеет ничего подобного. Похоже, вам нужно будет предоставить идентификатор объектов, а затем использовать эти id как ключи в объекте, как вы предложили. Тем не менее, если вы действительно хотите быть умными, вы можете реализовать «объекты id», переопределив метод toString и используя их как этот id = new Id(); cache [id] = obj'. Это немного орехи, но довольно интересно. Вот статья, которую я написал, которая объясняет эту технику более подробно: http://xavi.co/articles/fun-with-tostring-in-javascript – Xavi
Хорошо, я только что узнал, почему. jQuery также переопределяет идентификатор, и как-то моя страница сломалась, когда я его переопределил. Хах. Хорошо. Так. Я просто избегу проблем с именами и скрещиваю пальцы. – Lodewijk
На самом деле, вам не нужно модифицировать прототип 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;
}
Просто имейте в виду, что это НЕ будет хорошо работать с большинством способов копирования объектов, если вы ожидаете, что объекты будут иметь разные идентификаторы впоследствии. –
Действительно, вам понадобится специальная функция «copyObject», которая учитывает этот __obj_id. Вы также должны быть уверены, что нет конфликтов с использованием «__obj_id» в других библиотеках. Это намного проще в ActionScript, объект Dictionary которого использует строгое сравнение сравнений по ключам, включая объекты, используемые в качестве ключей. Фактически, вы, вероятно, могли бы написать класс Dictionary в JS, который автоматически привязывает идентификаторы таким образом к объектам, которые добавляются к нему в виде ключей. Это как квантово-механические идентификаторы JavaScript; они не существуют, пока вы не попытаетесь наблюдать их с помощью этой функции, ха-ха. – Triynko
Я только что наткнулся на это и подумал, что добавлю свои мысли. Как и другие предложили, я бы рекомендовал вручную добавлять идентификаторы, но если вы действительно хотите что-то близкое к тому, что вы описали, вы могли бы использовать это:
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 выполнить свою работу (но с этой точки все объекты будут сброшены).
Я считаю, что это медленно, но-надежное решение, и может быть немного улучшилось: '' ' вар ObjectId = (функция() { вар MEM = []; вар е = функция (OBJ) { вар г = mem.indexOf (OBJ); , если (г === -1) { г = mem.length; mem.push (OBJ); } возвращение г; }; f.reset = ( return mem = []; }; '' ' – luochen1990
@ luochen1990, я думаю, вы будете удивлены его быстротой. (Но вы правы, лучше применить значение indexOf() в переменную, хотя я бы сказал, что это с точки зрения СУХОЙ, а не с оптимизацией.) Пока проблема GC может быть эффективно решена, я думаю, d должны иметь множество объектов, чтобы заметить какое-либо значительное влияние на производительность. –
Если вы хотите для поиска/связать объект с уникальным идентификатором, не изменяя основной объект, вы можете использовать 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
гарантирует, что объекты по-прежнему может быть сборщиком мусора.
Лучший ответ! Использует память O (n), где n - количество объектов, чьи идентификаторы вам интересны (а не n = все объекты) и не влияют на сбор мусора. –
Вы хотите сравнить объекты с помощью object_id? – Upperstage
См. Http://stackoverflow.com/questions/1997661/unique-object-identifier-in-javascript –