tipos - pasar variables entre funciones javascript
¿Hay algún tipo de función de código hash en JavaScript? (16)
Además de la respuesta de la falta de párpado, aquí hay una función que devuelve una identificación reproducible y única para cualquier objeto:
var uniqueIdList = [];
function getConstantUniqueIdFor(element) {
// HACK, using a list results in O(n), but how do we hash e.g. a DOM node?
if (uniqueIdList.indexOf(element) < 0) {
uniqueIdList.push(element);
}
return uniqueIdList.indexOf(element);
}
Como puede ver, utiliza una lista de búsqueda que es muy ineficiente, sin embargo, eso es lo mejor que pude encontrar por el momento.
Básicamente, estoy tratando de crear un objeto de objetos únicos, un conjunto. Tuve la brillante idea de simplemente usar un objeto JavaScript con objetos para los nombres de las propiedades. Como,
set[obj] = true;
Esto funciona, hasta cierto punto. Funciona muy bien con cadenas y números, pero con otros objetos, todos parecen "hash" con el mismo valor y tienen acceso a la misma propiedad. ¿Hay alguna forma de que pueda generar un valor hash único para un objeto? ¿Cómo lo hacen las cadenas y los números? ¿Puedo anular el mismo comportamiento?
Aquí está mi solución simple que devuelve un número entero único.
function hashcode(obj) {
var hc = 0;
var chars = JSON.stringify(obj).replace(//{|/"|/}|/:|,/g, '''');
var len = chars.length;
for (var i = 0; i < len; i++) {
// Bump 7 to larger prime number to increase uniqueness
hc += (chars.charCodeAt(i) * 7);
}
return hc;
}
En ECMAScript 6 ahora hay un Set
que funciona como te gustaría: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
Ya está disponible en los últimos Chrome, FF e IE11.
Hace un tiempo, armé un pequeño módulo de JavaScript para producir hashcodes para cadenas, objetos, matrices, etc. (Acabo de GitHub a GitHub :))
Uso:
Hashcode.value("")
// -2559914341
Hashcode.value({ ''site'' : "" })
// -3579752159
La especificación JavaScript define el acceso a la propiedad indexada como la realización de una conversión toString en el nombre del índice. Por ejemplo,
myObject[myProperty] = ...;
es lo mismo que
myObject[myProperty.toString()] = ...;
Esto es necesario como en JavaScript
myObject["someProperty"]
es lo mismo que
myObject.someProperty
Y sí, me pone triste también :-(
La forma más sencilla de hacerlo es otorgando a cada uno de sus objetos su propio método exclusivo de toString
:
(function() {
var id = 0;
/*global MyObject */
MyObject = function() {
this.objectId = ''<#MyObject:'' + (id++) + ''>'';
this.toString= function() {
return this.objectId;
};
};
})();
Tuve el mismo problema y esto lo resolvió perfectamente para mí con un alboroto mínimo, y fue mucho más fácil que volviera a implementar algunos Hashtable
estilo graso de Java y agregara equals()
y hashCode()
a sus clases de objetos. Solo asegúrate de no poner una cadena ''<#MyObject: 12> en tu hash o borrará la entrada de tu objeto que sale con esa identificación.
Ahora todos mis hash son totalmente relajantes. También acabo de publicar una entrada de blog hace unos días acerca de este tema exacto .
La solución que elegí es similar a la de Daniel, pero en lugar de utilizar una fábrica de objetos y reemplazar el toString, agrego explícitamente el hash al objeto cuando se solicita por primera vez a través de una función getHashCode. Un poco desordenado, pero mejor para mis necesidades :)
Function.prototype.getHashCode = (function(id) {
return function() {
if (!this.hashCode) {
this.hashCode = ''<hash|#'' + (id++) + ''>'';
}
return this.hashCode;
}
}(0));
Lo que usted describió está cubierto por Harmony WeakMaps , parte de la especificación ECMAScript 6 (próxima versión de JavaScript). Es decir: un conjunto donde las claves pueden ser cualquier cosa (incluido indefinido) y no enumerable.
Esto significa que es imposible obtener una referencia a un valor a menos que tenga una referencia directa a la clave (¡cualquier objeto!) Que se vincule con ella. Es importante para una serie de razones de implementación del motor relacionadas con la eficiencia y la recolección de basura, pero también es genial porque permite una nueva semántica como permisos de acceso revocables y transmisión de datos sin exponer al remitente de datos.
De MDN :
var wm1 = new WeakMap(),
wm2 = new WeakMap();
var o1 = {},
o2 = function(){},
o3 = window;
wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // A value can be anything, including an object or a function.
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // Keys and values can be any objects. Even WeakMaps!
wm1.get(o2); // "azerty"
wm2.get(o2); // Undefined, because there is no value for o2 on wm2.
wm2.get(o3); // Undefined, because that is the set value.
wm1.has(o2); // True
wm2.has(o2); // False
wm2.has(o3); // True (even if the value itself is ''undefined'').
wm1.has(o1); // True
wm1.delete(o1);
wm1.has(o1); // False
WeakMaps están disponibles en Firefox, Chrome y Edge actuales. También se admiten en el nodo v7 y en v6 con la bandera --harmony-weak-maps
.
Los objetos de JavaScript solo pueden usar cadenas como claves (cualquier otra cosa se convierte en una cadena).
De forma alternativa, podría mantener una matriz que indice los objetos en cuestión y usar su cadena de índice como referencia al objeto. Algo como esto:
var ObjectReference = [];
ObjectReference.push(obj);
set[''ObjectReference.'' + ObjectReference.indexOf(obj)] = true;
Obviamente, es un poco detallado, pero podrías escribir un par de métodos que lo manejen, y obtener y establecer todo lo que quieras.
Editar:
Su suposición es un hecho - este es un comportamiento definido en JavaScript - específicamente se produce una conversión de toString lo que significa que puede definir su propia función toString en el objeto que se utilizará como nombre de propiedad. - Olliej
Esto trae a colación otro punto interesante; puede definir un método toString en los objetos que desea hash y que pueden formar su identificador hash.
Mi solución introduce una función estática para el objeto Object
global.
(function() {
var lastStorageId = 0;
this.Object.hash = function(object) {
var hash = object.__id;
if (!hash)
hash = object.__id = lastStorageId++;
return ''#'' + hash;
};
}());
Creo que esto es más conveniente con otras funciones de manipulación de objetos en JavaScript.
Para mi situación específica, solo me importa la igualdad del objeto en lo que respecta a las claves y los valores primitivos. La solución que funcionó para mí fue convertir el objeto a su representación JSON y usarlo como hash. Existen limitaciones tales como el orden de la definición de clave que puede ser inconsistente; pero como dije, funcionó para mí porque todos estos objetos se generaban en un solo lugar.
var hashtable = {};
var myObject = {a:0,b:1,c:2};
var hash = JSON.stringify(myObject);
// ''{"a":0,"b":1,"c":2}''
hashtable[hash] = myObject;
// {
// ''{"a":0,"b":1,"c":2}'': myObject
// }
Referencia: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
puede usar el símbolo Es6 para crear una clave única y acceder al objeto. Cada valor de símbolo devuelto por Symbol () es único. Un valor de símbolo se puede usar como un identificador para las propiedades del objeto; este es el único propósito del tipo de datos.
var obj = {};
obj[Symbol(''a'')] = ''a'';
obj[Symbol.for(''b'')] = ''b'';
obj[''c''] = ''c'';
obj.d = ''d'';
Si desea tener valores únicos en un objeto de búsqueda, puede hacer algo como esto:
Crear un objeto de búsqueda
var lookup = {};
Configurando la función hashcode
function getHashCode(obj) {
var hashCode = '''';
if (typeof obj !== ''object'')
return hashCode + obj;
for (var prop in obj) // No hasOwnProperty needed
hashCode += prop + getHashCode(obj[prop]); // Add key + value to the result string
return hashCode;
}
Objeto
var key = getHashCode({ 1: 3, 3: 7 });
// key = ''1337''
lookup[key] = true;
Formación
var key = getHashCode([1, 3, 3, 7]);
// key = ''01132337''
lookup[key] = true;
Otros tipos
var key = getHashCode('''');
// key = ''''
lookup[key] = true;
Resultado final
{ 1337: true, 01132337: true, : true }
Tenga en cuenta que getHashCode
no devuelve ningún valor cuando el objeto o matriz está vacío
getHashCode([{},{},{}]);
// ''012''
getHashCode([[],[],[]]);
// ''012''
Esto es similar a la solución @ijmacd. getHashCode
no tiene la dependencia JSON
.
Si desea una función hashCode () como Java en JavaScript, es suya:
String.prototype.hashCode = function(){
var hash = 0;
for (var i = 0; i < this.length; i++) {
var character = this.charCodeAt(i);
hash = ((hash<<5)-hash)+character;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
Esa es la forma de implementación en Java (operador bit a bit).
Si desea usar objetos como claves, necesita sobrescribir su método toString, como ya se mencionó aquí. Las funciones hash que se usaron están bien, pero solo funcionan para los mismos objetos, no para objetos iguales.
He escrito una pequeña biblioteca que crea hashes de objetos, que puedes usar fácilmente para este propósito. Los objetos pueden tener un orden diferente, los hashes serán los mismos. Internamente puede usar diferentes tipos para su hash (djb2, md5, sha1, sha256, sha512, ripemd160).
Aquí hay un pequeño ejemplo de la documentación:
var hash = require(''es-hash'');
// Save data in an object with an object as a key
Object.prototype.toString = function () {
return ''[object Object #''+hash(this)+'']'';
}
var foo = {};
foo[{bar: ''foo''}] = ''foo'';
/*
* Output:
* foo
* undefined
*/
console.log(foo[{bar: ''foo''}]);
console.log(foo[{}]);
El paquete se puede usar en el navegador y en Node-Js.
Repositorio: https://bitbucket.org/tehrengruber/es-js-hash
Si realmente quieres establecer el comportamiento (voy por conocimiento de Java), entonces será difícil encontrar una solución en JavaScript. La mayoría de los desarrolladores recomendarán una clave única para representar cada objeto, pero esto no se parece a un conjunto, ya que puede obtener dos objetos idénticos, cada uno con una clave única. La API de Java hace el trabajo de buscar valores duplicados al comparar los valores del código hash, no las claves, y como no hay representación del valor del código hash de los objetos en JavaScript, es casi imposible hacer lo mismo. Incluso la biblioteca Prototype JS admite este inconveniente, cuando dice:
"Hash puede considerarse como una matriz asociativa, vinculando claves únicas a los valores (que no son necesariamente únicos) ..."