为什么在JavaScript中"foo" === new String("foo")的结果是false?

102
我原本想在比较字符串值时始终使用 ===(三等号,严格比较),但现在我发现
"foo" === new String("foo")

是错误的,这个也一样:

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

当然:

f == g; // true

那么,是推荐始终使用 == 进行字符串比较,还是始终在比较之前将变量转换为字符串?


6
可能是因为foo是纯字符串,而new String("foo")是字符串对象。 - Danilo Valente
6
建议不要使用new String创建字符串(完全没有意义),而应该使用== - Esailija
2
为什么有人会想在Javascript中使用像new String("foo")这样的构造方式呢?我从来没有在代码中看到过这样的代码,比如jQuery... - Robert Koritnik
2
一旦您接收到“string”参数,您可以使用String(obj)将包装字符串转换为原始字符串。 (“foo” === String(new String(“foo”)))=== true - OrangeDog
显示剩余9条评论
5个回答

128

"foo"是一个字符串原始值。(在C#或Java中不存在这个概念)

new String("foo")是一个装箱的字符串对象。

===运算符对于原始类型和对象的比较有不同的行为
当比较相同类型的原始值时,如果它们具有相同的值,则===返回true。

当比较对象时,只有当它们引用同一对象(按引用比较)时,===才返回true。 因此,new String("a") !== new String("a")

在您的情况下,===返回false,因为操作数是不同类型的(一个是原始值,另一个是对象)。


原始值根本不是对象。
对于原始值,typeof运算符将不会返回"object"

当您尝试访问原始值的属性时(将其用作对象时),Javascript语言将对其进行装箱处理,每次都创建一个新对象。 这在规范中有所描述。

这就是为什么您不能在原始值上设置属性的原因:

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

每次你写 x.property,都会创建一个不同的装箱 String 对象。


35
+1 typeof "foo"; // "string" "foo" зљ„ typeof з»“жћњдёє "string"гЂ‚typeof new String("foo"); // "object" дЅїз”Ё new е…ій”®е­—е€›е»єзљ„ String еЇ№и±Ўзљ„ typeof з»“жћњдёє "object"гЂ‚ - Sampson
1
有趣,我以为在JS中字符串是对象。 - Cameron Martin
1
@Sarfraz:几乎所有的东西。不要忘记 nullundefined - user1106925
2
if( Object(a) !== a ) { //it's a primitive } - Esailija
1
@devundef:C#和Java都没有字符串原始类型;在这两种语言中,String是一个普通的类(引用类型)。在.Net中,String更接近于原始类型;它在IL(字面量)和GC/内存模型中有特殊支持(它们不是固定大小)。.Net和Java都有原始数值类型。 - SLaks
显示剩余8条评论

34

使用 ===

  • 对象只有和另一个对自身的引用相等时才相等。

  • 原始类型在其类型和值相同时与另一个原始类型相等。


3
new String("foo") === new String("foo") 的结果是 false。:-P - gen_Eric

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永远繁荣昌盛。


2
关于使用这个的一个快速问题。你正在调用String(一个构造函数?)而没有使用“new”关键字。这不意味着您将使用在String构造函数中分配的任何属性来污染范围吗?或者这种情况不会发生,因为构造函数是本地代码?换句话说,假设String函数包含“this.a = 1;”--这意味着您的函数/对象现在将具有属性a = 1。 - Michael Butler
1
我猜(但不能确定)每个“装箱构造函数”首先检查其上下文,如果它不是一个“较新的”(即原型对象),则立即切换到转换方法。例如,在 String 的情况下,这将是 toString() 方法。 - raina77ow

4

foo是纯字符串,new String("foo")是字符串对象。


2

从node.js REPL(如果已安装,则为命令行上的“node”):

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

typeof 不需要像函数一样使用,而且如果我没记错的话,new 绑定到第一个函数调用。 - PoolloverNathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接