我在现有的关于星体层代码点或国际化问题的答案中没有看到任何提及。“大写字母”在使用给定脚本的每种语言中的含义并不相同。_起初,我没有看到任何解决星体层代码点相关问题的答案。有一个(https://stackoverflow.com/a/45224904/1631952),但它有点埋了(我想这一个会是这样的!)_---大多数提议的功能如下所示:函数大写首字母(str){return str[0].toUpperCase()+str.slice(1);}然而,一些大小写字符不在BMP(基本多语言平面,代码点U+0到U+FFFF)范围内。以Deseret文本为例:大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉"); // "𐐶𐐲𐑌𐐼𐐲𐑉"这里的第一个字符无法大写,因为字符串的数组索引属性不访问“字符”或代码点*。他们访问UTF-16代码单元。切片时也是如此,索引值指向代码单元。UTF-16代码单元正好是1:1,USV代码点在两个范围内,即U+0到U+D7FF和U+E000到U+FFFF。大多数大小写字符都属于这两个范围,但不是全部。从ES2015开始,处理这个问题变得更容易了`String.prototype[@@iterator]`生成与代码点\*\*对应的字符串。例如,我们可以这样做:函数大写FirstLetter([first,…rest]){return[first.toUpperCase(),…rest].join('');}大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"对于较长的字符串,这可能不是很有效\*\*\*——我们实际上不需要迭代余数。我们可以使用`String.prototype.codePointAt`来获得第一个(可能的)字母,但我们仍然需要确定切片应该从哪里开始。避免迭代余数的一种方法是测试第一个码点是否在BMP之外;如果不是,切片从1开始,如果是,切片从2开始。函数大写首字母(str){const firstCP=str.codePointAt(0);常量索引=第一个CP>0xFFFF?2 : 1;return String.fromCodePoint(firstCP).toUpperCase()+str.slice(index);}大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"_您可以使用位数学而不是“>0xFFFF”,但这样可能更容易理解,而且两者都可以实现相同的目的_如果必要的话,我们也可以在ES5及以下版本中进一步完善这个逻辑。ES5中没有用于处理代码点的内部方法,因此我们必须手动测试第一个代码单元是否是代理:函数大写首字母(str){var firstCodeUnit=字符串[0];if(firstCodeUnit<'\uD800'||firstCode Unit>'\uDFFF'){return str[0].toUpperCase()+str.slice(1);}return str.slice(0,2).toUpperCase()+str.slices(2);}大写首字母(“𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"一开始我还提到了国际化的考虑。其中一些很难解释,因为它们不仅需要了解所使用的语言,还可能需要了解该语言中单词的特定知识。例如,爱尔兰有向图“mb”在单词开头大写为“mb”。另一个例子,德语eszett,从不以单词(afaik)开头,但仍然有助于说明这个问题。小写的eszett(“ß”)大写为“SS”,但“SS”可以小写为“ࢹ”或“SS”-您需要具备德语的课外知识才能知道哪一个是正确的!这类问题中最著名的例子可能是土耳其语。在土耳其语拉丁语中,i的大写形式是is,而i的小写形式是In——它们是两个不同的字母。幸运的是,我们确实有办法解释这一点:函数大写FirstLetter([first,…rest],locale){return[first.toLocaleUpperCase(locale),…rest].join('');}大写首字母(“意大利”,“en”)//“意大利”大写首字母(“italya”,“tr”)//“伊塔利亚”在浏览器中,用户最喜欢的语言标记由`navigator.language`表示,在`navigor.languages`中可以找到一个按优先顺序排列的列表,并且在多语言文档中可以(通常)使用`Object(element.locestimate('[lang]')).lang||YOUR_DEFAULT_HERE`获得给定DOM元素的语言。在ES2018中引入的支持RegExp中Unicode属性字符类的代理中,我们可以通过直接表示我们感兴趣的字符来进一步清理内容:函数capitalieFirstLetter(str,locale=navigator.language){return str.replace(/^\p{CWU}/u,char=>char.toLocaleUpperCase(locale));}这可以稍作调整,以处理字符串中多个单词的大写,并且具有相当好的准确性。`CWU`或[Changes_When_Uppercassed](https://unicode.org/reports/tr44/#CWU)character属性匹配所有代码点,当大写时,这些代码点会更改。我们可以用像荷兰语[ij]这样的带标题的双连字符来试试(https://en.wikipedia.org/wiki/IJ(英文)_(有向图),例如:大写首字母(“ijsselmeer”);//“塞尔米尔”在撰写本文时(2020年2月),Firefox/Spidermonkey尚未实现过去两年引入的任何RegExp功能。您可以在[Kangax-compat表]中检查此功能的当前状态(http://kangax.github.io/compat-table/es2016plus/#test-RegExp_Unicode_Property_Escapes)。Babel能够编译RegExp文本,并将其属性引用到等效模式,但要注意,生成的代码可能非常庞大。---问这个问题的人很可能与Deseret资本化或国际化无关。但是,意识到这些问题是件好事,因为即使这些问题目前并不令人担忧,最终你也很有可能会遇到它们。它们不是“边缘”案例,或者更确切地说,它们不是按定义的边缘案例——总之,在整个国家,大多数人都说土耳其语,将代码单元与代码点混为一谈是一个相当常见的错误来源(尤其是关于表情符号)。字符串和语言都很复杂!---_\*UTF-16/UCS2的代码单元在某种意义上也是Unicode代码点,例如U+D800在技术上是一个代码点,但这不是它在这里的“意思”。。。某种程度上。。。尽管它变得相当模糊。但是,代理项肯定不是USV(Unicode标量值)__\*\*尽管如果代理代码单元是“孤立的”,即不是逻辑对的一部分,您仍然可以在这里获得代理__\*\*\*也许吧。我还没有测试过它。除非你确定资本化是一个有意义的瓶颈,否则我可能不会费劲——选择你认为最清晰易读的内容__\*\*\*\*这样的函数可能希望测试第一个和第二个代码单元,而不是只测试第一个,因为第一个单元可能是孤立的代理。例如,输入“\uD800x”将X as-is大写,这可能是预期的,也可能不是预期的_