Array.from
đầu tiên cố gắng gọi trình lặp của đối số nếu nó có một và các chuỗi có các trình lặp, vì vậy nó gọi String.prototype[Symbol.iterator]
, vì vậy hãy tìm hiểu cách thức hoạt động của phương thức nguyên mẫu. Nó được mô tả trong đặc tả ở đây :
- Cho O là? RequireObjectCoercible (giá trị này).
- Cho S là? ToString (O).
- Trả về CreatStringIterator (S).
Nhìn lên CreateStringIterator
cuối cùng sẽ đưa bạn đến 21.1.5.2.1 %StringIteratorPrototype%.next ( )
, mà:
- Hãy để cp được! CodePointAt (s, vị trí).
- Đặt resultString là giá trị Chuỗi chứa cp. [[CodeUnitCount]] các đơn vị mã liên tiếp từ s bắt đầu với đơn vị mã ở vị trí chỉ mục.
- Đặt O. [[StringNext Index]] thành vị trí + cp. [[CodeUnitCount]].
- Trả về CreatIterResultObject (resultString, false).
Đây CodeUnitCount
là những gì bạn quan tâm. Số này đến từ CodePointAt :
- Trước tiên hãy là đơn vị mã ở vị trí chỉ mục trong chuỗi.
- Đặt cp là điểm mã có giá trị số là giá trị đầu tiên.
Nếu trước tiên không phải là người thay thế hàng đầu hoặc người thay thế
a. Trả lại hồ sơ { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }
.
Nếu đầu tiên là một đại diện thay thế hoặc vị trí + 1 = kích thước, thì
a.Quay lại bản ghi { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Đặt thứ hai là đơn vị mã ở vị trí chỉ mục + 1 trong chuỗi.
Nếu thứ hai không phải là một đại diện thay thế, thì
a. Trả lại hồ sơ { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }
.
Đặt cp thành! UTF16DecodeSurrogatePair (thứ nhất, thứ hai).
Trả lại hồ sơ { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }
.
Vì vậy, khi lặp qua một chuỗi với Array.from
, nó chỉ trả về CodeUnitCount bằng 2 khi ký tự trong câu hỏi là bắt đầu của một cặp thay thế. Các ký tự được hiểu là cặp thay thế được mô tả ở đây :
Các hoạt động này áp dụng xử lý đặc biệt cho mọi đơn vị mã có giá trị số trong phạm vi bao gồm 0xD800 đến 0xDBFF (được xác định bởi Tiêu chuẩn Unicode là đại diện thay thế hàng đầu , hoặc chính thức hơn là đơn vị mã thay thế cao) và mọi đơn vị mã có giá trị số trong phạm vi bao gồm 0xDC00 đến 0xDFFF (được định nghĩa là đại diện thay thế hoặc chính thức hơn là một đơn vị mã thay thế thấp) sử dụng các quy tắc sau ..:
षि
không phải là một cặp thay thế:
console.log('षि'.charCodeAt()); // First character code: 2359, or 0x937
console.log('षि'.charCodeAt(1)); // Second character code: 2367, or 0x93F
Nhưng 👍
các nhân vật là:
console.log('👍'.charCodeAt()); // 55357, or 0xD83D
console.log('👍'.charCodeAt(1)); // 56397, or 0xDC4D
Mã ký tự đầu tiên '👍'
là, trong hex, D83D, nằm trong phạm vi của 0xD800 to 0xDBFF
các đại diện thay thế hàng đầu. Ngược lại, mã ký tự đầu tiên của 'षि'
thấp hơn nhiều, và không. Vì vậy, 'षि'
được tách ra, nhưng'👍'
không.
षि
bao gồm hai nhân vật riêng biệt: ष
, Devanagari Thư SSA , và ि
, Devanagari nguyên âm Đăng tôi . Khi nằm cạnh nhau theo thứ tự này, chúng được kết hợp đồ họa thành một ký tự trực quan, mặc dù được tạo thành từ hai ký tự riêng biệt.
Ngược lại, mã ký tự 👍
chỉ có ý nghĩa khi cùng nhau dưới dạng một glyph. Nếu bạn cố gắng sử dụng một chuỗi có điểm mã mà không có mã khác, bạn sẽ nhận được một biểu tượng vô nghĩa:
console.log('👍'[0]);
console.log('👍'[1]);