Array.from
cerca prima di invocare l'iteratore dell'argomento se ne ha uno e le stringhe hanno iteratori, quindi invoca String.prototype[Symbol.iterator]
, quindi cerchiamo di capire come funziona il metodo prototipo. È descritto nelle specifiche qui :
- Let O be? RequireObjectCoercible (questo valore).
- Facciamo ? ToString (O).
- Restituisce CreateStringIterator (S).
Alzare lo sguardo alla CreateStringIterator
fine ti porta a 21.1.5.2.1 %StringIteratorPrototype%.next ( )
, che fa:
- Lascia che cp sia! CodePointAt (s, position).
- Lascia che resultString sia il valore String che contiene cp. [[CodeUnitCount]] unità di codice consecutive da s che iniziano con l'unità di codice in posizione indice.
- Impostare O. [[StringNextIndex]] su position + cp. [[CodeUnitCount]].
- Restituisce CreateIterResultObject (resultString, false).
Questo CodeUnitCount
è ciò che ti interessa. Questo numero proviene da CodePointAt :
- Sia prima l'unità di codice nella posizione dell'indice all'interno della stringa.
- Sia cp il punto di codice il cui valore numerico è quello del primo.
Se il primo non è un surrogato principale o un surrogato finale, allora
un. Restituisce il record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }
.
Se il primo è un surrogato finale o posizione + 1 = dimensione, allora
a. Restituire il record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Sia secondo l'unità di codice nella posizione di indice + 1 all'interno della stringa.
Se il secondo non è un surrogato finale, allora
un. Restituisce il record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Impostare cp su! UTF16DecodeSurrogatePair (primo, secondo).
Restituisce il record { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }
.
Quindi, quando si scorre su una stringa con Array.from
, restituisce CodeUnitCount di 2 solo quando il carattere in questione è l'inizio di una coppia surrogata. I personaggi che vengono interpretati come coppie surrogate sono descritti qui :
Tali operazioni applicano un trattamento speciale a ogni unità di codice con un valore numerico compreso tra 0xD800 e 0xDBFF (definito dallo standard Unicode come surrogato principale , o più formalmente come unità di codice surrogato elevato) e ogni unità di codice con un valore numerico nell'intervallo compreso tra 0xDC00 e 0xDFFF (definito come surrogato finale, o più formalmente come unità di codice surrogato basso) utilizzando le seguenti regole ..:
षि
non è una coppia surrogata:
console.log('षि'.charCodeAt()); // First character code: 2359, or 0x937
console.log('षि'.charCodeAt(1)); // Second character code: 2367, or 0x93F
Ma 👍
i personaggi sono:
console.log('👍'.charCodeAt()); // 55357, or 0xD83D
console.log('👍'.charCodeAt(1)); // 56397, or 0xDC4D
Il primo codice carattere di '👍'
è, in esadecimale, D83D, che si trova nel raggio di 0xD800 to 0xDBFF
surrogati principali. Al contrario, il primo codice carattere di 'षि'
è molto più basso e non lo è. Quindi 'षि'
viene diviso, ma '👍'
non lo fa.
षि
è composto da due caratteri separati: ष
, Devanagari Lettera Ssa , e ि
, Devanagari vocale I . Quando si trovano uno accanto all'altro in questo ordine, si combinano graficamente in un singolo personaggio visivamente, nonostante siano composti da due personaggi separati.
Al contrario, i codici dei caratteri hanno senso 👍
solo se uniti come un unico glifo. Se provi a usare una stringa con uno dei due punti di codice senza l'altro, otterrai un simbolo senza senso:
console.log('👍'[0]);
console.log('👍'[1]);