Firefox 27(Nightly) における新たな String.prototype["@@iterator"]

ちょいと面白いものが実装されて、String.prototype["@@iterator"]がアップデートされてた。

"@@iterator" というのは、ECMAScript 6th におけるイテレータとなるメソッドで、最近注目のジェネレータオブジェクトを返す。*1

で、このジェネレータオブジェクトのnextメソッドが、従来であればインデックス値に沿って順に値を返していたのだが、これからはUnicodeポイントに沿って値を返すようになる。UTF-16 においてサロゲートペアとなるような文字は従来は2文字として扱われていたのが、Unicodeポイントとして1文字として扱われるようになるのだ。

変更されたのはあくまでジェネレータ部分であって、インデックス値の扱いは変わっていないし、length プロパティも従来通りUTF-16換算なので注意。*2

文字 コードポイント UTF-16
𠀋 U+2000B \uD840\uDC0B
𡈽 U+2123D \uD844\uDE3D
𡌛 U+2131B \uD844\uDF18

上記の文字を例にしてみると
あ...orz はてなダイアリーだと &#... に変換されちゃうのね...orz 𠀋=𠀋 𡈽=𡈽 𡌛=𡌛 です。

var str = "𠀋𡈽𡌛"

console.log("length", str.length);
console.log("count", [...str].length);

for (var c of str) {
  console.log(c, c.length);
}

これが、以下のように出ることになる。

"length" 6
"count" 3
"𠀋" 2
"𡈽" 2
"𡌛" 2

今まではサロゲートペアまで考慮した文字数のカウントは面倒だったが、上記コードのように[...str].lengthと簡単に書ける。

2014-01-06 追記

まだ実装されてないけど、ものかの » Unicodeの特殊な文字 “結合文字列”にあるようなものがると駄目になるので、String.prototype.normalize で正規化する方が良さそう。

よって、もう少しきちんとカウントするには [...str.normalize()].lengthが良さそう。

*1:本来なら Symbol という型のプロパティ(文字列ではない)であるが、FirefoxJavaScript エンジンには Symbols が実装されていないので、文字列プロパティとして存在している。

*2:ここの部分に変更が入ることはないと思う。Break the web って怒られちゃう