bởi Alexey Samoshkin [Chỉnh sửa 2/5/2018]: Bài đăng này hiện có sẵn bằng tiếng Nga. Claps to Serj Bulavyk vì những nỗ lực của mình.: This post is now
available in Russian. Claps to Serj Bulavyk for his efforts. Loại ép buộc là quá trình chuyển đổi giá trị từ loại này sang loại khác [chẳng hạn như chuỗi sang số, đối tượng thành boolean, v.v.]. Bất kỳ loại nào, có thể là nguyên thủy hoặc một đối tượng, là một đối tượng hợp lệ cho sự ép buộc loại. Để nhớ lại, các nguyên thủy là: số, chuỗi, boolean, null, ký hiệu + không xác định [được thêm vào trong ES6]. is the process of converting value from one
type to another [such as string to number, object to boolean, and so on]. Any type, be it primitive or an object, is a valid subject for type coercion. To recall, primitives are: number, string, boolean, null, undefined + Symbol [added in ES6]. Như một ví dụ về sự ép buộc loại trong thực tế, hãy nhìn vào bảng so sánh JavaScript, cho thấy cách thức của người vận hành bình đẳng lỏng lẻo hoạt động cho các loại Biết động cơ của bạn
2 và String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
3 khác nhau. Ma trận này có vẻ đáng sợ do sự ép buộc loại ngầm mà nhà điều hành String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 thực hiện, và nó khó có thể nhớ tất cả các kết hợp đó. Và bạn không phải làm điều đó - chỉ cần học các nguyên tắc ép buộc loại cơ bản.String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
Bài viết này đi sâu về cách ép buộc loại hoạt động trong JavaScript và sẽ giúp bạn có kiến thức cần thiết, vì vậy bạn có thể cảm thấy tự tin giải thích những gì các biểu thức sau đây được tính toán. Đến cuối bài viết, tôi sẽ hiển thị câu trả lời và giải thích chúng.
true + false
12 / "6"
"number" + 15 + 3
15 + 3 + "number"
[1] > null
"foo" + + "bar"
'true' == true
false == 'false'
null == ''
!!"false" == !!"true"
[‘x’] == ‘x’
[] + null + 1
[1,2,3] == [1,2,3]
{}+[]+{}+[1]
!+[]+[]+![]
new Date[0] - 0
new Date[0] + 0
Vâng, danh sách này có đầy đủ những điều khá ngớ ngẩn bạn có thể làm với tư cách là một nhà phát triển. Trong 90% các trường hợp sử dụng, tốt hơn là tránh bị ép buộc loại ngầm. Hãy coi danh sách này là một bài tập học tập để kiểm tra kiến thức của bạn về cách thức cưỡng chế loại hoạt động. Nếu bạn chán, bạn có thể tìm thấy nhiều ví dụ hơn về wtfjs.com.
Nhân tiện, đôi khi bạn có thể phải đối mặt với những câu hỏi như vậy trong cuộc phỏng vấn cho vị trí nhà phát triển JavaScript. Vì vậy, tiếp tục đọc?
In ngầm so với sự ép buộc rõ ràng
Loại cưỡng chế có thể rõ ràng và tiềm ẩn.
Khi một nhà phát triển thể hiện ý định chuyển đổi giữa các loại bằng cách viết mã thích hợp, như
String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
5, nó được gọi là ép buộc loại rõ ràng [hoặc loại đúc].explicit type coercion [or type casting].Vì JavaScript là ngôn ngữ được gõ yếu, các giá trị cũng có thể được chuyển đổi giữa các loại khác nhau một cách tự động và nó được gọi là ép buộc loại ngầm. Nó thường xảy ra khi bạn áp dụng các toán tử vào các giá trị của các loại khác nhau, như ____36,
String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
7, String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
8 hoặc nó có thể được kích hoạt bởi bối cảnh xung quanh, như với String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
9, trong đó Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
0 bị ép buộc để boolean.implicit
type coercion. It usually happens when you apply operators to values of different types, likeString[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
6, String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
7, String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
8, or it can be triggered by the surrounding context, like with String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
9, where Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
0 is coerced to boolean.Một toán tử không kích hoạt sự ép buộc loại ngầm là
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
1, được gọi là toán tử bình đẳng nghiêm ngặt. Mặt khác, toán tử bình đẳng lỏng lẻo String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 thực hiện cả so sánh và ép buộc loại nếu cần.Sự ép buộc loại ẩn là một thanh kiếm hai cạnh: nó là một nguồn thất vọng và khuyết tật tuyệt vời, nhưng cũng là một cơ chế hữu ích cho phép chúng ta viết ít mã hơn mà không mất khả năng đọc.
Ba loại chuyển đổi
Quy tắc đầu tiên cần biết là chỉ có ba loại chuyển đổi trong JavaScript:
- để chuỗi
- để boolean
- đến số
Thứ hai, logic chuyển đổi cho các nguyên thủy và đối tượng hoạt động khác nhau, nhưng cả nguyên thủy và đối tượng chỉ có thể được chuyển đổi theo ba cách đó.
Hãy bắt đầu với những người nguyên thủy đầu tiên.
Chuyển đổi chuỗi
Để chuyển đổi rõ ràng các giá trị thành một chuỗi, hãy áp dụng hàm
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
3. Sự ép buộc ngầm được kích hoạt bởi toán tử nhị phân Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4, khi bất kỳ toán hạng nào là một chuỗi:String[123] // explicit
123 + '' // implicit
Tất cả các giá trị nguyên thủy được chuyển đổi thành các chuỗi một cách tự nhiên như bạn mong đợi:
String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
Chuyển đổi biểu tượng là một chút khó khăn, bởi vì nó chỉ có thể được chuyển đổi một cách rõ ràng, nhưng không ngầm. Đọc thêm về các quy tắc cưỡng chế
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
5.String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
Chuyển đổi Boolean
Để chuyển đổi một cách rõ ràng một giá trị thành boolean, hãy áp dụng hàm
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
6. Chuyển đổi quan trọng xảy ra trong bối cảnh logic hoặc được kích hoạt bởi các toán tử logic [Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
7 Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
8 Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
9].Implicit conversion happens in logical context, or is triggered by logical operators [
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
7 Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
8 Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
9] .Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
Lưu ý: Các toán tử logic như
7 và Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
8 không chuyển đổi boolean trong nội bộ, nhưng thực sự trả về giá trị của các toán hạng gốc, ngay cả khi chúng không boolean.: Logical operators such as Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
7
and Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
8 do boolean conversions internally, but actually return the value of original operands, even if they are not boolean.// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
Ngay khi chỉ có 2 kết quả chuyển đổi Boolean:
// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
2 hoặc // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
3, nó chỉ dễ nhớ hơn trong danh sách các giá trị giả.Boolean[''] // false
Boolean[0] // false
Boolean[-0] // false
Boolean[NaN] // false
Boolean[null] // false
Boolean[undefined] // false
Boolean[false] // false
Bất kỳ giá trị nào không có trong danh sách đều được chuyển đổi thành
// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
2, bao gồm đối tượng, chức năng, // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
5, // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
6, loại do người dùng xác định, v.v. Biểu tượng là giá trị sự thật. Đối tượng trống và mảng cũng là giá trị sự thật:Boolean[{}] // true
Boolean[[]] // true
Boolean[Symbol[]] // true
!!Symbol[] // true
Boolean[function[] {}] // true
Chuyển đổi số
Để chuyển đổi rõ ràng, chỉ cần áp dụng hàm
// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
7, giống như bạn đã làm với Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
6 và Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
3.Chuyển đổi ngầm là khó khăn, bởi vì nó đã được kích hoạt trong nhiều trường hợp hơn:
- Các toán tử so sánh [
0,Boolean[''] // false Boolean[0] // false Boolean[-0] // false Boolean[NaN] // false Boolean[null] // false Boolean[undefined] // false Boolean[false] // false
1, ________ 62, ________ 63]Boolean[''] // false Boolean[0] // false Boolean[-0] // false Boolean[NaN] // false Boolean[null] // false Boolean[undefined] // false Boolean[false] // false
- Các toán tử bitwise [
4Boolean[''] // false Boolean[0] // false Boolean[-0] // false Boolean[NaN] // false Boolean[null] // false Boolean[undefined] // false Boolean[false] // false
5Boolean[''] // false Boolean[0] // false Boolean[-0] // false Boolean[NaN] // false Boolean[null] // false Boolean[undefined] // false Boolean[false] // false
6Boolean[''] // false Boolean[0] // false Boolean[-0] // false Boolean[NaN] // false Boolean[null] // false Boolean[undefined] // false Boolean[false] // false
7]Boolean[''] // false Boolean[0] // false Boolean[-0] // false Boolean[NaN] // false Boolean[null] // false Boolean[undefined] // false Boolean[false] // false
- toán tử số học [
8Boolean[''] // false Boolean[0] // false Boolean[-0] // false Boolean[NaN] // false Boolean[null] // false Boolean[undefined] // false Boolean[false] // false
4Boolean[2] // explicit if [2] { ... } // implicit due to logical context !!2 // implicit due to logical operator 2 || 'hello' // implicit due to logical operator
0Boolean[{}] // true Boolean[[]] // true Boolean[Symbol[]] // true !!Symbol[] // true Boolean[function[] {}] // true
1Boolean[{}] // true Boolean[[]] // true Boolean[Symbol[]] // true !!Symbol[] // true Boolean[function[] {}] // true
2]. Lưu ý rằng BinaryBoolean[{}] // true Boolean[[]] // true Boolean[Symbol[]] // true !!Symbol[] // true Boolean[function[] {}] // true
4 không kích hoạt chuyển đổi số, khi bất kỳ toán hạng nào là một chuỗi.Boolean[2] // explicit if [2] { ... } // implicit due to logical context !!2 // implicit due to logical operator 2 || 'hello' // implicit due to logical operator
- Nhà điều hành
4Boolean[2] // explicit if [2] { ... } // implicit due to logical context !!2 // implicit due to logical operator 2 || 'hello' // implicit due to logical operator
- toán tử bình đẳng lỏng lẻo
1 [bao gồmString[Symbol['my symbol']] // 'Symbol[my symbol]' '' + Symbol['my symbol'] // TypeError is thrown
6]. Lưu ý rằngBoolean[{}] // true Boolean[[]] // true Boolean[Symbol[]] // true !!Symbol[] // true Boolean[function[] {}] // true
1 không kích hoạt chuyển đổi số khi cả hai toán hạng là chuỗi.String[Symbol['my symbol']] // 'Symbol[my symbol]' '' + Symbol['my symbol'] // TypeError is thrown
Note that
1 does not trigger numeric conversion when both operands are strings.String[Symbol['my symbol']] // 'Symbol[my symbol]' '' + Symbol['my symbol'] // TypeError is thrown
Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
Dưới đây là cách các giá trị nguyên thủy được chuyển đổi thành số:
Number[null] // 0
Number[undefined] // NaN
Number[true] // 1
Number[false] // 0
Number[" 12 "] // 12
Number["-12.34"] // -12.34
Number["\n"] // 0
Number[" 12s "] // NaN
Number[123] // 123
Khi chuyển đổi một chuỗi thành một số, công cụ đầu tiên cắt các ký tự dẫn và kéo theo,
Boolean[{}] // true
Boolean[[]] // true
Boolean[Symbol[]] // true
!!Symbol[] // true
Boolean[function[] {}] // true
8, Boolean[{}] // true
Boolean[[]] // true
Boolean[Symbol[]] // true
!!Symbol[] // true
Boolean[function[] {}] // true
9 ký tự, trả về Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
0 nếu chuỗi được cắt không đại diện cho một số hợp lệ. Nếu chuỗi trống, nó sẽ trả về Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
1.Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
2 và Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
3 được xử lý khác nhau: Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
2 trở thành Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
1, trong khi Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
3 trở thành Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
0.Các biểu tượng không thể được chuyển đổi thành một số không rõ ràng cũng không ngầm. Hơn nữa,
Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
8 bị ném, thay vì âm thầm chuyển đổi thành Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
0, giống như nó xảy ra với Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
3. Xem thêm về các quy tắc chuyển đổi biểu tượng trên MDN.String[123] // explicit
123 + '' // implicit
0Có hai quy tắc đặc biệt cần nhớ:special rules to remember:
- Khi áp dụng
1 lênString[Symbol['my symbol']] // 'Symbol[my symbol]' '' + Symbol['my symbol'] // TypeError is thrown
2 hoặcNumber['123'] // explicit +'123' // implicit 123 != '456' // implicit 4 > '5' // implicit 5/null // implicit true | 0 // implicit
3, chuyển đổi số không xảy ra.Number['123'] // explicit +'123' // implicit 123 != '456' // implicit 4 > '5' // implicit 5/null // implicit true | 0 // implicit
2 chỉ bằng vớiNumber['123'] // explicit +'123' // implicit 123 != '456' // implicit 4 > '5' // implicit 5/null // implicit true | 0 // implicit
2 hoặcNumber['123'] // explicit +'123' // implicit 123 != '456' // implicit 4 > '5' // implicit 5/null // implicit true | 0 // implicit
3 và không bằng bất cứ thứ gì khác.Number['123'] // explicit +'123' // implicit 123 != '456' // implicit 4 > '5' // implicit 5/null // implicit true | 0 // implicit
String[123] // explicit
123 + '' // implicit
12. Nan không bằng bất cứ thứ gì ngay cả chính nó:
String[123] // explicit
123 + '' // implicit
2Loại cưỡng chế cho các đối tượng
Cho đến nay, chúng tôi đã xem xét sự ép buộc loại cho các giá trị nguyên thủy. Điều đó không thú vị lắm.
Khi nói đến các đối tượng và các biểu thức gặp phải động cơ như
Number[null] // 0
Number[undefined] // NaN
Number[true] // 1
Number[false] // 0
Number[" 12 "] // 12
Number["-12.34"] // -12.34
Number["\n"] // 0
Number[" 12s "] // NaN
Number[123] // 123
7, trước tiên nó cần chuyển đổi một đối tượng thành giá trị nguyên thủy, sau đó được chuyển đổi thành loại cuối cùng. Và vẫn chỉ có ba loại chuyển đổi: số, chuỗi và boolean.Trường hợp đơn giản nhất là chuyển đổi Boolean: bất kỳ giá trị không định tuyến nào luôn bị ép buộc thành
// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
2, bất kể đối tượng hay mảng có trống hay không.coerced to
// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
2, no matter if an object or an array is empty or not.Các đối tượng được chuyển đổi thành nguyên thủy thông qua phương thức
Number[null] // 0
Number[undefined] // NaN
Number[true] // 1
Number[false] // 0
Number[" 12 "] // 12
Number["-12.34"] // -12.34
Number["\n"] // 0
Number[" 12s "] // NaN
Number[123] // 123
9 nội bộ, chịu trách nhiệm cho cả chuyển đổi số và chuỗi.Dưới đây là việc triển khai giả của phương thức
Number[null] // 0
Number[undefined] // NaN
Number[true] // 1
Number[false] // 0
Number[" 12 "] // 12
Number["-12.34"] // -12.34
Number["\n"] // 0
Number[" 12s "] // NaN
Number[123] // 123
9:Number[null] // 0
Number[undefined] // NaN
Number[true] // 1
Number[false] // 0
Number[" 12 "] // 12
Number["-12.34"] // -12.34
Number["\n"] // 0
Number[" 12s "] // NaN
Number[123] // 123
9 được truyền với giá trị đầu vào và loại chuyển đổi ưa thích: String[123] // explicit
123 + '' // implicit
02 hoặc String[123] // explicit
123 + '' // implicit
03. String[123] // explicit
123 + '' // implicit
04 là tùy chọn.Cả chuyển đổi số và chuỗi đều sử dụng hai phương thức của đối tượng đầu vào:
String[123] // explicit
123 + '' // implicit
05 và String[123] // explicit
123 + '' // implicit
06. Cả hai phương pháp đều được khai báo trên String[123] // explicit
123 + '' // implicit
07 và do đó có sẵn cho bất kỳ loại dẫn xuất nào, chẳng hạn như // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
6, // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
5, v.v.Nói chung, thuật toán như sau:
- Nếu đầu vào đã là một nguyên thủy, không làm gì và trả lại nó.
2. Gọi
String[123] // explicit
123 + '' // implicit
10, nếu kết quả là nguyên thủy, hãy trả lại.3. Gọi
String[123] // explicit
123 + '' // implicit
11, nếu kết quả là nguyên thủy, hãy trả lại.4. Nếu cả
String[123] // explicit
123 + '' // implicit
10 và String[123] // explicit
123 + '' // implicit
11 không mang lại nguyên thủy, hãy ném Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
8.Chuyển đổi số đầu tiên gọi
String[123] // explicit
123 + '' // implicit
05 [3] với dự phòng với String[123] // explicit
123 + '' // implicit
06 [2]. Chuyển đổi chuỗi thực hiện ngược lại: String[123] // explicit
123 + '' // implicit
06 [2] theo sau là String[123] // explicit
123 + '' // implicit
05 [3].Hầu hết các loại tích hợp không có
String[123] // explicit
123 + '' // implicit
05 hoặc có String[123] // explicit
123 + '' // implicit
05 trả về chính đối tượng String[123] // explicit
123 + '' // implicit
21, do đó, nó đã bỏ qua vì nó không phải là nguyên thủy. Đó là lý do tại sao chuyển đổi số và chuỗi có thể hoạt động giống nhau - cả hai đều gọi String[123] // explicit
123 + '' // implicit
22.Các toán tử khác nhau có thể kích hoạt chuyển đổi số hoặc chuỗi với trợ giúp của tham số
String[123] // explicit
123 + '' // implicit
04. Nhưng có hai ngoại lệ: Bình đẳng lỏng lẻo String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 và các toán tử Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 kích hoạt các chế độ chuyển đổi mặc định [String[123] // explicit
123 + '' // implicit
04 không được chỉ định hoặc bằng với String[123] // explicit
123 + '' // implicit
27]. Trong trường hợp này, hầu hết các loại tích hợp đều giả định chuyển đổi số là mặc định, ngoại trừ // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
6 không chuyển đổi chuỗi.Dưới đây là một ví dụ về hành vi chuyển đổi
// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
6:Bạn có thể ghi đè các phương thức
String[123] // explicit
123 + '' // implicit
22 và String[123] // explicit
123 + '' // implicit
31 mặc định để nối vào logic chuyển đổi đối tượng sang nguyên tắc.Lưu ý cách
String[123] // explicit
123 + '' // implicit
32 trả về String[123] // explicit
123 + '' // implicit
33 dưới dạng chuỗi. Toán tử Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 kích hoạt chế độ chuyển đổi mặc định và như đã nói trước String[123] // explicit
123 + '' // implicit
35 giả sử chuyển đổi số làm mặc định, do đó sử dụng phương thức String[123] // explicit
123 + '' // implicit
31 trước tiên thay vì String[123] // explicit
123 + '' // implicit
22.Biểu tượng ES6.Toprimitive Phương pháp
Trong ES5, bạn có thể nối vào logic chuyển đổi đối tượng sang nguyên bản bằng cách ghi đè các phương thức
String[123] // explicit
123 + '' // implicit
06 và String[123] // explicit
123 + '' // implicit
05.Trong ES6, bạn có thể đi xa hơn và thay thế hoàn toàn thói quen nội bộ bằng cách thực hiện phương thức ____141 trên một đối tượng.
Ví dụ
Được trang bị lý thuyết, bây giờ hãy để Lừa quay lại các ví dụ của chúng tôi:
String[123] // explicit
123 + '' // implicit
3Dưới đây bạn có thể tìm thấy lời giải thích cho mỗi biểu thức.
Nhà điều hành nhị phân
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 kích hoạt chuyển đổi số cho // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
2 và // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
3String[123] // explicit
123 + '' // implicit
4Toán tử phân chia số học
Boolean[{}] // true
Boolean[[]] // true
Boolean[Symbol[]] // true
!!Symbol[] // true
Boolean[function[] {}] // true
1 kích hoạt chuyển đổi số cho chuỗi String[123] // explicit
123 + '' // implicit
46:String[123] // explicit
123 + '' // implicit
5Nhà điều hành
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 có tính kết hợp từ trái sang phải, vì vậy biểu thức String[123] // explicit
123 + '' // implicit
48 chạy trước. Vì một toán hạng là một chuỗi, toán tử Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 kích hoạt chuyển đổi chuỗi cho số String[123] // explicit
123 + '' // implicit
50. Trên biểu thức bước thứ hai String[123] // explicit
123 + '' // implicit
51 được đánh giá tương tự.String[123] // explicit
123 + '' // implicit
6Biểu thức
String[123] // explicit
123 + '' // implicit
52 được đánh giá đầu tiên. Không cần sự ép buộc nào cả, vì cả hai toán hạng là số. Trên bước thứ hai, biểu thức String[123] // explicit
123 + '' // implicit
53 được đánh giá và vì một toán hạng là một chuỗi, nó kích hoạt chuyển đổi chuỗi.String[123] // explicit
123 + '' // implicit
7Nhà điều hành so sánh
Boolean[''] // false
Boolean[0] // false
Boolean[-0] // false
Boolean[NaN] // false
Boolean[null] // false
Boolean[undefined] // false
Boolean[false] // false
5GT; Kích hoạt chuyển đổi số f ________ 155 [1] AString[123] // explicit
123 + '' // implicit
56ULL.String[123] // explicit
123 + '' // implicit
8Toán tử
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 không được ưu tiên cao hơn toán tử Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 nhị phân. Vì vậy, biểu thức String[123] // explicit
123 + '' // implicit
59 đánh giá đầu tiên. Unary Plus kích hoạt chuyển đổi số cho chuỗi String[123] // explicit
123 + '' // implicit
60. Vì chuỗi không đại diện cho một số hợp lệ, kết quả là Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
0. Trên bước thứ hai, biểu thức String[123] // explicit
123 + '' // implicit
62 được đánh giá.String[123] // explicit
123 + '' // implicit
9String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 Toán tử kích hoạt chuyển đổi số, chuỗi String[123] // explicit
123 + '' // implicit
64 được chuyển đổi thành NAN, Boolean // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
2 được chuyển đổi thành 1.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
0String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 thường kích hoạt chuyển đổi số, nhưng nó không phải là trường hợp với Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
2. Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
2 chỉ bằng với Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
2 hoặc Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
3 và không bằng bất cứ thứ gì khác.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
1String[123] // explicit
123 + '' // implicit
71 toán tử chuyển đổi cả chuỗi String[123] // explicit
123 + '' // implicit
64 và String[123] // explicit
123 + '' // implicit
73 thành boolean // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
2, vì chúng là các chuỗi không trống. Sau đó, String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 chỉ kiểm tra sự bình đẳng của hai boolean String[123] // explicit
123 + '' // implicit
76 mà không có bất kỳ sự ép buộc nào.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
2String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 toán tử kích hoạt chuyển đổi số cho một mảng. Phương thức Array Array String[123] // explicit
123 + '' // implicit
31 trả về chính mảng và bị bỏ qua bởi vì nó không phải là nguyên thủy. Array Array String[123] // explicit
123 + '' // implicit
22 chuyển đổi String[123] // explicit
123 + '' // implicit
80 thành chuỗi String[123] // explicit
123 + '' // implicit
81.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
3Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 Toán tử kích hoạt chuyển đổi số cho String[123] // explicit
123 + '' // implicit
83. Phương pháp Array Array String[123] // explicit
123 + '' // implicit
31 bị bỏ qua, bởi vì nó tự trả về Array, không nguyên thủy. Array Array String[123] // explicit
123 + '' // implicit
06 trả về một chuỗi trống.Trên biểu thức bước thứ hai
String[123] // explicit
123 + '' // implicit
86 được đánh giá.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
4Logic
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
7 và Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
8 Các nhà khai thác ép buộc các toán tử để boolean, nhưng trả lại các toán hạng gốc [không phải booleans]. Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
1 là giả, trong khi String[123] // explicit
123 + '' // implicit
90 là sự thật, bởi vì nó là một chuỗi không trống. String[123] // explicit
123 + '' // implicit
91 Đối tượng trống cũng là sự thật.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
5Không cần ép buộc vì cả hai toán hạng đều có cùng loại. Vì
String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
1 kiểm tra nhận dạng đối tượng [và không phải cho bình đẳng đối tượng] và hai mảng là hai trường hợp khác nhau, kết quả là // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
3.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
6Tất cả các toán hạng là các giá trị không nguyên thủy, do đó
Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 bắt đầu với chuyển đổi số kích hoạt ngoài cùng bên trái. Cả hai phương thức String[123] // explicit
123 + '' // implicit
95 và String[123] // explicit
123 + '' // implicit
96 String[123] // explicit
123 + '' // implicit
05 tự trả về chính đối tượng, do đó, nó đã bỏ qua. String[123] // explicit
123 + '' // implicit
22 được sử dụng như một dự phòng. Bí quyết ở đây là String[123] // explicit
123 + '' // implicit
91 đầu tiên không được coi là một đối tượng theo nghĩa đen, mà là một tuyên bố khai báo khối, do đó, nó đã bỏ qua. Đánh giá bắt đầu bằng biểu thức String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
00 tiếp theo, được chuyển đổi thành một chuỗi trống thông qua phương thức String[123] // explicit
123 + '' // implicit
22 và sau đó thành Number['123'] // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit
1.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
7Điều này được giải thích tốt hơn từng bước theo ưu tiên của nhà điều hành.
String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
8Boolean[''] // false
Boolean[0] // false
Boolean[-0] // false
Boolean[NaN] // false
Boolean[null] // false
Boolean[undefined] // false
Boolean[false] // false
8 Người vận hành kích hoạt chuyển đổi số cho // returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123
6. String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
05 Trả về số mili giây kể từ thời đại UNIX.String[123] // '123'
String[-12.3] // '-12.3'
String[null] // 'null'
String[undefined] // 'undefined'
String[true] // 'true'
String[false] // 'false'
9Boolean[2] // explicit
if [2] { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator
4 Trình kích hoạt toán tử chuyển đổi mặc định. Ngày giả định chuyển đổi chuỗi là một mặc định, do đó, phương thức String[123] // explicit
123 + '' // implicit
22 được sử dụng, thay vì String[123] // explicit
123 + '' // implicit
31.String[Symbol['my symbol']] // 'Symbol[my symbol]'
'' + Symbol['my symbol'] // TypeError is thrown
0Tài nguyên
Tôi thực sự muốn giới thiệu cuốn sách xuất sắc của Hiểu về es6, được viết bởi Nicholas C. Zakas. Nó có một tài nguyên học tập ES6 tuyệt vời, không quá cao và không đào sâu vào nội bộ quá nhiều.
Và đây là một cuốn sách hay về ES5 - nói các bài nói được viết bởi Axel Rauschmayer.
[Nga] Đặc biệt là hai trang này về cưỡng chế loại.Russian] Современный учебник Javascript — //learn.javascript.ru/. Especially these two pages on type coercion.
Bảng so sánh JavaScript-//dorey.github.io/javascript-equality-Table/
WTFJS - Một blog nhỏ về ngôn ngữ mà chúng tôi yêu thích mặc dù cho chúng tôi rất nhiều để ghét - //wtfjs.com/
Học mã miễn phí. Chương trình giảng dạy nguồn mở của Freecodecamp đã giúp hơn 40.000 người có được việc làm với tư cách là nhà phát triển. Bắt đầu