Array.from
pertama-tama mencoba untuk memanggil iterator dari argumen jika ada, dan string memang memiliki iterator, jadi ia memanggil String.prototype[Symbol.iterator]
, jadi mari kita mencari cara kerja metode prototipe. Ini dijelaskan dalam spesifikasi di sini :
- Biarkan O menjadi? RequireObjectCoercible (nilai ini).
- Biarkan S? ToString (O).
- Kembali CreateStringIterator (S).
Melihat ke atas pada CreateStringIterator
akhirnya membawa Anda ke 21.1.5.2.1 %StringIteratorPrototype%.next ( )
, yang artinya:
- Biarkan cp! CodePointAt (s, posisi).
- Biarkan resultString menjadi nilai String yang berisi cp. [[CodeUnitCount]] unit kode berturut-turut dari awal dengan unit kode pada posisi indeks.
- Set O. [[StringNextIndex]] ke posisi + cp. [[CodeUnitCount]].
- Kembalikan CreateIterResultObject (resultString, false).
Inilah CodeUnitCount
yang Anda minati. Nomor ini berasal dari CodePointAt :
- Biarkan dulu menjadi unit kode pada posisi indeks dalam string.
- Biarkan cp menjadi titik kode yang nilai numeriknya lebih dulu.
Jika pertama bukan pengganti terkemuka atau pengganti tambahan, maka
Sebuah. Kembalikan Catatan { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }
.
Jika pertama adalah trailing surrogate atau posisi +1 = ukuran, maka
Kembalikan Catatan { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Biarkan kedua menjadi unit kode pada posisi indeks + 1 dalam string.
Jika yang kedua bukan pengganti tambahan, maka
Sebuah. Kembalikan Catatan { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Setel ke! UTF16DecodeSurrogatePair (pertama, kedua).
Kembalikan Catatan { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }
.
Jadi, ketika iterasi dengan string Array.from
, ia mengembalikan CodeUnitCount 2 hanya ketika karakter yang dimaksud adalah awal dari pasangan pengganti. Karakter yang ditafsirkan sebagai pasangan pengganti dijelaskan di sini :
Operasi tersebut menerapkan perlakuan khusus untuk setiap unit kode dengan nilai numerik dalam rentang inklusif 0xD800 hingga 0xDBFF (didefinisikan oleh Standar Unicode sebagai pengganti utama , atau lebih resmi sebagai unit kode pengganti tinggi) dan setiap unit kode dengan nilai numerik dalam rentang inklusif 0xDC00 hingga 0xDFFF (didefinisikan sebagai pengganti trailing, atau lebih formal sebagai unit kode pengganti rendah) menggunakan aturan berikut ..:
षि
bukan pasangan pengganti:
console.log('षि'.charCodeAt()); // First character code: 2359, or 0x937
console.log('षि'.charCodeAt(1)); // Second character code: 2367, or 0x93F
Tapi 👍
karakternya adalah:
console.log('👍'.charCodeAt()); // 55357, or 0xD83D
console.log('👍'.charCodeAt(1)); // 56397, or 0xDC4D
Kode karakter pertama '👍'
adalah, dalam hex, D83D, yang berada dalam jangkauan 0xD800 to 0xDBFF
surrogate terkemuka. Sebaliknya, kode karakter pertama 'षि'
jauh lebih rendah, dan tidak. Jadi 'षि'
mendapat terpisah, tetapi '👍'
tidak.
षि
terdiri dari dua karakter yang terpisah: ष
, Devanagari Surat Ssa , dan ि
, Devanagari Vokal Sign saya . Ketika bersebelahan dalam urutan ini, mereka digabungkan secara grafis menjadi satu karakter secara visual, meskipun terdiri dari dua karakter yang terpisah.
Sebaliknya, kode karakter 👍
hanya masuk akal ketika bersama sebagai mesin terbang tunggal. Jika Anda mencoba menggunakan string dengan salah satu titik kode tanpa yang lain, Anda akan mendapatkan simbol omong kosong:
console.log('👍'[0]);
console.log('👍'[1]);