Czym dokładnie jest wymuszanie typów w JavaScript?

122

Czym dokładnie jest wymuszanie typów w Javascript?

Na przykład, jeśli chodzi o użycie ==zamiast ===?

gespinha
źródło
21
(true == 1) => true/ (true === 1) => false.
VisioN
5
@VisioN Twój komentarz w ogóle nie pomaga, pytam: „dlaczego” tak się dzieje?
gespinha
3
Dzieje się tak, ponieważ JavaScript został opracowany w ten sposób. Mój komentarz powinien odpowiedzieć na twoje główne pytanie: Czym dokładnie jest wymuszanie typów w JavaScript?
VisioN
6
Za pomocą YDJS: „Konwersja wartości z jednego typu na inny jest często nazywana„ rzutowaniem typów ”, gdy jest wykonywana jawnie, i„ przymusem ”, gdy jest wykonywana niejawnie (wymuszane przez reguły użycia wartości).” - github.com/getify/You-Dont-Know-JS/blob/master/…
mattLummus

Odpowiedzi:

177

Wymuszenie typu oznacza, że ​​gdy operandy operatora są różnych typów, jeden z nich zostanie przekonwertowany na „równoważną” wartość typu drugiego operandu. Na przykład, jeśli:

boolean == integer

operand boolowski zostanie przekonwertowany na liczbę całkowitą: falsestaje się 0, truestaje się 1. Następnie dwie wartości są porównywane.

Jeśli jednak użyjesz nieprzekształcającego operatora porównania ===, taka konwersja nie nastąpi. Gdy operandy są różnych typów, ten operator zwraca falsei porównuje wartości tylko wtedy, gdy są tego samego typu.

Barmar
źródło
1
Jak mogę to przedstawić w praktycznej sytuacji? Czy nie powinienem zawsze używać, ===gdy chcę porównać, czy wartość jest równa innej?
gespinha
1
To zależy od tego, co robisz. Zobacz powiązane pytanie.
Barmar
8
@GEspinha no cóż, to „sztuka” posługiwania się luźnym językiem. Niektórzy tak myślą i generalnie uważają, że języki z luźnymi typami są plagą świata programowania. Jeśli jednak wiesz, co robisz, może to spowodować krótszy, bardziej elastyczny kod.
Crayon Violent
2
@Barmar Czy to dotyczy również > , <?
Royi Namir,
2
Doskonałe odniesienie i wyjaśnienie dotyczące przymusu: github.com/getify/You-Dont-Know-JS/blob/master/…
Greg Bell
57

Zacznijmy od krótkiego wprowadzenia do systemów typów, które, jak sądzę, pomoże ci zrozumieć ogólną ideę wymuszania typów.

System typów języka definiuje reguły, które mówią nam, jakie typy danych istnieją w tym języku i jak można je łączyć za pomocą różnych operatorów. Na przykład jedna taka reguła może określać, że operator plus (+) działa tylko na liczbach. Te zasady istnieją przede wszystkim po to, aby zapobiec strzeleniu sobie w stopę. Ale co się stanie, gdy programista złamie tę regułę w programie? Nic nie stoi na przeszkodzie, aby programiści pisali {} + {}lub włączali “hello” + 5program, nawet jeśli język nie uważa, że ​​te wyrażenia mają jakikolwiek sens.

To, co ostatecznie dzieje się w takich sytuacjach, zależy od tego, jak rygorystyczny jest język w odniesieniu do reguł dotyczących typów.

System typów języków często zajmuje jedną z dwóch pozycji dotyczących łamania jego zasad:

  1. Powiedz „Hej, to nie jest fajne!” i natychmiast zawieszaj program.
  2. Powiedz „Nie mogę nic zrobić z {}… ale mogę zrobić coś z liczbami” i spróbuj przekonwertować {} na liczbę.

Języki, w których systemy typów zajmują pierwsze miejsce w odniesieniu do ich reguł, są potocznie określane jako języki „silnie wpisane”. Surowo nie pozwalają ci łamać jej zasad. Te, które stosują drugie podejście (takie jak JavaScript) są nazywane językami „słabo typizowanymi” lub „luźno wpisanymi”. Jasne, możesz złamać zasady, ale nie zdziw się, gdy konwertuje typ danych, które opisałeś w swoim programie, na siłę, aby zachować zgodność z jego regułami. Takie zachowanie jest znane jako… (walenie w bęben)… rodzaj przymusu .

Spójrzmy teraz na kilka przykładów w JavaScript. Najpierw zacznijmy od wyrażenia, które nie prowadzi do wymuszenia typu.

5 + 5

Używanie operatora + z dwoma liczbami, co jest całkowicie poprawne. Program potraktuje + jako „dodaj” i szczęśliwie doda te dwie liczby. Nie jest konieczna konwersja.

Ale co z …

[] + 5

O o. W JavaScript +może oznaczać dodanie dwóch liczb lub połączenie dwóch ciągów. W tym przypadku nie mamy ani dwóch liczb, ani dwóch łańcuchów. Mamy tylko jedną liczbę i obiekt. Zgodnie z regułami typu JavaScript nie ma to logicznego sensu. Ponieważ wybacza to, że łamiesz jej zasady, zamiast się rozbijać, i tak próbuje to zrozumieć. Więc co robi JavaScript? Cóż, wie, jak łączyć łańcuchy, więc konwertuje zarówno [], jak i 5 na łańcuchy, a wynikiem jest łańcuch o wartości „5”.

O co chodzi z operatorami porównania ==i ===? Dlaczego istnieją dwa operatory porównania?

==nie jest odporny na zachowanie konwersji typów w JavaScript. Wyrażenia, takie jak, 5 == “5”zostaną ocenione jako prawdziwe, ponieważ JavaScript spróbuje przekonwertować jedno z nich, aby porównywać ten sam typ danych.

W wielu przypadkach jest to niepożądane, ponieważ prawdopodobnie chcesz wiedzieć, czy niektóre dane, z którymi porównujesz, są innego typu, abyś mógł zdecydować, co z tym zrobić. W tym miejscu ===pojawia się operator. Kiedy używasz ===, nie nastąpi żadna konwersja typu. Dlatego wyrażenie 5 === “5”zostanie ocenione jako fałszywe.

linstantnoodles
źródło
4
dzięki za miłe wyjaśnienie, szczególnie za „System typów języków często zajmuje jedną z dwóch pozycji”
Humoyun Ahmad,
1
To powinna być akceptowana odpowiedź, ponieważ pokazuje automatyczne wymuszanie typu w wielu aspektach, a nie tylko w przykładzie porównania ==. Ta odpowiedź działa znacznie lepiej, jeśli chodzi o udzielenie odpowiedzi na pytanie i usunięcie wszelkich niejasności. Dziękuję za poświęcenie czasu na napisanie tego.
czad
6

W Pythonie, jeśli spróbujesz dodać, powiedzmy, ciągi znaków i liczby całkowite, otrzymasz błąd:

>>> "hi" + 10
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

Jednak w JavaScript nie masz. 10Zostanie przekonwertowany na ciąg znaków:

> "hi" + 10
"hi10"

„Wymuszenie typu” to tylko wymyślne mylące określenie powyższego. W rzeczywistości żaden język nie ma „typów” w sensie Java lub C lub innych języków ze statycznymi systemami typów. To, jak języki traktują interakcje między różnymi wartościami, które nie są statycznie typowane, jest kwestią wyboru i konwencji.

Claudiu
źródło
1
Myślę, że z podanym przykładem jest pewien problem. To, co zaproponowałeś jako przykład dla JS, działa bezbłędnie z Javą i C #. Tak więc, zgodnie z tą odpowiedzią, jeśli dojdzie się do wniosku, że Java i C # obsługują wymuszenie typu , nie będzie to do końca prawdą ...
Romeo Sierra,
3

Pozwólcie, że wyjaśnię wymuszenie typu na następującym przykładzie

Typ wymuszania oznacza, że ​​JavaScript automatycznie (w locie) konwertuje zmienną z jednego typu danych na inny

Np .: 123 + "4"generalnie generuje błąd, ale w Javascript ze względu na wymuszenie typu skutkuje 1234ciągiem znaków

if(23 == "23"){
    console.log(" this line is inside the loop and is executed ");
}

W powyższym kodzie, ze względu na wymuszenie typu - JavaScript uważa, że 23(liczba) i "23"(ciąg znaków) to to samo. to sprawia, że ​​warunek jest prawdziwy i drukuje console.log

W innym przypadku

if(23 === "23"){
   console.log(" this line is inside the loop and is NOT executed");
}

W ===przypadku, gdy Javascript nie wykonuje wymuszania typu, a ponieważ 23jest liczbą i "23"jest ciągiem, a ponieważ ===te dwa typy danych są różne, co prowadzi do fałszywego warunku. Nie drukuje pliku console.log

W prostych słowach

W tym przypadku =jest to operator przypisania - który przypisuje wartości takie jak var a = 3;itp

(poniższe operatory służą do porównania)

W tym przypadku ==JavaScript konwertuje / wymusza typ danych na inny, a następnie porównuje go.

W tym przypadku === JavaScript nie konwertuje / nie wymusza typu danych

W celu uniknięcia błędów i debugowania ===jest używany głównie

Proszę o podanie dokładności powyższych informacji.

PRagh
źródło
2

Co to jest przymus:

Wymuszenie typu w javascript występuje, gdy silnik Javascript musi wykonać określoną operację, dla której potrzebuje danych określonego typu. Gdy silnik napotka dane określonego typu, które nie mają zastosowania do operacji, przekształca te dane w określony typ. Jest to potrzebne, ponieważ zmienne w javascript są wpisywane dynamicznie, co oznacza, że ​​danej zmiennej można przypisać wartość dowolnego typu.

Przykład:


if(1){
  // 1 gets coerced to true
}


if(4 > '3') {
  // 3 gets coerced into a number
}


44 == "44"  // true, the string 44 gets converted to a nr

Koercja boolowska:

W przypadku wymuszania javascript wszystkie wartości są konwertowane na truez wyjątkiem następujących wartości, na które są przekształcane false:

console.log(!!"");         // false
console.log(!!0);          // false
console.log(!!null);       // false
console.log(!!undefined);  // false
console.log(!!NaN);        // false
console.log(!!false);      // false

Zauważ również, że w powyższym przykładzie podwójne! używany jest operator. The! Operator mark przekształca wartość w wartość logiczną o przeciwnej wartości. Możemy użyć tego operatora dwukrotnie, aby przekonwertować dowolną wartość na wartość logiczną.

Willem van der Veen
źródło
1

a == bśrodki javascript oceni ana bpodstawie jeśli wartości mogą być oceniane jednakowo. Na przykład false == 0oszacuje wartość true, ponieważ 0 jest również wartością logiczną fałsz. Jednak false === 0oszacuje fałsz, ponieważ ścisłe porównanie 0 nie jest tą samą wartością fizyczną, co fałsz. Innym przykładem jestfalse == '' więc w zasadzie luźne porównanie vs. ścisłe porównanie, ponieważ javascript jest językiem o luźnej typografii. Oznacza to, że javascript spróbuje przekonwertować zmienną na podstawie kontekstu kodu, a to powoduje, że rzeczy są równe, jeśli nie są ściśle porównane. php również ma takie zachowanie.

Crayon Violent
źródło
0 is not the same physical value as false. IMO fizycznie falsejest dokładnie 0w pamięci. Powiedziałbym raczej, że różnią się one typem, ponieważ falsejest logiczne, a 0jest liczbą całkowitą.
VisioN
1

Wymuszenie typu to proces konwersji wartości z jednego typu na inny (na przykład z ciągu znaków na liczbę, obiektu na wartość logiczną itd.). Każdy typ, czy to prymityw, czy obiekt, jest prawidłowym podmiotem dla przymusu typu. Przypominamy, że prymitywy to: liczba, ciąg znaków, wartość logiczna, wartość null, nieokreślona + symbol (dodany w ES6).

Niejawny a jawny wymuszenie Wymuszenie typu może być jawne i niejawne.

Gdy programista wyraża zamiar konwersji między typami, pisząc odpowiedni kod, na przykład Number(value), nazywa się to jawnym wymuszeniem typu (lub rzutowaniem typów).

Ponieważ JavaScript jest językiem słabo typizowanym, wartości można również konwertować automatycznie między różnymi typami i nazywa się to niejawnym wymuszeniem typu. To zwykle bywa w przypadku zastosowania operatorów do wartości różnych typów, takich jak 1 == null, 2/’5', null + new Date(), lub może być wyzwalane przez otaczającą kontekście, jak w przypadku if (value) {…}, w którym wartość jest zmuszany do boolean.

Jednym z operatorów, który nie wyzwala niejawnego wymuszania typu ===, jest operator ścisłej równości. Z ==drugiej strony operator luźnej równości wykonuje w razie potrzeby zarówno porównanie, jak i wymuszenie typu.

Niejawny wymuszenie typu to miecz o dwóch ostrzach: to świetne źródło frustracji i defektów, ale także przydatny mechanizm, który pozwala nam pisać mniej kodu bez utraty czytelności.

Trzy typy konwersji Pierwsza zasada, którą należy wiedzieć, mówi, że w JavaScript istnieją tylko trzy typy konwersji:

  • do sznurka
  • to boolean
  • na numer

Po drugie, logika konwersji dla prymitywów i obiektów działa inaczej, ale zarówno prymitywy, jak i obiekty można konwertować tylko na te trzy sposoby.

Zacznijmy najpierw od prymitywów.

Konwersja ciągów

Aby jawnie przekonwertować wartości na łańcuch, należy zastosować funkcję String (). Niejawne wymuszenie jest wyzwalane przez operator binarny +, gdy dowolny operand jest łańcuchem znaków:

String(123) // explicit
123 + ''    // implicit

Wszystkie wartości pierwotne są naturalnie konwertowane na ciągi, jak można się spodziewać:

String(123)                   // '123'
String(-12.3)                 // '-12.3'
String(null)                  // 'null'
String(undefined)             // 'undefined'
String(true)                  // 'true'
String(false)                 // 'false'

Konwersja symboli jest nieco skomplikowana, ponieważ można ją konwertować tylko jawnie, ale nie w sposób niejawny.

String(Symbol('my symbol'))   // 'Symbol(my symbol)'
'' + Symbol('my symbol')      // TypeError is thrown

Konwersja logiczna

Aby jawnie przekonwertować wartość na wartość logiczną, zastosuj Boolean()funkcję. Niejawna konwersja odbywa się w kontekście logicznym lub jest wyzwalana przez operatory logiczne ( || && !).

Boolean(2)          // explicit
if (2) { ... }      // implicit due to logical context
!!2                 // implicit due to logical operator
2 || 'hello'        // implicit due to logical operator

Uwaga: Operatory logiczne, takie jak || and &&wewnętrznie wykonują konwersje logiczne, ale w rzeczywistości zwracają wartość oryginalnych operandów, nawet jeśli nie są to wartości logiczne.

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

Gdy tylko pojawią się tylko 2 możliwe wyniki konwersji boolowskiej: prawda lub fałsz, po prostu łatwiej jest zapamiętać listę fałszywych wartości.

Boolean('')           // false
Boolean(0)            // false     
Boolean(-0)           // false
Boolean(NaN)          // false
Boolean(null)         // false
Boolean(undefined)    // false
Boolean(false)        // false

Każda wartość, która nie znajduje się na liście przekształca się truetym object, function, Array, Date, typ zdefiniowany przez użytkownika, i tak dalej. Symbole to prawdziwe wartości. Pusty obiekt i tablice są również prawdziwymi wartościami:

Boolean({})             // true
Boolean([])             // true
Boolean(Symbol())       // true
!!Symbol()              // true
Boolean(function() {})  // true

Konwersja numeryczna

Aby uzyskać jawną konwersję, po prostu zastosuj Number()funkcję, tak samo jak w przypadku Boolean()i String().

Niejawna konwersja jest trudna, ponieważ jest wyzwalana w większej liczbie przypadków:

  • operatory porównania (>, <, <=,> =)

  • operatory bitowe (| & ^ ~)

  • operatory arytmetyczne (- + * /%). Zauważ, że binarny + nie wyzwala konwersji numerycznej, gdy dowolny operand jest łańcuchem.

  • jednoargumentowy + operator

  • luźny operator równości == (włącznie! =).

    Zauważ, że == nie wyzwala konwersji numerycznej, gdy oba operandy są łańcuchami.

    Number ('123') // jawne + '123' // implicit 123! = '456' // implicit 4> '5' // implicit 5 / null // implicit true | 0 // niejawne

Oto jak prymitywne wartości są konwertowane na liczby:

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
Tejas Savaliya
źródło
0
var str = 'dude';
console.log(typeof str); // "string"
console.log(!str); // false
console.log(typeof !str); // "boolean"

Przykład zmiennej, która jest początkowo zadeklarowana jako łańcuch, przekształcana na wartość logiczną za pomocą! operator

Mister P.
źródło
3
Opisz swoją odpowiedź. Tylko kod odpowiedzi nie są naprawdę pomocne.
cezar
3
osobiście uważam kod tylko przykłady zwięzłe, oczywiste i bardzo przydatne, myślę, że to kwestia osobistej opinii
Pan P
0

Wymuszenie typu to proces konwersji wartości z jednego typu na inny (na przykład z ciągu znaków na liczbę, obiektu na wartość logiczną itd.). Każdy typ, czy to prymityw, czy obiekt, jest prawidłowym podmiotem dla przymusu typu. Przypominamy, że prymitywy to: liczba, ciąg znaków, wartość logiczna, wartość null, nieokreślona + symbol (dodany w ES6).

Wymuszenie typu może być jawne i niejawne.

Gdy programista wyraża zamiar konwersji między typami, pisząc odpowiedni kod, taki jak Number (value), nazywa się to jawnym wymuszeniem typu (lub rzutowaniem typu).

Ponieważ JavaScript jest językiem słabo typizowanym, wartości można również konwertować automatycznie między różnymi typami i nazywa się to niejawnym wymuszeniem typu. Zwykle dzieje się tak, gdy stosujesz operatory do wartości różnych typów, takich jak 1 == null, 2 / '5', null + new Date (), lub może być wyzwalane przez otaczający kontekst, na przykład if (value) {… }, gdzie wartość jest przekształcana na wartość logiczną.

oto przykład niejawnego wymuszania typu:

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

czytaj więcej: https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/

Mahdi Salehian
źródło
-2

Jeśli typy danych nie są sobie równe, następuje wymuszenie. jak 3 == "3" lub boolen == integer

ASAbir
źródło