Basically, I'm trying to create an object of unique objects, a set. I had the brilliant idea of just using a Javascript object with objects for the property names. Such as,
基本上,我正在尝试创建一个对象的唯一对象,一个集合。例如,
set[obj] = true;
This works, up to a point. It works great with string and numbers, but with other objects, they all seem to "hash" to the same value and access the same property. Is there some kind of way I can generate a unique hash value for an object? How do strings and numbers do it, can I override the same behavior?
这在一定程度上是可行的。它可以很好地处理字符串和数字,但是对于其他对象,它们似乎都可以“哈希”到相同的值并访问相同的属性。是否有某种方法可以为对象生成唯一的哈希值?字符串和数字是怎么做的,我能重写相同的行为吗?
32
Javascript objects can only use strings as keys (anything else is converted to a string).
Javascript对象只能使用字符串作为键(其他任何东西都被转换为字符串)。
You could, alternatively, maintain an array which indexes the objects in question, and use its index string as a reference to the object. Something like this:
或者,您可以维护一个数组,该数组对相关对象进行索引,并使用其索引字符串作为对象的引用。是这样的:
var ObjectReference = [];
ObjectReference.push(obj);
set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;
Obviously it's a little verbose, but you could write a couple of methods that handle it and get and set all willy nilly.
显然,它有点冗长,但是您可以编写一些方法来处理它,然后获取和设置所有的威利。
Edit:
编辑:
Your guess is fact -- this is defined behaviour in Javascript -- specifically a toString conversion occurs meaning that you can can define your own toString function on the object that will be used as the property name. - olliej
您的猜测是事实——这是Javascript中定义的行为——特别是发生了toString转换,这意味着您可以在对象上定义自己的toString函数,该对象将用作属性名。——olliej
This brings up another interesting point; you can define a toString method on the objects you want to hash, and that can form their hash identifier.
这引出了另一个有趣的观点;您可以在想要散列的对象上定义一个toString方法,这可以形成它们的散列标识符。
38
If you want a hashCode() function like Java's in Javascript, that is yours:
如果您想要一个hashCode()函数,如Javascript中的Java,那就是您的:
String.prototype.hashCode = function(){
var hash = 0;
for (var i = 0; i
That is the way of implementation in Java (bitwise operator).
这就是Java中的实现方式(位操作符)。
32
The easiest way to do this is to give each of your objects its own unique toString
method:
要做到这一点,最简单的方法就是给你的每个对象一个独特的toString方法:
(function() {
var id = 0;
/*global MyObject */
MyObject = function() {
this.objectId = '<#MyObject:' + (id++) + '>';
this.toString= function() {
return this.objectId;
};
};
})();
I had the same problem and this solved it perfectly for me with minimal fuss, and was a lot easier that re-implementing some fatty Java style Hashtable
and adding equals()
and hashCode()
to your object classes. Just make sure that you don't also stick a string '<#MyObject:12> into your hash or it will wipe out the entry for your exiting object with that id.
我也遇到了同样的问题,这就很好地为我解决了这个问题,而且很容易重新实现一些胖Java风格的散列表,并向对象类添加equals()和hashCode()。只要确保您不将字符串'<#MyObject:12>插入到您的散列中,否则它将用该id清除退出对象的条目。
Now all my hashes are totally chill. I also just posted a blog entry a few days ago about this exact topic.
现在我所有的散列都是冷的。几天前,我刚刚就这个话题发表了一篇博客文章。
18
The solution I chose is similar to Daniel's, but rather than use an object factory and override the toString, I explicitly add the hash to the object when it is first requested through a getHashCode function. A little messy, but better for my needs :)
我选择的解决方案与Daniel的类似,但我没有使用对象工厂并覆盖toString,而是在通过getHashCode函数首次请求对象时显式地将散列添加到对象中。有点乱,但更符合我的需要:)
Function.prototype.getHashCode = (function(id) {
return function() {
if (!this.hashCode) {
this.hashCode = '';
}
return this.hashCode;
}
}(0));
16
What you described is covered by Harmony WeakMaps, part of the ECMAScript 6 specification (next version of Javascript). That is: a set where the keys can be anything (including undefined) and is non-enumerable.
您所描述的是Harmony WeakMaps,它是ECMAScript 6规范(Javascript的下一个版本)的一部分。即:一个集合,其中的键可以是任何东西(包括未定义的),并且是不可枚举的。
This means it's impossible to get a reference to a value unless you have a direct reference to the key (any object!) that links to it. It's important for a bunch of engine implementation reasons relating to efficiency and garbage collection, but it's also super cool for in that it allows for new semantics like revokable access permissions and passing data without exposing the data sender.
这意味着不可能获得对值的引用,除非您有指向该值的键(任何对象!)的直接引用。对于与效率和垃圾收集相关的许多引擎实现原因来说,这很重要,但它也非常酷,因为它允许新的语义,比如撤销访问权限和传递数据,而不暴露数据发送者。
From 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 are available in current Firefox, Chrome and Edge. They're also supported in Node v7 , and in v6 with the --harmony-weak-maps
flag.
弱地图可以在当前的Firefox、Chrome和Edge中使用。它们在节点v7中也得到了支持,在v6中也有—谐波-弱映射标志。
8
For my specific situation I only care about the equality of the object as far as keys and primitive values go. The solution that worked for me was converting the object to its JSON representation and using that as the hash. There are limitations such as order of key definition potentially being inconsistent; but like I said it worked for me because these objects were all being generated in one place.
对于我的具体情况,我只关心键和原始值之间的相等性。我的解决方案是将对象转换为JSON表示,并将其用作散列。有一些限制,比如关键定义的顺序可能不一致;但就像我说的,它对我有用因为这些对象都是在一个地方生成的。
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
// }
8
The Javascript specification defines indexed property access as performing a toString conversion on the index name. For example,
Javascript规范将索引属性访问定义为对索引名执行toString转换。例如,
myObject[myProperty] = ...;
is the same as
是一样的
myObject[myProperty.toString()] = ...;
This is necessary as in Javascript
这是必需的,就像在Javascript中一样
myObject["someProperty"]
is the same as
是一样的
myObject.someProperty
And yes, it makes me sad as well :-(
是的,这也让我难过
8
I put together a small Javascript module a while ago to produce hashcodes for strings, objects, arrays, etc. (I just committed it to GitHub :) )
我不久前组装了一个小的Javascript模块,为字符串、对象、数组等生成hashcode(我只是将它提交给GitHub:)。
Usage:
用法:
Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159
6
In ECMAScript 6 there's now a Set
that works how you'd like: https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Global_Objects/Set
在ECMAScript 6中,现在有一个设置可以按照您的要求工作:https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Global_Objects/Set
It's already available in the latest Chrome, FF, and IE11.
它已经在最新的Chrome、FF和IE11中可用。
3
Reference: https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Global_Objects/Symbol
参考:https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Global_Objects/Symbol
you can use Es6 symbol to create unique key and access object. Every symbol value returned from Symbol() is unique. A symbol value may be used as an identifier for object properties; this is the data type's only purpose.
您可以使用Es6符号来创建唯一的密钥和访问对象。从symbol()返回的每个符号值都是惟一的。符号值可以用作对象属性的标识符;这是数据类型的唯一用途。
var obj = {};
obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';
1
My solution introduces a static function for the global Object
object.
我的解决方案为全局对象对象引入了一个静态函数。
(function() {
var lastStorageId = 0;
this.Object.hash = function(object) {
var hash = object.__id;
if (!hash)
hash = object.__id = lastStorageId++;
return '#' + hash;
};
}());
I think this is more convenient with other object manipulating functions in Javascript.
我认为在Javascript中使用其他对象操作函数更方便。
1
Here's my simple solution that returns a unique integer.
下面是返回唯一整数的简单解决方案。
function hashcode(obj) {
var hc = 0;
var chars = JSON.stringify(obj).replace(/\{|\"|\}|\:|,/g, '');
var len = chars.length;
for (var i = 0; i
0
If you truly want set behavior (I'm going by Java knowledge), then you will be hard pressed to find a solution in Javascript. Most developers will recommend a unique key to represent each object, but this is unlike set, in that you can get two identical objects each with a unique key. The Java API does the work of checking for duplicate values by comparing hash code values, not keys, and since there is no hash code value representation of objects in Javascript, it becomes almost impossible to do the same. Even the Prototype JS library admits this shortcoming, when it says:
如果您确实想要设置行为(我是用Java知识编写的),那么您将很难在Javascript中找到解决方案。大多数开发人员会推荐一个唯一的键来表示每个对象,但这与set不同,因为您可以得到两个相同的对象,每个对象都有一个唯一的键。Java API通过比较散列代码值(而不是键)来检查重复的值,而且由于Javascript中没有对象的散列代码值表示,因此几乎不可能进行相同的操作。甚至JS库的原型也承认这个缺点,当它说:
"Hash can be thought of as an associative array, binding unique keys to values (which are not necessarily unique)..."
哈希可以被认为是一个关联数组,将唯一键绑定到值(不一定是唯一的)……
http://www.prototypejs.org/api/hash
http://www.prototypejs.org/api/hash
0
In addition to eyelidlessness's answer, here is a function that returns a reproducible, unique ID for any object:
除了无眼睑的答案之外,这里还有一个函数,它为任何对象返回可重复的唯一ID:
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);
}
As you can see it uses a list for look-up which is very inefficient, however that's the best I could find for now.
正如你看到的,它使用了一个查找列表,这是非常低效的,但是这是我目前能找到的最好的。
0
If you want to use objects as keys you need to overwrite their toString Method, as some already mentioned here. The hash functions that were used are all fine, but they only work for the same objects not for equal objects.
如果想使用对象作为键,需要覆盖它们的toString方法,这里已经提到了一些方法。使用的散列函数都很好,但是它们只适用于相同的对象,而不适用于相同的对象。
I've written a small library that creates hashes from objects, which you can easily use for this purpose. The objects can even have a different order, the hashes will be the same. Internally you can use different types for your hash (djb2, md5, sha1, sha256, sha512, ripemd160).
我编写了一个小的库,它从对象创建散列,您可以很容易地为此目的使用它。对象甚至可以有不同的顺序,散列将是相同的。在内部,您可以对哈希使用不同的类型(djb2、md5、sha1、sha256、sha512、ripemd160)。
Here is a small example from the documentation:
以下是文件中的一个小例子:
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[{}]);
The package can be used either in browser and in Node-Js.
该包可以在浏览器和Node-Js中使用。
Repository: https://bitbucket.org/tehrengruber/es-js-hash
库:https://bitbucket.org/tehrengruber/es-js-hash
0
If you want to have unique values in a lookup object you can do something like this:
如果你想在一个查找对象中有唯一的值,你可以这样做:
Creating a lookup object
创建一个查询对象
var lookup = {};
Setting up the hashcode function
设置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;
}
Object
对象
var key = getHashCode({ 1: 3, 3: 7 });
// key = '1337'
lookup[key] = true;
Array
数组
var key = getHashCode([1, 3, 3, 7]);
// key = '01132337'
lookup[key] = true;
Other types
其他类型
var key = getHashCode('StackOverflow');
// key = 'StackOverflow'
lookup[key] = true;
Final result
最终结果
{ 1337: true, 01132337: true, StackOverflow: true }
{1337:true, StackOverflow: true}
Do note that getHashCode
doesn't return any value when the object or array is empty
请注意,当对象或数组为空时,getHashCode不会返回任何值
getHashCode([{},{},{}]);
// '012'
getHashCode([[],[],[]]);
// '012'
This is similar to @ijmacd solution only getHashCode
doesn't has the JSON
dependency.
这类似于@ijmacd解决方案,只有getHashCode没有JSON依赖项。