เหตุใด (“ foo” === new String (“ foo”)) จึงประเมินค่าเป็นเท็จใน JavaScript


98

ฉันจะเริ่มใช้ === (สามเท่าเท่ากับการเปรียบเทียบอย่างเข้มงวด) ตลอดเวลาเมื่อเปรียบเทียบค่าสตริง แต่ตอนนี้ฉันพบว่า

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

เป็นเท็จและเหมือนกันกับสิ่งนี้:

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

แน่นอน:

f == g; // true

ดังนั้นจึงแนะนำให้ใช้ == สำหรับการเปรียบเทียบสตริงเสมอหรือแปลงตัวแปรเป็นสตริงก่อนทำการเปรียบเทียบเสมอ?


6
อาจfooเป็นเพราะเป็นสตริงที่บริสุทธิ์และnew String("foo")เป็น Object String
Danilo Valente

ความเป็นมา: stackoverflow.com/questions/1646698/…
Pekka

6
ไม่แนะนำให้สร้างสตริงด้วยnew String(ไม่มีจุดหมายโดยสิ้นเชิง) แทนที่จะใช้==
Esailija

2
ทำไมใคร ๆ ก็อยากใช้โครงสร้างเหมือนnew String("foo")ใน Javascript ตั้งแต่แรก? ฉันไม่เคยเห็นรหัสดังกล่าวในรหัสเช่น jQuery ...
Robert Koritnik

2
คุณสามารถใช้String(obj)เพื่อแปลงสตริงแบบบรรจุกล่องเป็นแบบดั้งเดิมเมื่อคุณได้รับพารามิเตอร์ "string" แล้ว ("foo" === String(new String("foo"))) === true
OrangeDog

คำตอบ:


126

"foo"เป็นสตริงดั้งเดิม (แนวคิดนี้ไม่มีใน C # หรือ Java)

new String("foo") เป็นวัตถุสตริงชนิดบรรจุกล่อง

===ประกอบการทำงานแตกต่างกันบนพื้นฐานและวัตถุ
เมื่อเปรียบเทียบ primitives (ชนิดเดียวกัน) ===จะคืนค่า true หากทั้งสองมีค่าเหมือนกัน

เมื่อเปรียบเทียบออบเจ็กต์===จะคืนค่าจริงก็ต่อเมื่ออ้างถึงวัตถุเดียวกัน (เปรียบเทียบโดยการอ้างอิง) ด้วยnew String("a") !== new String("a")ประการฉะนี้.

ในกรณีของคุณให้===ส่งคืนค่าเท็จเนื่องจากตัวถูกดำเนินการเป็นประเภทที่แตกต่างกัน (แบบแรกเป็นแบบดั้งเดิมและอีกแบบเป็นอ็อบเจ็กต์)


ดึกดำบรรพ์ไม่ใช่วัตถุเลย ผู้ประกอบการจะไม่กลับมาสำหรับวิทยาการ
typeof"object"

เมื่อคุณพยายามเข้าถึงคุณสมบัติของดั้งเดิม (โดยใช้มันเป็นอ็อบเจกต์) ภาษา Javascript จะจัดกล่องให้กับอ็อบเจ็กต์และสร้างอ็อบเจกต์ใหม่ทุกครั้ง นี้มีการอธิบายในสเปค

นี่คือเหตุผลที่คุณไม่สามารถวางคุณสมบัติบนพื้นฐานได้:

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

ทุกครั้งที่คุณเขียนx.propertyที่แตกต่างกันชนิดบรรจุกล่องStringวัตถุที่ถูกสร้างขึ้น


33
+1 typeof "foo"; // "string",typeof new String("foo"); // "object"
Sampson

1
น่าสนใจฉันคิดว่าสตริงเป็นวัตถุใน JS
Cameron Martin

1
@Sarfraz: เกือบทุกอย่าง อย่าลืมเกี่ยวกับและnull undefined

2
if( Object(a) !== a ) { //it's a primitive }
Esailija

1
Java มีแบบดั้งเดิม /. Net don't
Marcelo De Zen

34

การใช้===,

  • ออบเจ็กต์ไม่เคยเท่ากับสิ่งใดเลยนอกจากการอ้างอิงอื่นกับตัวมันเอง

  • ดั้งเดิมมีค่าเท่ากันเมื่อเทียบกับดั้งเดิมอื่นถ้าประเภทและค่าเหมือนกัน


3
new String("foo") === new String("foo")คือfalse:-P
Rocket Hazmat

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 มี "this.a = 1;" - นั่นหมายความว่าฟังก์ชัน / วัตถุของคุณจะมีคุณสมบัติ a = 1
Michael Butler

ฉันคิดว่า (แต่ไม่สามารถพูดได้อย่างแน่นอน) ฟังก์ชั่น 'ตัวสร้างการชกมวย' แต่ละฟังก์ชั่นจะตรวจสอบบริบทก่อน - และหากไม่ใช่ 'ใหม่' (เช่นวัตถุต้นแบบ) ให้เปลี่ยนไปใช้วิธีการแปลงทันที ในกรณีของ String ที่จะเป็นtoString()วิธีการตัวอย่างเช่น
raina77ow


2

จาก node.js REPL ("โหนด" บนบรรทัดคำสั่งหากติดตั้ง):

> "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'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.