Preciso fazer alguns experimentos e conhecer algum tipo de identificador único para objetos em javascript, para ver se são iguais. Não quero usar operadores de igualdade, preciso de algo como a função id () em python.
Será que algo assim existe ?
Preciso fazer alguns experimentos e conhecer algum tipo de identificador único para objetos em javascript, para ver se são iguais. Não quero usar operadores de igualdade, preciso de algo como a função id () em python.
Será que algo assim existe ?
Respostas:
Atualização Minha resposta original abaixo foi escrita há 6 anos em um estilo adequado à época e ao meu entendimento. Em resposta a alguma conversa nos comentários, uma abordagem mais moderna para isso é a seguinte:
(function() {
if ( typeof Object.id == "undefined" ) {
var id = 0;
Object.id = function(o) {
if ( typeof o.__uniqueid == "undefined" ) {
Object.defineProperty(o, "__uniqueid", {
value: ++id,
enumerable: false,
// This could go either way, depending on your
// interpretation of what an "id" is
writable: false
});
}
return o.__uniqueid;
};
}
})();
var obj = { a: 1, b: 1 };
console.log(Object.id(obj));
console.log(Object.id([]));
console.log(Object.id({}));
console.log(Object.id(/./));
console.log(Object.id(function() {}));
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
console.log(k);
}
}
// Logged keys are `a` and `b`
Se você tiver requisitos de navegador arcaicos, verifique aqui a compatibilidade do navegador para Object.defineProperty.
A resposta original é mantida abaixo (em vez de apenas no histórico de alterações) porque acho que a comparação é valiosa.
Você pode experimentar o seguinte. Isso também oferece a opção de definir explicitamente o ID de um objeto em seu construtor ou em outro lugar.
(function() {
if ( typeof Object.prototype.uniqueId == "undefined" ) {
var id = 0;
Object.prototype.uniqueId = function() {
if ( typeof this.__uniqueid == "undefined" ) {
this.__uniqueid = ++id;
}
return this.__uniqueid;
};
}
})();
var obj1 = {};
var obj2 = new Object();
console.log(obj1.uniqueId());
console.log(obj2.uniqueId());
console.log([].uniqueId());
console.log({}.uniqueId());
console.log(/./.uniqueId());
console.log((function() {}).uniqueId());
Tome cuidado para certificar-se de que qualquer membro que você usar para armazenar internamente o ID exclusivo não colida com outro nome de membro criado automaticamente.
object.hasOwnProperty(member)ao usar um for..inloop. Esta é uma prática bem documentada e aplicada por jslint
defineProperty(…, {enumerable:false}). E o uidmétodo em si deve estar no Objectnamespace de qualquer maneira
4como você atribuiria obj com o id 4 a uma variável para que você possa fazer coisas com ele ... como acessar suas propriedades?
Até onde vai minha observação, qualquer resposta postada aqui pode ter efeitos colaterais inesperados.
Em um ambiente compatível com ES2015, você pode evitar quaisquer efeitos colaterais usando o WeakMap .
const id = (() => {
let currentId = 0;
const map = new WeakMap();
return (object) => {
if (!map.has(object)) {
map.set(object, ++currentId);
}
return map.get(object);
};
})();
id({}); //=> 1
return currentId?
WeakMapque em oposição a Map? Essa função irá falhar se você fornecer uma string ou número.
Os navegadores mais recentes fornecem um método mais limpo para estender Object.prototype. Este código tornará a propriedade oculta da enumeração de propriedade (para p em o)
Para os navegadores que implementam defineProperty , você pode implementar a propriedade uniqueId como este:
(function() {
var id_counter = 1;
Object.defineProperty(Object.prototype, "__uniqueId", {
writable: true
});
Object.defineProperty(Object.prototype, "uniqueId", {
get: function() {
if (this.__uniqueId == undefined)
this.__uniqueId = id_counter++;
return this.__uniqueId;
}
});
}());
Para obter detalhes, consulte https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty
Na verdade, você não precisa modificar o objectprotótipo e adicionar uma função lá. O seguinte deve funcionar bem para o seu propósito.
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;
}
objecthacks. você só precisa executá-lo quando quiser que o objeto do OP corresponda e ele não atrapalhe o resto do tempo.
Para navegadores que implementam o Object.defineProperty()método, o código a seguir gera e retorna uma função que você pode vincular a qualquer objeto de sua propriedade.
Essa abordagem tem a vantagem de não se estender Object.prototype.
O código funciona verificando se o objeto fornecido tem uma __objectID__propriedade e definindo-o como uma propriedade somente leitura oculta (não enumerável), caso não tenha.
Portanto, é seguro contra qualquer tentativa de alterar ou redefinir a obj.__objectID__propriedade somente leitura após ela ter sido definida e gera consistentemente um bom erro em vez de falhar silenciosamente.
Finalmente, no caso extremo em que algum outro código já teria definido __objectID__em um determinado objeto, esse valor seria simplesmente retornado.
var getObjectID = (function () {
var id = 0; // Private ID counter
return function (obj) {
if(obj.hasOwnProperty("__objectID__")) {
return obj.__objectID__;
} else {
++id;
Object.defineProperty(obj, "__objectID__", {
/*
* Explicitly sets these two attribute values to false,
* although they are false by default.
*/
"configurable" : false,
"enumerable" : false,
/*
* This closure guarantees that different objects
* will not share the same id variable.
*/
"get" : (function (__objectID__) {
return function () { return __objectID__; };
})(id),
"set" : function () {
throw new Error("Sorry, but 'obj.__objectID__' is read-only!");
}
});
return obj.__objectID__;
}
};
})();
O código jQuery usa seu próprio data()método como id.
var id = $.data(object);
No backstage, o método datacria um campo muito especial objectchamado, "jQuery" + now()coloque o próximo id de um fluxo de ids únicos como
id = elem[ expando ] = ++uuid;
Eu sugiro que você use o mesmo método que John Resig, obviamente sabe tudo sobre JavaScript e seu método é baseado em todo esse conhecimento.
datamétodo jQuery tem falhas. Veja, por exemplo, stackoverflow.com/questions/1915341/… . Além disso, John Resig de forma alguma sabe tudo o que há para saber sobre JavaScript, e acreditar que ele sabe não o ajudará como desenvolvedor de JavaScript.
Versão datilografada de @justin answer, compatível com ES6, usando símbolos para evitar qualquer colisão de chaves e adicionado ao Object.id global por conveniência. Basta copiar e colar o código abaixo ou colocá-lo em um arquivo ObjecId.ts que você importará.
(enableObjectID)();
declare global {
interface ObjectConstructor {
id: (object: any) => number;
}
}
const uniqueId: symbol = Symbol('The unique id of an object');
export function enableObjectID(): void {
if (typeof Object['id'] !== 'undefined') {
return;
}
let id: number = 0;
Object['id'] = (object: any) => {
const hasUniqueId: boolean = !!object[uniqueId];
if (!hasUniqueId) {
object[uniqueId] = ++id;
}
return object[uniqueId];
};
}
Exemplo de uso:
console.log(Object.id(myObject));
Usei um código como este, o que fará com que os objetos sequenciem com strings exclusivas:
Object.prototype.__defineGetter__('__id__', function () {
var gid = 0;
return function(){
var id = gid++;
this.__proto__ = {
__proto__: this.__proto__,
get __id__(){ return id }
};
return id;
}
}.call() );
Object.prototype.toString = function () {
return '[Object ' + this.__id__ + ']';
};
os __proto__bits são para evitar que o __id__getter apareça no objeto. isso só foi testado no firefox.
__defineGetter__não é padrão.
Apesar do conselho de não modificar Object.prototype, isso ainda pode ser realmente útil para teste, dentro de um escopo limitado. O autor da resposta aceita mudou, mas ainda está definindo Object.id, o que não faz sentido para mim. Aqui está um snippet que faz o trabalho:
// Generates a unique, read-only id for an object.
// The _uid is generated for the object the first time it's accessed.
(function() {
var id = 0;
Object.defineProperty(Object.prototype, '_uid', {
// The prototype getter sets up a property on the instance. Because
// the new instance-prop masks this one, we know this will only ever
// be called at most once for any given object.
get: function () {
Object.defineProperty(this, '_uid', {
value: id++,
writable: false,
enumerable: false,
});
return this._uid;
},
enumerable: false,
});
})();
function assert(p) { if (!p) throw Error('Not!'); }
var obj = {};
assert(obj._uid == 0);
assert({}._uid == 1);
assert([]._uid == 2);
assert(obj._uid == 0); // still
Eu enfrentei o mesmo problema e aqui está a solução que implementei com ES6
code
let id = 0; // This is a kind of global variable accessible for every instance
class Animal {
constructor(name){
this.name = name;
this.id = id++;
}
foo(){}
// Executes some cool stuff
}
cat = new Animal("Catty");
console.log(cat.id) // 1
Para efeito de comparação de dois objetos, a maneira mais simples de fazer isso seria adicionar uma propriedade única a um dos objetos no momento em que você precisa comparar os objetos, verificar se a propriedade existe no outro e removê-la novamente. Isso salva protótipos sobrescritos.
function isSameObject(objectA, objectB) {
unique_ref = "unique_id_" + performance.now();
objectA[unique_ref] = true;
isSame = objectB.hasOwnProperty(unique_ref);
delete objectA[unique_ref];
return isSame;
}
object1 = {something:true};
object2 = {something:true};
object3 = object1;
console.log(isSameObject(object1, object2)); //false
console.log(isSameObject(object1, object3)); //true