Hướng dẫn how does type coercion work in javascript? - kiểu ép buộc hoạt động như thế nào trong javascript?

bởi Alexey Samoshkin

Biết động cơ của bạn

Những điều kỳ lạ có thể xảy ra trong JavaScript

[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

String[Symbol['my symbol']]   // 'Symbol[my symbol]'
'' + Symbol['my symbol']      // TypeError is thrown
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.

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, like
String[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ư

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 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
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 [
    Boolean['']           // false
    Boolean[0]            // false     
    Boolean[-0]           // false
    Boolean[NaN]          // false
    Boolean[null]         // false
    Boolean[undefined]    // false
    Boolean[false]        // false
    0,
    Boolean['']           // false
    Boolean[0]            // false     
    Boolean[-0]           // false
    Boolean[NaN]          // false
    Boolean[null]         // false
    Boolean[undefined]    // false
    Boolean[false]        // false
    1, ________ 62, ________ 63]
  • Các toán tử bitwise [
    Boolean['']           // false
    Boolean[0]            // false     
    Boolean[-0]           // false
    Boolean[NaN]          // false
    Boolean[null]         // false
    Boolean[undefined]    // false
    Boolean[false]        // false
    4
    Boolean['']           // false
    Boolean[0]            // false     
    Boolean[-0]           // false
    Boolean[NaN]          // false
    Boolean[null]         // false
    Boolean[undefined]    // false
    Boolean[false]        // false
    5
    Boolean['']           // false
    Boolean[0]            // false     
    Boolean[-0]           // false
    Boolean[NaN]          // false
    Boolean[null]         // false
    Boolean[undefined]    // false
    Boolean[false]        // false
    6
    Boolean['']           // false
    Boolean[0]            // false     
    Boolean[-0]           // false
    Boolean[NaN]          // false
    Boolean[null]         // false
    Boolean[undefined]    // false
    Boolean[false]        // false
    7]
  • toán tử số học [
    Boolean['']           // false
    Boolean[0]            // false     
    Boolean[-0]           // false
    Boolean[NaN]          // false
    Boolean[null]         // false
    Boolean[undefined]    // false
    Boolean[false]        // false
    8
    Boolean[2]          // explicit
    if [2] { ... }      // implicit due to logical context
    !!2                 // implicit due to logical operator
    2 || 'hello'        // implicit due to logical operator
    4
    Boolean[{}]             // true
    Boolean[[]]             // true
    Boolean[Symbol[]]       // true
    !!Symbol[]              // true
    Boolean[function[] {}]  // true
    0
    Boolean[{}]             // true
    Boolean[[]]             // true
    Boolean[Symbol[]]       // true
    !!Symbol[]              // true
    Boolean[function[] {}]  // true
    1
    Boolean[{}]             // true
    Boolean[[]]             // true
    Boolean[Symbol[]]       // true
    !!Symbol[]              // true
    Boolean[function[] {}]  // true
    2]. Lưu ý rằng Binary
    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 kích hoạt chuyển đổi số, khi bất kỳ toán hạng nào là một chuỗi.
  • Nhà đ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
  • toán tử bình đẳng lỏng lẻo
    String[Symbol['my symbol']]   // 'Symbol[my symbol]'
    '' + Symbol['my symbol']      // TypeError is thrown
    1 [bao gồm
    Boolean[{}]             // true
    Boolean[[]]             // true
    Boolean[Symbol[]]       // true
    !!Symbol[]              // true
    Boolean[function[] {}]  // true
    6]. Lưu ý rằng
    String[Symbol['my symbol']]   // 'Symbol[my symbol]'
    '' + Symbol['my symbol']      // TypeError is thrown
    1 không kích hoạt chuyển đổi số khi cả hai toán hạng là chuỗi.
    Note that
    String[Symbol['my symbol']]   // 'Symbol[my symbol]'
    '' + Symbol['my symbol']      // TypeError is thrown
    1 does not trigger numeric conversion when both operands are strings.
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
0

Có hai quy tắc đặc biệt cần nhớ:special rules to remember:

  1. Khi áp dụng
    String[Symbol['my symbol']]   // 'Symbol[my symbol]'
    '' + Symbol['my symbol']      // TypeError is thrown
    1 lên
    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, 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ớ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] // explicit
123 + ''    // implicit
1

2. Nan không bằng bất cứ thứ gì ngay cả chính nó:

String[123] // explicit
123 + ''    // implicit
2

Loạ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:

  1. 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
3

Dướ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
3

String[123] // explicit
123 + ''    // implicit
4

Toá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
5

Nhà đ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
6

Biể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
7

Nhà đ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] A
String[123] // explicit
123 + ''    // implicit
56ULL.

String[123] // explicit
123 + ''    // implicit
8

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 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
9

String[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'
0

String[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'
1

String[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'
2

String[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'
3

Boolean[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'
4

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 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'
5

Khô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'
6

Tấ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'
8

Boolean['']           // 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'
9

Boolean[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
0

Tà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

Làm thế nào để ép buộc loại hoạt động?

Loại cưỡng chế là chuyển đổi tự động hoặc ngầm định các giá trị từ loại dữ liệu này sang loại dữ liệu khác. Ví dụ: chuyển đổi giá trị chuỗi thành giá trị số tương đương. Nó còn được gọi là chuyển đổi loại. Loại cưỡng chế có thể hữu ích nhưng nó có thể gây ra sự không nhất quán.automatic or implicit conversion of values from one data type to another. For example, converting a string value to an equivalent number value. It is also known as type conversion. Type coercion can be useful but it can cause inconsistencies.

Làm thế nào để bạn sử dụng loại ép buộc loại trong javascript?

Để ép buộc rõ ràng một giá trị cho một chuỗi trong javascript, chúng ta có thể sử dụng hàm chuỗi [].Để ngầm ép một giá trị cho một chuỗi, chúng ta có thể sử dụng toán tử + với bất kỳ toán hạng nào là một chuỗi.Chúng ta nên cẩn thận khi sử dụng loại ép buộc loại khi chúng ta muốn tạo một thao tác và một trong các loại toán hạng của chúng ta là một chuỗi.. To implicitly coerce a value to a string, we can use the + operator with any operand that is a string. We should be careful when using type coercion when we want to create an operation and one of our operand types is a string.

Chuyển đổi loại và ép buộc trong JavaScript là gì?

Chuyển đổi loại tương tự như ép buộc loại vì cả hai đều chuyển đổi các giá trị từ loại dữ liệu này sang loại dữ liệu khác với một sự khác biệt chính - ép buộc loại là ẩn khi chuyển đổi loại có thể là ẩn hoặc rõ ràng.type coercion is implicit whereas type conversion can be either implicit or explicit.

Sự khác biệt giữa == và cái nào cho phép ép buộc loại là gì?

!!Toán tử chuyển đổi cả chuỗi 'true' và 'false' thành boolean true, vì chúng là các chuỗi không trống.Sau đó, == chỉ kiểm tra sự bình đẳng của hai Boolean True mà không có sự ép buộc nào.== Toán tử kích hoạt chuyển đổi số cho một mảng.== just checks equality of two boolean true's without any coercion. == operator triggers a numeric conversion for an array.

Bài Viết Liên Quan

Chủ Đề