W tym artykule poruszamy primitive values
w kontekście wyrażeń algebraicznych.
W JS mamy następujące znaki działań - #operations-table, i niezależnie z którego operatora byśmy skorzystali (+, -, *, /), pod spodem obsługa wyrażeń algebraicznych działa dokładnie tak - #sec-applystringornumericbinaryoperator.
Metoda wpierw sprawdza czy występuje operator dodawania, potem ewentualne konwertuje nasze wartości do ToPrimitive
i dalej do ToString
- lub w przypadku innych operatorów zawsze następuje konwersja do ToNumeric
.
Przeanalizujmy wpierw sytuację przy dodawaniu - następuje ToPrimitive
na obu wartościach.
"abc" + true // chcemy dodać do siebie dwie wartości - string'a i boolean'a
Zauważ, że w ToPrimitive nasz
input
jest traktowany różnie w zależności od typu (primitive
jest od razu zwracany, aObject
dalej obsługiwany - co omówimy w oddzielnym artykule).
Tak więc w przypadku primitive
nasze wartości są przekazywane dalej. Metoda ApplyStringOrNumericBinaryOperator
sprawdza czy któraś z wartości jest typu String
- jeśli tak to na obu primitive value
leci ToString - a co za tym idzie w ostatecznym dodawaniu następuje konkatencja stringów!!
"abc" + true // ToPrimitive("abc") + ToPrimitive(true)
ToPrimitive("abc") + ToPrimitive(true) // ToString("abc") + ToString(true)
"abc" + true // "abc" + "true" --> "abctrue" (konkatenacja)
W przypadku
ToString
jest to właściwie odpalenie konstruktoraString
na naszej wartości.
Przedstawia się to następująco dla naszych podstawowych typów prostych:
boolean
(true / false) ->String(true)
->"true"
(w przypadku false"false"
)number
->String(1)
->"1"
undefined
->String(undefined)
->"undefined"
null
->String(null)
->"null"
string
->String("abc")
->"abc"
Jeśli oba primitive value
nie są typu String
lub działaniem nie jest dodawanie to następuje ToNumeric na naszych wartościach (i tak naprawdę dzieje się tak dla wszystkich innych typów).
true + false // chcemy dodać do siebie dwie wartości typu boolean
W przypadku
ToNumeric
pod spodem odpalane jest tak naprawdę ToNumber.
Czyli dokładnie tak:
true + false // ToPrimitive(true) + ToPrimitive(false)
ToPrimitive(true) + ToPrimitive(false) // toNumeric(true) + toNumeric(false)
toNumeric(true) + toNumeric(false) // ToNumber(true) + ToNumber(false)
true + false // 1 + 0 --> 1
W przypadku
ToNumber
jest to właściwie odpalenie konstruktoraNumber
na naszej wartości.
Przedstawia się to następująco dla naszych podstawowych typów prostych:
boolean
(true / false) ->Number(true)
->1
(w przypadku false0
)number
->Number(1)
->1
(i zgodnie ze specyfikacją do typu number zaliczamyall possible Number values including the special “Not-a-Number” (NaN) value, positive infinity (+Infinity), and negative infinity (-Infinity)
)undefined
->Number(undefined)
->NaN
null
->Number(null)
->0
string
->Number("1")
->1
- tutaj tak naprawdę na naszej wartości robione jest Number::toString - co mniej więcej oznacza, że jeśli argumentem jest Number Type w postaci string'a to tak naprawdę jest traktowane jakoNumber
string
->Number("text")
->NaN
- każdy string niebędący Number Type będzieNaN
Wiedząc już, że należy rozpoznać typ naszego primitive value
ORAZ działanie (+, - itd.) myślę, że całkowicie jasne są dla Ciebie poniższe przykłady na typach prostych:
true + false // 1 + 0 --> 1
undefined + false // NaN + 0 --> NaN
"abc" + true // "abc" + "true" --> "abctrue"
"abc" - false // NaN - 0 --> NaN
5 + null // 5 + 0 --> 5
"NaN" - false // NaN - 0 --> NaN
"NaN" + false // "NaN" + "false" --> "NaNfalse"
Ciekawostka! W przypadku większej ilości składowych wyrażenia należy wykonywać operacje od lewej do prawej. Np.
true + "true" + true = "truetruetrue"
lubtrue + true + "true" = "2true"
.
W kolejnych artykułach omówię wyrażenia algebraiczne na typach złożonych.