如何使用JavaScript创建唯一标识符?

128
我有一个表单,用户可以添加多个城市的选择框。问题是每个新生成的选择框需要具有唯一的id。这可以在JavaScript中完成吗?
以下是用于选择城市的表单部分。还要注意,当选择特定州时,我使用一些PHP来填充城市。
<form id="form" name="form" method="post" action="citySelect.php">
<select id="state" name="state" onchange="getCity()">
    <option></option>
    <option value="1">cali</option>
    <option value="2">arizona</option>
    <option value="3">texas</option>
</select>
<select id="city" name="city" style="width:100px">
    
</select>

    <br/>
</form>

这是 JavaScript 代码:
$("#bt").click(function() {

$("#form").append(
       "<select id='state' name='state' onchange='getCity()'>
           <option></option>
           <option value='1'>cali</option>
           <option value='2'>arizona</option>
           <option value='3'>texas</option>
        </select>
        <select id='city' name='city' style='width:100px'></select><br/>"
     );
});

你是在使用类似于Jquery这样的框架/工具包,还是只用原生的JavaScript?另外,你能否发布一些你的代码,至少是生成的HTML输出部分? - DeaconDesperado
你最好使用单选按钮来处理这种行为。否则在Javascript中,你可以想一个名字叫做'cities',然后像'var i = 0;' 这样使用循环迭代每个选择框,执行.setAttribute('id', 'cities' + i)。getElementsByTagName('?') 在这里会有帮助。你需要提供一些HTML示例以便他人提供真正的帮助。 - Metalshark
1
你是在询问为每个新的<option id="blah">New City</option>生成唯一的id属性吗?你可以在javascript中维护对特定新DOM元素的引用,而不仅仅是它的id。因此,根据您要做什么,您不必生成唯一的ID。 - pioto
1
我相信他的意思是,他们可以列出一个或多个城市,每个城市都来自于一个选择。 - Jonathan Fingland
您可以在此处查看相同问题的答案:http://stackoverflow.com/questions/3782825/how-to-add-unique-id-to-dynamically-generated-inputs/37424649#37424649。 - Sanjay Nishad
35个回答

135
var id = "id" + Math.random().toString(16).slice(2)

33
尽管发生碰撞的概率很小,但并非零。 - fedeghe

80
const uid = function(){
    return Date.now().toString(36) + Math.random().toString(36).substr(2);
}

此函数生成非常独特的ID,按其生成日期排序。也可用于数据库中的ID。


3
请注意,长度可能会有所不同。 - swisswiss
5
不错,也许稍微改变一下使长度固定:Date.now().toString(36) + Math.floor(Math.pow(10, 12) + Math.random() * 9*Math.pow(10, 12)).toString(36) - Aditya
2
不错的建议,但您可能想要用substringslice替换已弃用的substr,以确保在大多数环境中都能正常工作。请参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring#the_difference_between_substring_and_substr - Gerald Senarclens de Grancy
2
@Aditya 很遗憾,这个问题还没有解决。在循环中运行它会显示输出的字符串长度在16和17之间交替变化。 - icecub
只需使用padStart来固定长度 Date.now().toString(36) + Math.random().toString(36).substring(2, 12).padStart(12, 0) - Tofandel

77
另一种方法是使用毫秒计时器:

var uniq = 'id' + (new Date()).getTime();

console.log(uniq)


4
似乎不是一个好主意: (+new Date + +new Date )/2 === +new Date; 翻译为:将两个当前日期相加取平均值是否等于当前日期的数值。 - fedeghe
6
如果用户在不同的国家创建ID,会发生什么? - Max Lynn
34
如果连续创建两个id,它们将不会是唯一的。var first = (new Date()).getTime(); var second = (new Date()).getTime(); console.log(first == second); - Adam Pietrasiak
1
在这种情况下,您最好使用 performance.now()performance.now() === performance.now() === false - Ulysse BN
4
@UlysseBN,我刚试了performance.now(),尽管具有超高的分辨率,但在我的机器上它并不像你描述的那样工作。 - user234932
显示剩余3条评论

46

你能不能保持一个运行中的索引呢?

var _selectIndex = 0;

...code...
var newSelectBox = document.createElement("select");
newSelectBox.setAttribute("id","select-"+_selectIndex++);

编辑

经过进一步考虑,您可能更喜欢使用数组样式的名称来选择...

例如:

<select name="city[]"><option ..../></select>
<select name="city[]"><option ..../></select>
<select name="city[]"><option ..../></select>

然后,在服务器端,例如使用 php:

$cities = $_POST['city']; //array of option values from selects

编辑2 回复OP评论

使用DOM方法动态创建选项可以按以下方式完成:

var newSelectBox = document.createElement("select");
newSelectBox.setAttribute("id","select-"+_selectIndex++);

var city = null,city_opt=null;
for (var i=0, len=cities.length; i< len; i++) {
    city = cities[i];
    var city_opt = document.createElement("option");
    city_opt.setAttribute("value",city);
    city_opt.appendChild(document.createTextNode(city));
    newSelectBox.appendChild(city_opt);
}
document.getElementById("example_element").appendChild(newSelectBox);

假设已经存在cities数组。
或者,您可以使用innerHTML方法.....
var newSelectBox = document.createElement("select");
newSelectBox.setAttribute("id","select-"+_selectIndex++);
document.getElementById("example_element").appendChild(newSelectBox);

var city = null,htmlStr="";
for (var i=0, len=cities.length; i< len; i++) {
    city = cities[i];
    htmlStr += "<option value='" + city + "'>" + city + "</option>";
}
newSelectBox.innerHTML = htmlStr;

1
我该如何将<option></option>标签插入到这个select中? - JamesTBennett
请注意,使用运行计数器可能会导致页面点击之间极有可能发生冲突。换句话说,如果计数器每次页面加载时都从1开始,那么下一次编辑/更新对象时很可能会发生冲突。记住这一点是很好的。 - Brad Lee

31

2
你应该提到 chrome > 92,并且只在 HTTPS 中使用。 - vsync

24
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);
}

2
你可能想为了OP的利益解释一下你的答案。 - Luca
你觉得用这个例子生成相同的ID的可能性有多大?看起来是有可能的,但是非常不太可能。 - user699242
1
考虑到 JavaScript 中的 RNG 很糟糕,这比你想象的更有可能发生。 - Nisk
2
为了好玩,我决定看看这有多大的可能性:在Chrome的命令行中执行以下代码:var meh=fun();while(meh !== fun()){ console.log('.'); } 到目前为止,没有重复的一百万个结果已经足够大部分情况下使用了。我猜这也是因为字符串长度为32字符所带来的预期结果。 - Nisk
此函数有可能生成相同的ID,但对于DOM的“友好性”会加1。 - Burak Tokak
始终以字母开头:这适用于HTML4,但不适用于HTML5。 - Ron Jonk

15
不需要外部库。独特性已经证明。
你可以像这样做。

// Function to generate unique id

const uniqueId = (length=16) => {
  return parseInt(Math.ceil(Math.random() * Date.now()).toPrecision(length).toString().replace(".", ""))
}

// ----------------------------

document.querySelector("#butt01").onclick = () => {
  document.querySelector("#span01").innerHTML = uniqueId()
}

ids = new Set()
count = 0

document.querySelector("#butt02").onclick = () => {
  for (let i = 0; i< 1000; i++){
    ids.add(uniqueId())
  }

  document.querySelector("#span02").innerHTML = `Found ${1000 - ids.size} duplicated random values.`
}
<div>
    <button id="butt01">Generate</button>
    <span id="span01"></span>
    <hr>
    <button id="butt02">Check collision potentiality in 1000 cases</button>
    <span id="span02"></span>
</div>

将毫秒级别的时间乘以一个随机值,使其固定大小。
运行此代码以查看可能的冲突。
无论是1000、10000还是1000000000,你都会发现没有冲突。
如果两个用户在同一时间生成ID并获得相同的随机数,那么发生的概率非常小。
为了增加唯一性,你可以将日期乘以更多的Math.random()值。

1
你的测试并不能作为证明,因为结果总是0,因为ids.indexOf(el)和ids.indexOf(ell)始终具有相同的值。 - T'lash

10
我正在解决与原帖相似的问题,并发现可以将 Guy 和 Scott 的解决方案结合起来创建一个更加可靠的解决方案。这里生成的唯一 ID 由三个部分组成,用下划线分隔开:
  1. 一个前导字母;
  2. 以36为基数显示的时间戳;
  3. 最后是一个随机部分。
这个解决方案应该非常适用于大型数据集:
function uniqueId () {
    // desired length of Id
    var idStrLen = 32;
    // always start with a letter -- base 36 makes for a nice shortcut
    var idStr = (Math.floor((Math.random() * 25)) + 10).toString(36) + "_";
    // add a timestamp in milliseconds (base 36 again) as the base
    idStr += (new Date()).getTime().toString(36) + "_";
    // similar to above, complete the Id using random, alphanumeric characters
    do {
        idStr += (Math.floor((Math.random() * 35))).toString(36);
    } while (idStr.length < idStrLen);

    return (idStr);
}

谢谢 - 这是我修改后的代码。 我重用了这段代码,将字母行替换为 var IdStr = ''; 然后我将idStrLen设置为16,以便给我一个可排序(时间)的ID,例如: ivm859mg_9dl74lu - Mark N Hopgood

10

一个非常简短的函数可以为您提供唯一的ID:

var uid = (function(){var id=0;return function(){if(arguments[0]===0)id=0;return id++;}})();

alert(uid());


4
如果您恰巧在页面上已经有下一个ID元素,则会失败。 - Michael

9
作为回复 @scott 的信息: 有时候JS运行速度非常快...所以...
var uniqueId = null,
    getUniqueName = function(prefix) {
        if (!uniqueId) uniqueId = (new Date()).getTime();
        return (prefix || 'id') + (uniqueId++);
    };

6
除非我错了,否则这只会检查重复一次? - James P.
2
它不是检查重复项,而是递增最后一个数字值。 - Michael Paulukonis
2
顺便提一下,如果您立即设置了初始的 uniqueId,则不需要该条件。 - Yanick Rochon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接