在Javascript中从字符串生成哈希

Fre*_*nöw 530 javascript hash

我需要将字符串转换为某种形式的哈希.这在JavaScript中可行吗?

我没有使用服务器端语言,所以我不能这样做.

esm*_*lha 735

String.prototype.hashCode = function() {
  var hash = 0, i, chr;
  if (this.length === 0) return hash;
  for (i = 0; i < this.length; i++) {
    chr   = this.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
};
Run Code Online (Sandbox Code Playgroud)

资料来源:http: //werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/

  • 我在jsperf(http://jsperf.com/hashing-strings)上做了一些测试,而bitwise函数实际上比基于数字的函数慢. (40认同)
  • 是否需要(或应该)使用String原型?仅仅拥有例如,是否会降低效率/效率; `var hashCode = function hashCode(str){etc ...}`?然后用作`hashCode("mystring")`? (29认同)
  • 这与Java中使用的相同.`hash << 5-hash`与`hash*31 + char`相同,但速度更快.这很好,因为它太快了,31是一个小素数.在那里赢得胜利. (20认同)
  • @PeterAronZentai为什么它"无法使用"?基于数字的代码`(hash*31)+ char`产生的输出与基于移位的代码`((hash << 5)-hash)+ char`产生的输出相同,即使对于很长的字符串也是如此(我用包含超过一百万个字符的字符串对其进行了测试),因此在准确性方面并不"无法使用".对于基于数字和基于班次的版本,复杂度为O(n),因此就复杂性而言,它不是"不可用的". (16认同)
  • 任何人都可以评论输出的唯一性(或不是)吗?具体来说,如果我只将这个哈希值用于长度小于"n"的字符串,那么我不可能发生冲突的最大"n"是什么? (10认同)
  • 我想知道是否删除行`if(this.length == 0)返回哈希;`将对性能产生重大影响.在清洁代码方面,在我看来,它只是噪音. (8认同)
  • 谢谢,但是你已经将2个变量泄漏到全局命名空间中. (5认同)
  • 如果我需要一些未签名的东西,会怎么样? (4认同)
  • 创建端口,谢谢.为了确保总是正数(因为我不想要负数),我将`return hash;`改为`return(hash >>> 0);` (4认同)
  • @AbhimanyuAryan这是JS中Java的String.hashCode的实现。它只是将哈希乘以31,然后添加下一个字符。((hash &lt;&lt; 5)-hash`只是按位优化,对编译器很有用,但是在JS中是不必要的。在ES6中,可以像这样使用`Math.imul`来实现:`var hashCode = s =&gt; {for(var i = h = 0; i &lt;s.length; i ++)h = Math.imul(31,h) + s.charCodeAt(i)| 0;返回h;}`Math.imul`在这种情况下要快得多。 (4认同)
  • 基于数字不适用于较大的字符串. (3认同)
  • 两个连续值之间的熵非常低!“a”是 97,b 是“98” (3认同)
  • @DonMcCurdy“我不可能发生碰撞的最大 n 是多少?” 恐怕是“n=1”。[`'Aa'.hashCode() == 'BB'.hashCode()` 为 `true`](/sf/ask/658474281/)。 (3认同)
  • @hdgarrood - `Math.pow(2,33)&<anything> === 0`因为`&`op对32位int进行了隐式转换,最后32位为0,所以第34位的1被扔掉了.使用`&`op的任何东西都是完全相同的,包括`&0xffffffff` (2认同)
  • @skerit您的基于数字的性能测试未正确实现算法,如下所述:http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#hashCode()。这是一个更新:http://jsperf.com/hashing-strings/38基于数字的速度明显慢于按位。 (2认同)
  • FWIW我不认为`hash | = 0`表达式正在做预期的事情.我有一个应用程序,我需要在JavaScript和PHP中生成匹配的哈希,所以我将此函数移植到PHP.两个函数的哈希值不匹配,但是当我明确保持低32位(`hash&= 0xffff`)时,所有内容都匹配. (2认同)
  • @OZZIE var hashCode = yourString.hashCode(); (2认同)
  • @ScottMeans您不会期望`| = 0'在JS和PHP中总是有相同的结果–在JS中,它隐式地将第一个操作数转换为32位整数–在PHP中不是这种情况。即32位整数转换是JS`|`运算符的怪癖。 (2认同)
  • @robinnnnn 左移 5 次相当于乘以 32。选择它是因为它可能在测试期间导致最少的冲突。即使向左移动一次,也就是乘以 2,您也可以逃脱。它没有什么特别之处。它并不比 4 或 6 好多少。这甚至不是一个 _good_ 哈希函数。FNV 明显更好,MurmurHash 甚至比 FNV 更好。 (2认同)
  • 删除 `if (this.length === 0) return hash;` 因为 `0 &lt; 0 == false` 所以 `for` 将跳过并返回 `0` (2认同)
  • 我们需要这行“if (this.length === 0) return hash;”吗?如果 length = 0 那么它无论如何都不会进入循环 (2认同)

lor*_*lad 120

编辑

基于我的jsperf测试,接受的答案实际上更快:http://jsperf.com/hashcodelordvlad

原版的

如果有人感兴趣,这里有一个改进的(更快的)版本,在没有reduce数组功能的旧浏览器上会失败.

hashCode = function(s){
  return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
}
Run Code Online (Sandbox Code Playgroud)

  • 好人@lordvlad,实际测试他自己的答案,然后报告它什么时候慢. (90认同)
  • 奇怪的.我只是测试了它,结果是比接受的答案慢得多.http://jsperf.com/hashcodelordvlad (38认同)
  • 我刚刚意识到:完全合理的是接受的答案更快,因为我的版本必须首先将字符串转换为数组,分配新内存并复制每个字符...... (8认同)
  • 有没有办法获得只有正数的哈希? (7认同)
  • [] .reduce.call(str,(p,c,i,a)=>(p << 5) - p + a.charCodeAt(i),0); (5认同)

mar*_*r10 93

注意:即使使用最佳的32位散列,您也必须处理迟早发生冲突的事实.即两个不同的输入字符串将返回相同的散列值,概率至少为1:2 ^ 32.

在回答这个问题时, 哪种哈希算法最适合于唯一性和速度?,Ian Boyd发表了一篇很好的深度分析报告.简而言之(正如我所解释的那样),他得出的结论是Murmur是最好的,其次是FNV-1a.
esmiralha提出的Java的String.hashCode()算法似乎是DJB2的变种.

  • FNV-1a的分布比DJB2好,但速度较慢
  • DJB2比FNV-1a快,但往往会产生更多的碰撞
  • MurmurHash3比DJB2和FNV-1a更好更快(但优化的实现需要比FNV和DJB2更多的代码行)

这里有一些带有大输入字符串的基准测试:http://jsperf.com/32-bit-hash
输入字符串被散列时,murmur的性能相对于DJ2B和FNV-1a而言下降:http://jsperf.com/32- 位散列/ 3

所以一般来说我会推荐murmur3.
请参阅此处获取JavaScript实现:https: //github.com/garycourt/murmurhash-js

如果输入字符串很短并且性能比分发质量更重要,请使用DJB2(由esmiralha接受的答案提出).

如果质量和小代码大小比速度更重要,我使用FNV-1a的这种实现(基于此代码).

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as 
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 这会加上前导'0',因此生成的哈希值始终为8个字符。在输出中更易于阅读和识别,但这是我个人的看法 (3认同)
  • 我喜欢这个答案,因为它产生了一个更好的分布式哈希:这里提出的其他函数将产生相应的哈希值.例如`hash("example1") - hash("example2")== 1",而这个更难以预测. (3认同)
  • 针对“FNV-1a 的分布比 DJB2 更好,但速度更慢”——我认为应该说,当使用 ES6 `Math.imul` 函数实现时,FNV1a 可以非常快。仅此一点就使其成为顶级基准,并且从长远来看最终是比 DJB2 更好的选择。 (2认同)

dee*_*ith 51

根据ES6中接受的答案.更小,可维护,适用于现代浏览器.

function hashCode(str) {
  return str.split('').reduce((prevHash, currVal) =>
    (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}

// Test
console.log("hashCode(\"Hello!\"): ", hashCode('Hello!'));
Run Code Online (Sandbox Code Playgroud)

  • 但是,比这些更慢,更慢:[https://jsperf.com/hashing-strings](https://jsperf.com/hashing-strings) (4认同)
  • @deekshith接受的答案使用`hash | = 0`转换为32位int.这种实现没有.这是一个错误吗? (3认同)
  • 有什么办法只能产生积极但仍然独特的结果? (2认同)
  • @BeetleJuice 更合适的问题是,如果您有一个旨在接受字符串的函数,那么为什么您的程序首先向它发送非字符串?也许这个错误表明调用者正在做奇怪的事情。深思熟虑。 (2认同)

bry*_*ryc 29

这是一个简单,分布均匀的53位哈希.与32位散列相比,它速度非常快,并且具有明显更低的冲突率.

var jhashcode=s=>{for(var i=0,h;i<s.length;i++)h=Math.imul(31,h)+s.charCodeAt(i)|0;return h}
Run Code Online (Sandbox Code Playgroud)

它使用类似于xxHash/MurmurHash3的技术,但不是那么彻底.它实现了雪崩(非严格),因此输入中的微小变化会使输出发生很大变化,使其看起来是随机的:

const cyrb53 = function(str, seed = 0) {
    let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
    for (let i = 0, ch; i < str.length; i++) {
        ch = str.charCodeAt(i);
        h1 = Math.imul(h1 ^ ch, 2654435761);
        h2 = Math.imul(h2 ^ ch, 1597334677);
    }
    h1 = Math.imul(h1 ^ h1>>>16, 2246822507) ^ Math.imul(h2 ^ h2>>>13, 3266489909);
    h2 = Math.imul(h2 ^ h2>>>16, 2246822507) ^ Math.imul(h1 ^ h1>>>13, 3266489909);
    return 4294967296 * (2097151 & h2) + (h1>>>0);
};
Run Code Online (Sandbox Code Playgroud)

您还可以为相同输入的备用流提供种子:

0xc2ba782c97901 = cyrb53("a")
0xeda5bc254d2bf = cyrb53("b")
0xe64cc3b748385 = cyrb53("revenge")
0xd85148d13f93a = cyrb53("revenue")
Run Code Online (Sandbox Code Playgroud)

从技术上讲,它是64位散列,但JavaScript仅限于53位整数.通过改变十六进制字符串或数组的返回行,仍然可以使用完整的64位:

0xee5e6598ccd5c = cyrb53("revenue", 1)
0x72e2831253862 = cyrb53("revenue", 2)
0x0de31708e6ab7 = cyrb53("revenue", 3)
Run Code Online (Sandbox Code Playgroud)

问题是,构造十六进制字符串成为性能瓶颈,数组需要两个比较运算符而不是一个,这不方便.因此,在将其用于高性能应用程序时请记住这一点.


而且只是为了好玩,这里有89个字符的最小32位散列,仍然比FNV/DJB2/SMDB好:

return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return [h2>>>0, h1>>>0];
Run Code Online (Sandbox Code Playgroud)

  • @KossiD.TS 我没有选择那些乘数;它们是从其他地方借来的(L'Ecuyer、Knuth、MurmurHash)。通常这些数字是由聪明的人通过概率测试(例如模拟退火、遗传编程)找到的,寻找最佳的统计结果,并针对他们的用例进行调整。它们并不真正影响效率,只是影响哈希结果的质量。例如,将它们设为偶数通常会破坏一切,但数百万个奇数的组合可以给出不错的结果。我确信可以找到更好的常数。我从未使用 SMHasher 对此进行过测试。 (9认同)
  • 哇,这比通常的* 31输入短(或类似)输入要好得多。:) (4认同)
  • @bryc你如何选择那些不一定是质数的大数字?它们如何影响结果的效率和性能? (4认同)
  • @aomarks 抱歉,我不喜欢中年皇家法令;这是公共领域,你可以随意接受。也许如果麻省理工学院为我提供免费学费来支持他们;) (4认同)
  • @Andrew 更新了答案以澄清“种子”。它是一个 32 位无符号整数。因此,值可以是 0 到 2^32-1,并且没有小数点。所以没有浮动;JS 无论如何都会在第一次 XOR 操作时去除小数部分。`str` 的长度没有限制。此外,它可以轻松地与数组而不是字符串一起使用,但这个问题是针对字符串的。 (4认同)
  • @ hellowill89糟糕,我忘了声明它,并且正在渗入全球范围。现在修复,谢谢:') (3认同)
  • @BachT 您可以使用 [polyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul#Polyfill) 或完整的 [ES6 shim](https: //github.com/paulmillr/es6-shim)。但是 IE11 在 2009 年悲惨地冻结了,没有更新。 (3认同)
  • ch在哪里初始化? (2认同)
  • @KossiD.TS 这解释了为什么我在答案底部的 TSH 哈希中使用“9**9”作为乘数。它只是一个很大的奇数,387420489。乘数越大,越容易发生混乱(但 32 位是 JS 中按位运算的限制)。 (2认同)
  • @bryc 公共领域很棒!您愿意明确授予“cyrb53”公共领域的等效许可证吗?建议示例: https://opensource.org/licenses/0BSD https://opensource.org/licenses/unlicense 提出此请求的(令人沮丧的)原因是,在某些司法管辖区,声明某些内容属于公共领域并不合法使之如此。因此,最接近的可用工具是通过授予与公共领域相同的使用自由度的许可证来覆盖它。请参阅 https://en.wikipedia.org/wiki/Public-domain-equivalent_license。感谢您考虑! (2认同)

Kyl*_*ner 26

如果它可以帮助任何人,我将前两个答案组合成一个较旧的浏览器容忍版本,如果reduce可用则使用快速版本,如果不是,则使用esmiralha的解决方案.

/**
 * @see http://stackoverflow.com/q/7616461/940217
 * @return {number}
 */
String.prototype.hashCode = function(){
    if (Array.prototype.reduce){
        return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
    } 
    var hash = 0;
    if (this.length === 0) return hash;
    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;
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

var hash = new String("some string to be hashed").hashCode();
Run Code Online (Sandbox Code Playgroud)


mom*_*omo 24

这是一个精致且性能更好的变体:

String.prototype.hashCode = function() {
    var hash = 0, i = 0, len = this.length;
    while ( i < len ) {
        hash  = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
    }
    return hash;
};
Run Code Online (Sandbox Code Playgroud)

这与Java的标准实现相匹配 object.hashCode()

这里也只返回正的哈希码:

String.prototype.hashcode = function() {
    return (this.hashCode() + 2147483647) + 1;
};
Run Code Online (Sandbox Code Playgroud)

这是一个匹配的Java,只返回正的哈希码:

public static long hashcode(Object obj) {
    return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}
Run Code Online (Sandbox Code Playgroud)

请享用!

  • @momomo你的意思是左_shift_? (26认同)
  • @koolaang这是左手操作员,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Left_shift (7认同)
  • @Maykonn(2 ^ 32-1) (3认同)
  • 好的答案,但是&lt;&lt; 0的目的是什么? (2认同)
  • @momomo我想他在问为什么这是零位的左移。 (2认同)
  • @jpfx1342 我后来意识到了这一点。快速测试没有建议不同的输出,所以是的,需要。我相信它将括号中的内容转换为 32 位整数。32 位整数转换是 JS 的一个怪癖。 (2认同)

bvd*_*vdb 24

UUID v3 和 UUID v5 实际上是给定输入字符串的哈希值。

  • UUID v3基于MD5,
  • UUID v5 基于 SHA-1。

因此,最明显的选择是使用 UUID v5。

幸运的是,有一个流行的 npm 包,其中包含所有 UUID 算法。

npm install uuid
Run Code Online (Sandbox Code Playgroud)

要实际生成 UUID v5,您需要一个唯一的命名空间。这个命名空间就像一个种子,并且应该是一个常量,以确保对于给定的输入,输出始终是相同的。讽刺的是,您应该生成 UUID v4 作为命名空间。最简单的方法是使用一些在线工具

获得命名空间后,一切就都准备好了。

import { v5 as uuidv5 } from 'uuid';

const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
const hash = uuidv5('input', MY_NAMESPACE);
Run Code Online (Sandbox Code Playgroud)

例如,如果您的输入字符串始终是 URL,则可以使用一些默认名称空间。

const hashForURL = uuidv5('https://www.w3.org/', uuidv5.URL);
Run Code Online (Sandbox Code Playgroud)

  • @YanKingYin 之所以这么长,部分原因是为了保证唯一性。这是这个答案的一个优点。;;;; 然而,唯一性并不总是哈希码的要求。如果您不需要唯一性,还有很多其他算法可以为您提供更短的哈希值。_(例如,索引算法有时使用不唯一的哈希值。查询可能会导致误报命中,随后将通过严格比较进行过滤。) (2认同)

Kai*_*ido 22

我有点惊讶没有人谈论过新的SubtleCrypto API.

要从字符串中获取哈希值,可以使用以下subtle.digest方法:

function getHash(str, algo = "SHA-256") {
  let strBuf = new TextEncoder('utf-8').encode(str);
  return crypto.subtle.digest(algo, strBuf)
    .then(hash => {
      window.hash = hash;
      // here hash is an arrayBuffer, 
      // so we'll connvert it to its hex version
      let result = '';
      const view = new DataView(hash);
      for (let i = 0; i < hash.byteLength; i += 4) {
        result += ('00000000' + view.getUint32(i).toString(16)).slice(-8);
      }
      return result;
    });
}

getHash('hello world')
  .then(hash => {
    console.log(hash);
  });
Run Code Online (Sandbox Code Playgroud)

  • 我同意.转换为十六进制可能会有所不同......`var promise = crypto.subtle.digest({name:"SHA-256"},Uint8Array.from(data)); promise.then(function(result){console.log(Array.prototype.map.call(new Uint8Array(result),x => x.toString(16).padStart(2,'0')).join(' '));});` (4认同)
  • 字符串的加密哈希函数有点过分。.“ crypto”并非完全有效。 (2认同)

Ami*_*imi 13

这是一个紧凑的 ES6 友好可读片段

const stringHashCode = str => {
  let hash = 0
  for (let i = 0; i < str.length; ++i)
    hash = Math.imul(31, hash) + str.charCodeAt(i)

  return hash | 0
}
Run Code Online (Sandbox Code Playgroud)

  • 因为它必须是“(hash &lt;&lt; 5) - hash)”,这意味着“(2^5 x hash - hash) = 32 x hash - hash = 31 x hash” (3认同)

dja*_*ham 7

多亏了mar10的例子,我找到了一种方法,可以在C#和Javascript中为FNV-1a获得相同的结果.如果存在unicode字符,则为了性能而丢弃上部.不知道为什么在散列时维护它们会有所帮助,因为现在只有散列url路径.

C#版本

private static readonly UInt32 FNV_OFFSET_32 = 0x811c9dc5;   // 2166136261
private static readonly UInt32 FNV_PRIME_32 = 0x1000193;     // 16777619

// Unsigned 32bit integer FNV-1a
public static UInt32 HashFnv32u(this string s)
{
    // byte[] arr = Encoding.UTF8.GetBytes(s);      // 8 bit expanded unicode array
    char[] arr = s.ToCharArray();                   // 16 bit unicode is native .net 

    UInt32 hash = FNV_OFFSET_32;
    for (var i = 0; i < s.Length; i++)
    {
        // Strips unicode bits, only the lower 8 bits of the values are used
        hash = hash ^ unchecked((byte)(arr[i] & 0xFF));
        hash = hash * FNV_PRIME_32;
    }
    return hash;
}

// Signed hash for storing in SQL Server
public static Int32 HashFnv32s(this string s)
{
    return unchecked((int)s.HashFnv32u());
}
Run Code Online (Sandbox Code Playgroud)

JavaScript版本

var utils = utils || {};

utils.FNV_OFFSET_32 = 0x811c9dc5;

utils.hashFnv32a = function (input) {
    var hval = utils.FNV_OFFSET_32;

    // Strips unicode bits, only the lower 8 bits of the values are used
    for (var i = 0; i < input.length; i++) {
        hval = hval ^ (input.charCodeAt(i) & 0xFF);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }

    return hval >>> 0;
}

utils.toHex = function (val) {
    return ("0000000" + (val >>> 0).toString(16)).substr(-8);
}
Run Code Online (Sandbox Code Playgroud)


Ari*_*nez 6

我参加聚会有点晚了,但你可以使用这个模块:crypto

const crypto = require('crypto');

const SALT = '$ome$alt';

function generateHash(pass) {
  return crypto.createHmac('sha256', SALT)
    .update(pass)
    .digest('hex');
}
Run Code Online (Sandbox Code Playgroud)

该函数的结果始终是64字符串;像这样:"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"


And*_*rew 6

Jenkins One at a Time Hash非常好:

//Credits (modified code): Bob Jenkins (http://www.burtleburtle.net/bob/hash/doobs.html)
//See also: https://en.wikipedia.org/wiki/Jenkins_hash_function
//Takes a string of any size and returns an avalanching hash string of 8 hex characters.
function jenkinsOneAtATimeHash(keyString)
{
  let hash = 0;
  for (charIndex = 0; charIndex < keyString.length; ++charIndex)
  {
    hash += keyString.charCodeAt(charIndex);
    hash += hash << 10;
    hash ^= hash >> 6;
  }
  hash += hash << 3;
  hash ^= hash >> 11;
  //4,294,967,295 is FFFFFFFF, the maximum 32 bit unsigned integer value, used here as a mask.
  return (((hash + (hash << 15)) & 4294967295) >>> 0).toString(16)
};
Run Code Online (Sandbox Code Playgroud)

例子:

jenkinsOneAtATimeHash('test')
"31c25ec1"
jenkinsOneAtATimeHash('a')
"ca2e9442"
jenkinsOneAtATimeHash('0')
"6e3c5c6b"
Run Code Online (Sandbox Code Playgroud)

您还可以删除.toString(16)末尾的部分来生成数字:

jenkinsOneAtATimeHash2('test')
834821825
jenkinsOneAtATimeHash2('a')
3392050242
jenkinsOneAtATimeHash2('0')
1849449579
Run Code Online (Sandbox Code Playgroud)

请注意,如果您不需要专门对字符串密钥进行哈希处理,而只需要凭空生成的哈希值,则可以使用

window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
Run Code Online (Sandbox Code Playgroud)

例子:

window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
"6ba9ea7"
window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
"13fe7edf"
window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
"971ffed4"
Run Code Online (Sandbox Code Playgroud)

和上面一样,你可以删除末尾的 `.toString(16) 部分来生成数字:

window.crypto.getRandomValues(new Uint32Array(1))[0]
1154752776
window.crypto.getRandomValues(new Uint32Array(1))[0]
3420298692
window.crypto.getRandomValues(new Uint32Array(1))[0]
1781389127
Run Code Online (Sandbox Code Playgroud)

注意:您还可以使用此方法一次生成多个值,例如:

window.crypto.getRandomValues(new Uint32Array(3))
Uint32Array(3) [ 2050530949, 3280127172, 3001752815 ]
Run Code Online (Sandbox Code Playgroud)


jco*_*lum 5

我需要一个类似的函数(但有所不同)来根据用户名和当前时间生成一个唯一的ID。所以:

window.newId = ->
  # create a number based on the username
  unless window.userNumber?
    window.userNumber = 0
  for c,i in window.MyNamespace.userName
    char = window.MyNamespace.userName.charCodeAt(i)
    window.MyNamespace.userNumber+=char
  ((window.MyNamespace.userNumber + Math.floor(Math.random() * 1e15) + new Date().getMilliseconds()).toString(36)).toUpperCase()
Run Code Online (Sandbox Code Playgroud)

产生:

2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc 
Run Code Online (Sandbox Code Playgroud)

编辑2015年6月:对于新代码,我使用shortid:https://www.npmjs.com/package/shortid

  • @ t0r0X现在好了,我使用了一个名为shortid的模块:https://www.npmjs.com/package/shortid (2认同)

sou*_*ine 5

一种快速简洁的方法,从这里改编而成:

String.prototype.hashCode = function() {
  var hash = 5381, i = this.length
  while(i)
    hash = (hash * 33) ^ this.charCodeAt(--i)
  return hash >>> 0;
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ith 5

我基于FNV Multiply+Xor方法的快速(很长)衬垫:

my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);
Run Code Online (Sandbox Code Playgroud)


Кон*_*Ван 5

SubtleCrypto.digest

我没有使用服务器端语言,所以我不能那样做。

你肯定你不能这样做

您是否忘记了您正在使用 Javascript,这是一种不断发展的语言?

试试SubtleCrypto。它支持 SHA-1、SHA-128、SHA-256 和 SHA-512 哈希函数。


async function hash(message/*: string */) {
	const text_encoder = new TextEncoder;
	const data = text_encoder.encode(message);
	const message_digest = await window.crypto.subtle.digest("SHA-512", data);
	return message_digest;
} // -> ArrayBuffer

function in_hex(data/*: ArrayBuffer */) {
	const octets = new Uint8Array(data);
	const hex = [].map.call(octets, octet => octet.toString(16).padStart(2, "0")).join("");
	return hex;
} // -> string

(async function demo() {
	console.log(in_hex(await hash("Thanks for the magic.")));
})();
Run Code Online (Sandbox Code Playgroud)

  • 这与 Kaiido [比你早两年](/sf/answers/3036879331/) 的答案有何不同? (2认同)
  • @Luc 显然不是。 (2认同)