Array.from
essaie d'abord d'appeler l'itérateur de l'argument s'il en a un, et les chaînes ont des itérateurs, donc il invoque String.prototype[Symbol.iterator]
, alors regardons comment fonctionne la méthode prototype. Il est décrit dans la spécification ici :
- Soit O? RequireObjectCoercible (cette valeur).
- Soyons ? ToString (O).
- Renvoie CreateStringIterator (S).
La recherche vous CreateStringIterator
amène finalement à 21.1.5.2.1 %StringIteratorPrototype%.next ( )
, ce qui:
- Que cp soit! CodePointAt (s, position).
- Soit resultString la valeur de chaîne contenant cp. [[CodeUnitCount]] unités de code consécutives de s commençant par l'unité de code à la position d'index.
- Définissez O. [[StringNextIndex]] sur position + cp. [[CodeUnitCount]].
- Renvoie CreateIterResultObject (resultString, false).
C'est CodeUnitCount
ce qui vous intéresse. Ce numéro provient de CodePointAt :
- Soit d'abord l'unité de code à la position d'index dans la chaîne.
- Soit cp le point de code dont la valeur numérique est celle du premier.
Si le premier n'est pas un substitut principal ou un substitut de fuite, alors
une. Renvoyez le dossier { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }
.
Si le premier est un substitut de fin ou une position + 1 = taille, alors
a.Retournez l'enregistrement { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Soit en second lieu l'unité de code à la position d'index + 1 dans la chaîne.
Si le second n'est pas un substitut de fuite, alors
une. Renvoyez le dossier { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Réglez cp sur! UTF16DecodeSurrogatePair (premier, deuxième).
Renvoyez le dossier { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }
.
Ainsi, lors de l'itération sur une chaîne avec Array.from
, il renvoie un CodeUnitCount de 2 uniquement lorsque le caractère en question est le début d'une paire de substitution. Les caractères qui sont interprétés comme des paires de substitution sont décrits ici :
De telles opérations appliquent un traitement spécial à chaque unité de code avec une valeur numérique dans la plage inclusive 0xD800 à 0xDBFF (définie par la norme Unicode comme substitut principal , ou plus formellement comme unité de code à substitution élevée) et à chaque unité de code avec une valeur numérique dans la plage inclusive 0xDC00 à 0xDFFF (défini comme un substitut de fin, ou plus formellement comme une unité de code à faible substitution) en utilisant les règles suivantes ..:
षि
n'est pas une paire de substitution:
console.log('षि'.charCodeAt()); // First character code: 2359, or 0x937
console.log('षि'.charCodeAt(1)); // Second character code: 2367, or 0x93F
Mais 👍
les personnages de sont:
console.log('👍'.charCodeAt()); // 55357, or 0xD83D
console.log('👍'.charCodeAt(1)); // 56397, or 0xDC4D
Le premier code de caractère de '👍'
est, en hexadécimal, D83D, qui est dans la gamme 0xD800 to 0xDBFF
des principaux substituts. En revanche, le premier code de caractère de 'षि'
est beaucoup plus bas, et ne l'est pas. Alors le'षि'
se sépare, mais '👍'
ne le fait pas.
षि
est composé de deux caractères distincts: ष
, Lettre Devanagari Ssa , et ि
, Devanagari Voyelle Connectez - je . Lorsqu'ils sont côte à côte dans cet ordre, ils sont combinés graphiquement en un seul caractère visuellement, bien qu'ils soient composés de deux caractères distincts.
En revanche, les codes de caractère 👍
n'ont de sens que lorsqu'ils sont ensemble comme un seul glyphe. Si vous essayez d'utiliser une chaîne avec l'un des points de code sans l'autre, vous obtiendrez un symbole non-sens:
console.log('👍'[0]);
console.log('👍'[1]);