生成唯一的id js

时间:2016-05-11 22:09:12

标签: javascript arrays jasmine

在Jasmine中运行一些测试试图让这段代码工作,发现id不是唯一的。这是有道理的,因为它们是随机生成的。

var Robot = function(){
    this.name = makeid();
    function makeid()
    {
        var text = "";
        var possible ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for( var i=0; i < 2; i++ ){
            text += possible.charAt(Math.floor(Math.random() * possible.length));
        }
        var possibleNums ="0123456789";
        for( var j=0; j < 3; j++ ){
            text += possibleNums.charAt(Math.floor(Math.random() * possibleNums.length));
        }
        return text;
    }
};

我需要它来完成这个测试。

it('there can be lots of robots with different names each', function() {
    var i,
        numRobots = 10000,
        usedNames = {};

    for (i = 0; i < numRobots; i++) {
      var newRobot = new Robot();
      usedNames[newRobot.name] = true;
    }
    expect(Object.keys(usedNames).length).toEqual(numRobots);
  });

我认为我可以创建一个数组,将每个名称推送到它,然后比较唯一性。看起来这可能令人沮丧。我想知道是否有另一种方式,可能是为了保证生成时的唯一性或一些不涉及数组的简单比较工具。

编辑:日期戳方法将是确保唯一ID的好方法,但不幸的是我必须使用我用于传递另一个测试的id生成方法。基本上我需要id是5个字符,带有2个大写字母,后跟3个数字。

5 个答案:

答案 0 :(得分:6)

您可以使用Date.now()代替使用自定义唯一ID生成系统,它会以毫秒为单位返回日期和时间,如下所示:1463004819469

Date.now()每毫秒都会发生变化,并且始终是无情的。假设您的程序没有多个线程,则必须按顺序完成,因此不会有两个ID相同。

例如:

var Robot = function(){
    this.name = Date.now(); //1463004819469
}

希望这能解决你的问题!

修改:如果您连续两次致电new Robot(),您可能会获得相同的ID。您可以使用连接Date.now()连接到自定义唯一ID或随机数,如下所示:

  • this.name = String(Date.now())+Math.floor(Math.random()*10000);
  • this.name = String(Date.now())+makeid();
  • this.name = String(Date.now())+String(counter); //increment this every time you create a Robot

这些只是示例,您可以创建任何您想要的组合。

老实说,你为什么不用柜台呢?像这样:

var counter = 0;
var Robot = function(){
    counter++;
    this.name = counter;
}

除非ID也存在于程序之外,所以在这种情况下,这不起作用。

答案 1 :(得分:3)

略微修改你的代码,你可以得到保证的独特ID,但我不建议像100000+这样的大型机器人,因为它变得非常缓慢。

var Robot = function(){
    this.name = this.makeId();
};

Robot.prototype.makeId = function makeId(){
  var     text = "",
      possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  possibleNums = "0123456789";
  for( var i=0; i < 2; i++ ){
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }

  for( var j=0; j < 3; j++ ){
    text += possibleNums.charAt(Math.floor(Math.random() * 10));
  }
return !~Robot.prototype.ids.indexOf(text) ? (Robot.prototype.ids.push(text),text) : makeId();
};

Robot.prototype.ids = [];

function robotFactory(n){
  a = [];
  for(var i = 0; i < n; i++) a.push(new Robot());
  return a;
}

var myRobotArmy = robotFactory (10000);

编辑@ 2017年8月18日

检查上面的代码我以为我可以做得更好。尤其是在indexOf部分,这是性能上的巨大瓶颈。现在它运行得更快。此外,我可以通过将实例化对象的访问中的不必要的数据和功能隐藏起来,从而更好地构建构造函数。另一件事是所需的命名方案只允许676,000个名称(26 x 26 x 10 x 10 x 10),因此要求更多的机器人将导致堆栈溢出,因为我们将拥有所有可能的名称,但仍在尝试生成唯一的名称。当然,这可以通过从一开始就限制军队规模来防止。但后来考虑要求一支由676,000个机器人组成的军队。当使用的名称在哈希表中堆叠时,随机名称生成器的失败率将增加。根据姓氏,我们将不得不尝试数十万随机名称,直到我们获得最后一个独特的名称。在这种特殊情况下,您有两种解决方案;

1)如果你想要1M的机器人,那么至少以XYZ123的形式命名 2)如果您将使用大多数可用的命名方案,如XY123,并且您想要600K机器人,那么不是随机分配名称,而是按顺序分配。

function Robot(){
 this.name = Robot.makeId();
}

Robot.nums   = Array.from({length:10},(_,i) => i);
Robot.chars  = Array.from({length:26},(_,i) => String.fromCharCode(65+i));
Robot.idmap  = {};
Robot.makeId = function(){
                 var text = Array.from({length:2}, _ => Robot.chars[~~(Math.random()*26)]).join("") +
                            Array.from({length:3}, _ => Robot.nums[~~(Math.random()*10)]).join("");
                 return !Robot.idmap[text] ? (Robot.idmap[text] = true,text) : Robot.makeId();
               };

function robotFactory(n){
  a = [];
  for(var i = 0; i < n; i++) a.push(new Robot());
  return a;
}

var myRobotArmy = robotFactory(10);
console.log(myRobotArmy);

答案 2 :(得分:1)

我知道这个问题更具体,但也许像我这样的人只是寻找获取身份证的简短方法。我找到了一个解决方案 gord.github.com/gordonbrander/2230317 by gordonbrander / ID.js

  var ID = function () {
  // Math.random should be unique because of its seeding algorithm.
  // Convert it to base 36 (numbers + letters), and grab the first 9 characters
  // after the decimal.
  return '_' + Math.random().toString(36).substr(2, 9);
};

答案 3 :(得分:0)

如果您只想要一个对您自己的页面来说唯一的ID,那么只需一个计数器就可以做到这一点:

var unique = (function() {
    var cntr = 0;
    return function(prefix) {
        prefix = prefix || "";
        return prefix + cntr++;
    }
})();

console.log(unique("myid"));   // "myid0"
console.log(unique("myid"));   // "myid1"

在代码中使用它:

var unique = (function() {
    var cntr = 0;
    return function(prefix) {
        prefix = prefix || "";
        return prefix + cntr++;
    }
})();

var Robot = function(){
    this.name = unique("robot");
};

您需要一个单调递增的计数器,以确保在此范围内生成唯一的名称。

如果您想生成很可能在所有客户端中都是唯一的字符串,您可以使用以下答案中找到的内容:

Unique Random DIV ID

unique random array javascript

Generating random numbers on different input texts and ensuring random numbers shown are unique

如果您想在世界上所有页面/用户中获得完全保证,那么您必须使用中央服务器来协调和分配唯一值或使用一些已知的唯一客户端种子(这对于PC上的GUID生成器很常见)使用以太网mac地址作为种子,因为其他计算机不会重复这些地址。)

答案 4 :(得分:-1)

这是我在JS代码中使用的函数:

function uniqueid() {
    // always start with a letter (for DOM friendlyness)
    var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
    do {
        // between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
        var ascicode = Math.floor((Math.random() * 42) + 48);
        if (ascicode < 58 || ascicode > 64) {
            // exclude all chars between : (58) and @ (64)
            idstr += String.fromCharCode(ascicode);
        }
    } while (idstr.length < 32);

    return (idstr);
}