Dlaczego („foo” === new String („foo”)) przyjmuje wartość fałsz w JavaScript?

98

Miałem zamiar zacząć używać === (potrójne równa się, ścisłe porównanie) przez cały czas porównując wartości ciągów, ale teraz stwierdzam, że

"foo" === new String("foo")

jest fałszem i to samo z tym:

var f = "foo", g = new String("foo");
f === g; // false

Oczywiście:

f == g; // true

Czy więc zaleca się, aby zawsze używać == do porównywania ciągów, czy zawsze konwertować zmienne na ciągi przed porównaniem?

Michael Butler
źródło
6
Może dlatego, że foojest czystym ciągiem i new String("foo")jest ciągiem obiektu
Danilo Valente,
6
Zaleca się, aby nie tworzyć ciągów z new String(Całkowicie bezcelowe), zamiast używać==
Esailija
2
Dlaczego ktoś miałby chcieć używać konstrukcji takiej jak new String("foo")w JavaScript? Nigdy nie widziałem takiego kodu w kodzie tj.
JQuery
2
Możesz użyć String(obj)do przekonwertowania łańcucha w ramce na prymityw po otrzymaniu parametru „string”. ("foo" === String(new String("foo"))) === true
OrangeDog

Odpowiedzi:

126

"foo"jest łańcuchem pierwotnym . (ta koncepcja nie istnieje w C # ani w Javie)

new String("foo") jest obiektem łańcucha w ramce.

===Operatora zachowuje się inaczej w pierwotnych i przedmiotów .
Porównując prymitywy (tego samego typu), ===zwróci true, jeśli oba mają tę samą wartość.

Podczas porównywania obiektów ===zwróci wartość true tylko wtedy, gdy odnoszą się do tego samego obiektu (porównując przez odniesienie). Zatem new String("a") !== new String("a").

W twoim przypadku ===zwraca false, ponieważ operandy są różnych typów (jeden jest prymitywem, a drugi obiektem).


Prymitywy w ogóle nie są obiektami. Operator nie powróci do pierwotnych.
typeof"object"

Kiedy spróbujesz uzyskać dostęp do właściwości prymitywu (używając go jako obiektu), język Javascript umieści go w obiekcie, tworząc za każdym razem nowy obiekt. Jest to opisane w specyfikacji .

Dlatego nie możesz nadawać właściwości prymitywom:

var x = "a";
x.property = 2;
alert(x.property) //undefined

Za każdym razem, gdy piszesz x.property, tworzony jest innyString obiekt w ramce .

SLaks
źródło
33
+1 typeof "foo"; // "string",typeof new String("foo"); // "object"
Sampson
1
Co ciekawe, myślałem, że łańcuchy znaków to obiekty w JS.
Cameron Martin
1
@Sarfraz: Prawie wszystko. Nie zapomnij o nulli undefined.
2
if( Object(a) !== a ) { //it's a primitive }
Esailija
1
Java ma prymitywy / .Net nie
Marcelo De Zen
34

Korzystanie ===,

  • Obiekt nigdy nie jest równy żadnemu z wyjątkiem innego odniesienia do siebie.

  • prymityw jest równy w porównaniu z innym prymitywem, jeśli ich typ i wartość są takie same.


źródło
3
new String("foo") === new String("foo")jest false:-P
Rocket Hazmat
10

Tutaj newsłowo jest przestępcą ( jak zwykle , powiem) ...

Kiedy używasz new, wyraźnie wyrażasz chęć pracy z przedmiotem . Może to być dla Ciebie zaskakujące, ale to:

var x = new String('foo');
var y = new String('foo');
x === y; 

... da ci moc false. To proste: porównywane są nie wnętrza obiektów, ale odniesienia do obiektów. I oczywiście nie są równe, ponieważ powstały dwa różne obiekty.

Prawdopodobnie chcesz użyć konwersji :

var x = String('foo');
var y = String('foo');
x === y;

... a to da ci, zgodnie z oczekiwaniami, truew rezultacie, abyś mógł cieszyć się i prosperować razem z równymi sobie na fooszawsze. )

raina77ow
źródło
2
szybkie pytanie dotyczące korzystania z tego. Wołasz String (konstruktor?) Bez słowa kluczowego „new”. Czy to nie oznacza, że ​​będziesz zanieczyszczać zakres dowolnymi właściwościami przypisanymi w konstruktorze String? A może tak się nie dzieje, ponieważ konstruktor jest kodem natywnym? Innymi słowy, załóżmy, że funkcja String zawiera „this.a = 1;” - to znaczy, że twoja funkcja / obiekt miałby teraz właściwość a = 1.
Michael Butler,
Przypuszczam (ale nie mogę powiedzieć na pewno) każda z funkcji „konstruktora pudełkowego” najpierw sprawdza swój kontekst - a jeśli nie jest to „nowy” (tj. Obiekt prototypowy), od razu przełącza się na metodę konwersji. Na przykład w przypadku String byłaby to toString()metoda.
raina77ow
4

foojest czystym ciągiem i new String("foo")jest ciągiem obiektu

Danilo Valente
źródło
2

Z pliku REPL node.js („węzeł” w wierszu poleceń, jeśli jest zainstalowany):

> "foo" === (new String("foo")).valueOf()
true
> "foo" === new String("foo")
false
> typeof("foo")
'string'
> typeof(new String("foo"))
'object'
> typeof((new String("foo")).valueOf())
'string'
mda
źródło