Почему («foo» === new String («foo»)) оценивается как false в JavaScript?

98

Я собирался начать использовать === (тройное равенство, строгое сравнение) все время при сравнении строковых значений, но теперь я обнаружил, что

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

ложно, и то же самое с этим:

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

Конечно:

f == g; // true

Итак, рекомендуется ли всегда использовать == для сравнения строк или всегда преобразовывать переменные в строки перед сравнением?

Майкл Батлер
источник
6
Возможно, потому что fooэто чистая строка, а new String("foo")это строка объекта
Данило Валенте
Предыстория: stackoverflow.com/questions/1646698/…
Pekka
6
Рекомендуется не создавать строки с помощью new String(Совершенно бессмысленно) вместо использования==
Esailija
2
Зачем кому-то вообще нужно использовать конструкцию, подобную new String("foo")Javascript? Я никогда не видел такого кода в коде, например, jQuery ...
Роберт Коритник 08
2
Вы можете использовать его String(obj)для преобразования строки в рамке в примитив после того, как вы получили свой "строковый" параметр. ("foo" === String(new String("foo"))) === true
OrangeDog 08

Ответы:

126

"foo"является строковым примитивом . (этой концепции нет в C # или Java)

new String("foo") - строковый объект в рамке.

===Оператор ведет себя по- разному на примитивы и объекты .
При сравнении примитивов (одного типа) ===вернет истину, если они оба имеют одинаковое значение.

При сравнении объектов ===вернет истину, только если они относятся к одному и тому же объекту (сравнение по ссылке). Таким образом, new String("a") !== new String("a").

В вашем случае ===возвращает false, потому что операнды имеют разные типы (один - примитив, а другой - объект).


Примитивы вообще не объекты. Оператор не вернется
typeof"object" примитивов .

Когда вы пытаетесь получить доступ к свойству примитива (используя его как объект), язык Javascript помещает его в объект, создавая каждый раз новый объект. Это описано в спецификации .

Вот почему вы не можете добавлять свойства к примитивам:

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

Каждый раз , когда вы пишете x.property, разные коробочный Stringобъект создается.

SLaks
источник
33
+1 typeof "foo"; // "string",typeof new String("foo"); // "object"
Sampson
1
Интересно, что я думал, что строки - это объекты в JS.
Кэмерон Мартин
1
@Sarfraz: Почти все. Не забывайте про nullи undefined.
2
if( Object(a) !== a ) { //it's a primitive }
Esailija
1
В Java есть примитивы, а в .Net их нет
Марсело Де Зен
34

Используя ===,

  • Объект никогда не равен ничему, кроме другой ссылки на себя.

  • примитив равен по сравнению с другим примитивом, если их тип и значение совпадают.


источник
3
new String("foo") === new String("foo")является false:-P
Rocket Hazmat 08
10

newСлово преступник здесь ( как обычно , я могу сказать) ...

Когда вы используете new, вы явно выражаете свое желание работать с объектом . Это может вас удивить, но вот это:

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

... даст вам могущественный false . Все просто: сравниваются не внутренности объектов, а ссылки на объекты. И они, конечно, не равны, так как были созданы два разных объекта.

Вероятно, вы захотите использовать преобразование :

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

... и это даст вам, как и ожидалось, trueрезультат, так что вы сможете foosвечно радоваться и процветать вместе со своими равными . )

raina77ow
источник
2
быстрый вопрос об использовании этого. Вы вызываете String (конструктор?) Без ключевого слова new. Разве это не означает, что вы загрязните область видимости любыми свойствами, назначенными в конструкторе String? Или этого не происходит, потому что конструктор - это машинный код? Другими словами, предположим, что функция String содержит this.a = 1; - это означает, что ваша функция / объект теперь будет иметь свойство a = 1.
Майкл Батлер
Я полагаю (но не могу сказать наверняка) каждая из функций «конструктора бокса» сначала проверяет свой контекст - и, если это не «новый» (то есть объект-прототип), сразу переключается на метод преобразования. toString()Например, в случае String это будет метод.
raina77ow 08
4

fooэто чистая строка и new String("foo")объектная строка

Данило Валенте
источник
2

Из REPL node.js ("узел" в командной строке, если он установлен):

> "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'
мда
источник