TLDR
Kiểu ép buộc hoặc chuyển đổi kiểu ngầm, cho phép nhập yếu và được sử dụng trong JavaScript. Hầu hết các toán tử (với ngoại lệ đáng chú ý là các toán tử bình đẳng nghiêm ngặt ===và !==), và các hoạt động kiểm tra giá trị (ví dụ. if(value)...), Sẽ ép buộc các giá trị được cung cấp cho chúng, nếu các loại giá trị đó không tương thích ngay với phép toán.
Cơ chế chính xác được sử dụng để ép buộc một giá trị phụ thuộc vào biểu thức được đánh giá. Trong câu hỏi, toán tử bổ sung đang được sử dụng.
Toán tử bổ sung trước tiên sẽ đảm bảo cả hai toán hạng là nguyên thủy, trong trường hợp này, liên quan đến việc gọi valueOfphương thức. Các toStringphương pháp không được gọi trong trường hợp này vì ghi đè valueOfphương pháp trên đối tượng xtrả về một giá trị nguyên thủy.
Sau đó, vì một trong các toán hạng trong câu hỏi là một chuỗi, nên cả hai toán hạng đều được chuyển đổi thành chuỗi. Quá trình này sử dụng thao tác trừu tượng, hoạt động nội bộ ToString(lưu ý: viết hoa) và khác với toStringphương thức trên đối tượng (hoặc chuỗi nguyên mẫu của nó).
Cuối cùng, các chuỗi kết quả được nối với nhau.
Chi tiết
Trên nguyên mẫu của mọi đối tượng hàm tạo tương ứng với mọi loại ngôn ngữ trong JavaScript (ví dụ: Number, BigInt, String, Boolean, Symbol và Object), có hai phương thức: valueOfvà toString.
Mục đích của valueOflà lấy giá trị nguyên thủy được liên kết với một đối tượng (nếu nó có). Nếu một đối tượng không có giá trị nguyên thủy cơ bản, thì đối tượng đó chỉ được trả về.
Nếu valueOfđược gọi chống lại một nguyên thủy, thì nguyên thủy sẽ được tự động đóng hộp theo cách thông thường và giá trị nguyên thủy cơ bản được trả về. Lưu ý rằng đối với các chuỗi, giá trị nguyên thủy cơ bản (tức là giá trị được trả về bởi valueOf) chính là biểu diễn chuỗi.
Đoạn mã sau đây cho thấy rằng valueOfphương thức trả về giá trị nguyên thủy cơ bản từ một đối tượng trình bao bọc và nó cho thấy cách các cá thể đối tượng chưa được sửa đổi không tương ứng với nguyên thủy, không có giá trị nguyên thủy để trả về, vì vậy chúng chỉ tự trả về.
console.log(typeof new Boolean(true)) // 'object'
console.log(typeof new Boolean(true).valueOf()) // 'boolean'
console.log(({}).valueOf()) // {} (no primitive value to return)
Mặt khác, mục đích của toStringnó là trả về một biểu diễn chuỗi của một đối tượng.
Ví dụ:
console.log({}.toString()) // '[object Object]'
console.log(new Number(1).toString()) // '1'
Đối với hầu hết các thao tác, JavaScript sẽ cố gắng chuyển đổi một cách âm thầm một hoặc nhiều toán hạng thành kiểu bắt buộc. Hành vi này được chọn để làm cho JavaScript dễ sử dụng hơn. JavaScript ban đầu không có ngoại lệ và điều này cũng có thể đóng một vai trò trong quyết định thiết kế này. Kiểu chuyển đổi kiểu ngầm này được gọi là kiểu ép buộc và nó là cơ sở của hệ thống kiểu lỏng lẻo (yếu) của JavaScript. Các quy tắc phức tạp đằng sau hành vi này nhằm chuyển sự phức tạp của việc đánh máy vào chính ngôn ngữ và ra khỏi mã của bạn.
Trong quá trình cưỡng chế, có hai phương thức chuyển đổi có thể xảy ra:
- Chuyển đổi một đối tượng thành nguyên thủy (có thể liên quan đến chính chuyển đổi kiểu) và
- Chuyển đổi trực tiếp với một trường hợp loại hình cụ thể, sử dụng một đối tượng hàm constructor của một trong những loại nguyên thủy (tức là.
Number(), Boolean(), String()Vv)
Chuyển đổi sang nguyên thủy
Khi cố gắng chuyển đổi các kiểu không nguyên thủy thành các kiểu nguyên thủy sẽ được vận hành, thao tác trừu tượng ToPrimitiveđược gọi với một "gợi ý" tùy chọn là 'số' hoặc 'chuỗi'. Nếu gợi ý bị bỏ qua, gợi ý mặc định là 'số' (trừ khi @@toPrimitivephương thức đã được ghi đè). Nếu gợi ý là 'chuỗi', thì toStringlần đầu tiên được thử và valueOflần thứ hai nếu toStringkhông trả về giá trị nguyên thủy. Khác, ngược lại. Gợi ý phụ thuộc vào thao tác yêu cầu chuyển đổi.
Toán tử bổ sung cung cấp không có gợi ý, vì vậy hãy valueOfthử trước. Toán tử phép trừ cung cấp một gợi ý về 'số', vì vậy valueOfsẽ được thử trước. Các tình huống duy nhất tôi có thể tìm thấy trong thông số kỹ thuật mà gợi ý là 'chuỗi' là:
Object#toString
- Hoạt động trừu tượng
ToPropertyKey, chuyển đổi một đối số thành một giá trị có thể được sử dụng làm khóa thuộc tính
Chuyển đổi loại trực tiếp
Mỗi nhà điều hành có các quy tắc riêng để hoàn thành hoạt động của họ. Toán tử cộng đầu tiên sẽ sử dụng ToPrimitiveđể đảm bảo mỗi toán hạng là một nguyên thủy; sau đó, nếu một trong hai toán hạng là một chuỗi, thì nó sẽ cố ý gọi phép toán trừu tượng ToStringtrên mỗi toán hạng, để thực hiện hành vi nối chuỗi mà chúng ta mong đợi với các chuỗi. Nếu sau ToPrimitivebước, cả hai toán hạng không phải là chuỗi, thì phép cộng số học được thực hiện.
Không giống như phép cộng, toán tử phép trừ không có hành vi quá tải và do đó sẽ gọi toNumerictrên mỗi toán hạng đã chuyển đổi chúng đầu tiên thành nguyên thủy bằng cách sử dụng ToPrimitive.
Vì thế:
1 + 1 // 2
'1' + 1 // '11' Both already primitives, RHS converted to string, '1' + '1', '11'
1 + [2] // '12' [2].valueOf() returns an object, so `toString` fallback is used, 1 + String([2]), '1' + '2', 12
1 + {} // '1[object Object]' {}.valueOf() is not a primitive, so toString fallback used, String(1) + String({}), '1' + '[object Object]', '1[object Object]'
2 - {} // NaN {}.valueOf() is not a primitive, so toString fallback used => 2 - Number('[object Object]'), NaN
+'a' // NaN `ToPrimitive` passed 'number' hint), Number('a'), NaN
+'' // 0 `ToPrimitive` passed 'number' hint), Number(''), 0
+'-1' // -1 `ToPrimitive` passed 'number' hint), Number('-1'), -1
+{} // NaN `ToPrimitive` passed 'number' hint', `valueOf` returns an object, so falls back to `toString`, Number('[Object object]'), NaN
1 + 'a' // '1a' Both are primitives, one is a string, String(1) + 'a'
1 + {} // '1[object Object]' One primitive, one object, `ToPrimitive` passed no hint, meaning conversion to string will occur, one of the operands is now a string, String(1) + String({}), `1[object Object]`
[] + [] // '' Two objects, `ToPrimitive` passed no hint, String([]) + String([]), '' (empty string)
1 - 'a' // NaN Both are primitives, one is a string, `ToPrimitive` passed 'number' hint, 1-Number('a'), 1-NaN, NaN
1 - {} // NaN One primitive, one is an object, `ToPrimitive` passed 'number' hint, `valueOf` returns object, so falls back to `toString`, 1-Number([object Object]), 1-NaN, NaN
[] - [] // 0 Two objects, `ToPrimitive` passed 'number' hint => `valueOf` returns array instance, so falls back to `toString`, Number('')-Number(''), 0-0, 0
Lưu ý rằng Dateđối tượng nội tại là duy nhất, trong đó nó là đối tượng nội tại duy nhất ghi đè @@toPrimitivephương thức mặc định , trong đó gợi ý mặc định được cho là 'chuỗi' (thay vì 'số'). Lý do của việc này là Datetheo mặc định, các phiên bản dịch sang chuỗi có thể đọc được, thay vì giá trị số của chúng, để thuận tiện cho người lập trình. Bạn có thể ghi đè @@toPrimitivecác đối tượng của riêng mình bằng cách sử dụng Symbol.toPrimitive.
Lưới sau đây hiển thị kết quả cưỡng chế cho toán tử bình đẳng trừu tượng ( ==) ( nguồn ):

Xem cũng .
window.console.log (x);hoặcalert (x);?