(a == 1 && a == 2 && a == 3) เคยประเมินว่าเป็นจริงหรือไม่


2484

หมายเหตุผู้ดูแล:โปรดต่อต้านการกระตุ้นให้แก้ไขรหัสหรือลบประกาศนี้ รูปแบบของพื้นที่ว่างอาจเป็นส่วนหนึ่งของคำถามดังนั้นจึงไม่ควรแก้ไขโดยไม่จำเป็น หากคุณอยู่ใน "ช่องว่างที่ไม่มีความหมาย" ค่ายคุณควรจะยอมรับรหัสตามที่เป็นอยู่

เป็นไปได้ไหมที่(a== 1 && a ==2 && a==3)จะประเมินเป็นtrueJavaScript?

นี่คือคำถามสัมภาษณ์ที่ถามโดย บริษัท เทคโนโลยีรายใหญ่ มันเกิดขึ้นเมื่อสองสัปดาห์ก่อน แต่ฉันยังคงพยายามหาคำตอบ ฉันรู้ว่าเราไม่เคยเขียนรหัสดังกล่าวในงานประจำวัน แต่ฉันอยากรู้


9
ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
หลอกลวง

109
สำหรับคนที่ลงคะแนนให้เห็นอย่างชัดเจนว่ากว้างเกินไป : ผู้ขุดที่ Javascript กล่าวว่ามีคำตอบที่ถูกต้องมากเกินไปหรือไม่
tomsmeding

24
บางคนนั่งอ่านบทวิจารณ์เกี่ยวกับสิ่งที่เป็นไปได้ คนอื่น ๆ มุ่งเน้นความพยายามของพวกเขาว่าพวกเขากำลังสร้างความเป็นไปได้หรือไม่ผลิตภัณฑ์ที่ถูกต้องทางธุรกิจสำหรับลูกค้า IMO คำถามนี้ไม่มีประโยชน์ใด ๆ นอกเหนือจากข้อเท็จจริงที่ว่าคุณไม่ควรถามคำถามประเภทนี้ในการสัมภาษณ์หรือเขียนรหัสประเภทนี้ นั่นเป็นเหตุผลว่าทำไมจึงควรปิด ฉันหมายถึงจริงๆธุรกิจรู้หรือไม่ว่าพวกเขาจ่ายเงินจริงให้ใครสักคนเพื่อไปนั่งคุยเรื่องนี้?
P.Brian.Mackey

15
หลังจากอ่านคำตอบแล้วศีลธรรมของเรื่องราวก็คือ: อย่าใช้==เมื่อคุณหมายถึง===มีมาตรฐานการเข้ารหัสที่ห้ามชื่อตัวแปรที่ไม่ใช่ ASCII และมีกระบวนการที่เป็นขุยซึ่งบังคับใช้ศีลธรรมสองข้อก่อนหน้านี้
Jesse C. Slicer

87
ผู้ดำเนินรายการหมายเหตุ: Stack Overflow มีประวัติบุคคลที่พูดคุยกับคำตอบในภาษาต่าง ๆ ต่อหนึ่งคำถาม สิ่งเหล่านี้เป็นความพยายามที่จะตอบคำถามเพราะมันเป็นวิธีการแก้ปัญหาทั่วไปแม้ว่าจะเป็นภาษาอื่น โปรดงดเว้นการตั้งค่าสถานะเป็น "ไม่ใช่คำตอบ" ต้องบอกว่าโปรดงดเว้นการโพสต์คำตอบเพิ่มเติมในภาษาต่าง ๆ - มีเหตุผลที่คำถามนี้เฉพาะกับจาวาสคริปต์ตามที่แสดงความคิดเห็นภายใต้คำตอบอื่น ๆ เหล่านี้และมีเหตุผลที่เราชอบคำถามเฉพาะภาษาของเรา ยังคงเป็นเช่นนั้น
BoltClock

คำตอบ:


3323

หากคุณใช้ประโยชน์จากวิธีการ==ทำงานคุณสามารถสร้างวัตถุที่มีฟังก์ชั่นที่กำหนดเองtoString(หรือvalueOf) ซึ่งจะเปลี่ยนสิ่งที่มันคืนมาในแต่ละครั้งที่มันถูกใช้เพื่อให้เป็นไปตามเงื่อนไขทั้งสามข้อ

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}


เหตุผลที่งานนี้เกิดจากการใช้ตัวดำเนินการความเท่าเทียมกันแบบหลวม เมื่อใช้ความเท่าเทียมกันแบบหลวมหากตัวถูกดำเนินการตัวใดตัวหนึ่งแตกต่างจากตัวอื่นเครื่องยนต์จะพยายามแปลงค่าหนึ่งเป็นอีกแบบหนึ่ง ในกรณีของวัตถุทางด้านซ้ายและจำนวนที่อยู่ทางขวาหนึ่งก็จะพยายามที่จะแปลงวัตถุไปยังหมายเลขโดยการโทรครั้งแรกvalueOfถ้ามันเป็น callable toStringและความล้มเหลวที่จะเรียก ฉันใช้toStringในกรณีนี้เพียงเพราะมันเป็นสิ่งที่อยู่ในใจvalueOfจะทำให้รู้สึกมากขึ้น ถ้าฉันส่งคืนสตริงจากtoStringเครื่องยนต์จะพยายามแปลงสตริงเป็นตัวเลขซึ่งให้ผลลัพธ์ที่เหมือนกันแม้ว่าจะมีเส้นทางที่ยาวกว่าเล็กน้อย


70
คุณสามารถทำได้โดยการเปลี่ยนแปลงการvalueOf()ดำเนินการโดยนัย?
Sterling Archer

43
ใช่ valueOf ทำงานแทน toString ด้วยเหตุผลเดียวกัน
Kevin B

4
ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
หลอกลวง

13
ตามนี้แปลงตัวเลขจะพยายามครั้งแรกดังนั้นvalueOfจะดีกว่าเล็กน้อย
Salman

6
@Pureferret ด้านซ้ายมือของการเปรียบเทียบความเท่าเทียมกันเป็นวัตถุไม่ใช่ตัวเลข วัตถุนั้นมีคุณสมบัติตัวเลขเปิดอยู่iไม่รบกวนเครื่องยนต์ ;)
tomsmeding

2057

ฉันไม่สามารถต้านทาน - คำตอบอื่น ๆ เป็นจริงไม่ต้องสงสัย แต่คุณไม่สามารถเดินผ่านรหัสต่อไปนี้

var a = 1;
var a = 2;
var a = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
    console.log("Why hello there!")
}

สังเกตการเว้นวรรคแปลก ๆ ในifคำสั่ง (ที่ฉันคัดลอกมาจากคำถามของคุณ) เป็นอังกูลแบบครึ่งความกว้าง (เป็นภาษาเกาหลีสำหรับผู้ที่ไม่คุ้นเคย) ซึ่งเป็นอักขระช่องว่าง Unicode ที่สคริปต์ ECMA ไม่ได้ตีความว่าเป็นอักขระเว้นวรรค - ซึ่งหมายความว่าเป็นอักขระที่ถูกต้องสำหรับตัวระบุ ดังนั้นจึงมีตัวแปรที่แตกต่างกันโดยสิ้นเชิงสามตัวหนึ่งตัวกับอังกูลหลังตัว a หนึ่งตัวก่อนและตัวสุดท้ายด้วยตัว แทนที่ช่องว่างด้วย_เพื่อให้สามารถอ่านได้รหัสเดียวกันจะมีลักษณะดังนี้:

var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
    console.log("Why hello there!")
}

ตรวจสอบการตรวจสอบในชื่อตัวแปรงัดตรวจสอบ ถ้าระยะห่างแปลก ๆ นั้นรวมอยู่ในคำถามของพวกเขาฉันรู้สึกว่ามันเป็นคำใบ้สำหรับคำตอบแบบนี้

อย่าทำอย่างนี้ อย่างจริงจัง.

แก้ไข: มีความสนใจของฉันที่ (แม้ว่าจะไม่ได้รับอนุญาตให้เริ่มตัวแปร) ตัวเชื่อมตัวZero-widthและZero-width ไม่ใช่ตัวเชื่อมตัวอักษรยังได้รับอนุญาตในชื่อตัวแปร - ดูJavaScript ที่สับสนกับตัวอักษรความกว้างเป็นศูนย์ - ข้อดีและข้อเสีย ? .

นี่จะมีลักษณะดังนี้:

var a= 1;
var a‍= 2; //one zero-width character
var a‍‍= 3; //two zero-width characters (or you can use the other one)
if(a==1&&a‍==2&&a‍‍==3) {
    console.log("Why hello there!")
}


368
ตัดสินจากระยะห่างที่แปลกประหลาดในคำถามเดิมฉันคิดว่านี่เป็นคำตอบที่ตรงกับคำถามสัมภาษณ์ที่กำลังมองหา - ใช้ประโยชน์จากตัวละครที่ไม่ใช่ช่องว่างที่ดูเหมือนช่องว่าง จุดที่ดี!
Baracus

18
@Baracus มันเป็น RonJohn ที่สังเกตเห็นระยะห่างที่แปลกประหลาดในความเห็นของเขาเกี่ยวกับคำตอบของ Kevin ซึ่งทำให้ฉันนึกถึงเทคนิค (อันยิ่งใหญ่) นี้ดังนั้นฉันจึงไม่สามารถใช้เครดิตเพื่อตรวจสอบได้ ฉันรู้สึกประหลาดใจที่ไม่มีใครตอบคำถามนี้ไปแล้วเพราะมันเดินไปรอบ ๆ งานของฉันเมื่อสองสามปีก่อนเพราะโพสต์บล็อกบางแห่ง - ฉันคิดว่ามันเป็นความรู้ทั่วไปที่น่าสนใจ
Jeff

102
แน่นอนว่าสิ่งนี้ถูกแบนเหมือนช่องโหว่มาตรฐานซึ่งใช้กับการสัมภาษณ์ด้วย [อ้างจำเป็น]
Sanchises

13
เมื่อพิจารณาระยะห่างดั้งเดิมอาจแย่กว่านั้นคือใช้ตัวแปรไปvar ᅠ2 = 3แล้ว ดังนั้นจึงมีตัวแปรสามตัวaᅠᅠ= 1, ᅠ2 = 3, a = 3( a␣ = 1, ␣2 = 3, a = 3ดังนั้น(a␣==1 && a==␣2 && a==3)) ...
โฮล

2
@ AL-zami มีอักขระพิเศษในสองตัวแปรซึ่งแสดงบนหน้าจอของคุณเป็นช่องว่าง แต่ถูกตีความว่าเป็นส่วนหนึ่งของตัวบ่งชี้ซึ่งหมายความว่ามีตัวแปรสามตัวแยกกันคือ - a และ a - อักขระพิเศษคือ พื้นที่ครึ่งความกว้างของอังกูล
Jeff

620

มันเป็นไปได้!

var i = 0;

with({
  get a() {
    return ++i;
  }
}) {
  if (a == 1 && a == 2 && a == 3)
    console.log("wohoo");
}

สิ่งนี้ใช้ getter ภายในwithคำสั่งเพื่อให้aประเมินค่าที่ต่างกันสามค่า

... สิ่งนี้ยังไม่ได้หมายความว่าควรใช้ในรหัสจริง ...

ยิ่งไปกว่านั้นเคล็ดลับนี้จะใช้ได้กับการใช้งาน===ด้วย

  var i = 0;

  with({
    get a() {
      return ++i;
    }
  }) {
    if (a !== a)
      console.log("yep, this is printed.");
  }


65
ใช่ฉันพยายามแบบเดียวกัน :) ดังนั้นคำตอบที่ถูกต้องในการสัมภาษณ์ก็คือ "มันไม่สามารถเกิดขึ้นได้ในรหัสของฉันเพราะฉันไม่เคยใช้withเลย"
Pointy

7
@ Pointy - และฉันตั้งโปรแกรมในโหมดเข้มงวดที่withไม่ได้รับอนุญาต
jfriend00

6
@Pointy ในคำตอบที่ได้รับการยอมรับพวกเขาทำสิ่งที่คล้ายกันโดยไม่withเกิดขึ้นเลย
จองกุก

2
@jorrit ==จะไม่มีใครใช้ และ===ป้องกันคำตอบที่ยอมรับ
Jonas Wilms

4
@JonasW ผู้คนจำนวนมากยังคงใช้==แต่ฉันไม่ได้เห็นwithตั้งแต่ ... จริง ๆ แล้วไม่เคยอยู่นอกเอกสาร JS ซึ่งมันบอกว่า "ได้โปรดอย่าใช้มัน" อย่างไรก็ตามทางออกที่ดี
wortwart

516

ตัวอย่างที่ไม่มี getters หรือ valueOf:

a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);

วิธีนี้ใช้งานได้เนื่องจาก==เรียกใช้toStringสายใด.joinอาร์เรย์ใช้

โซลูชันอื่นSymbol.toPrimitiveซึ่งใช้ซึ่งเทียบเท่ากับ ES6 toString/valueOf:

let i = 0;
let a = { [Symbol.toPrimitive]: () => ++i };

console.log(a == 1 && a == 2 && a == 3);


9
without valueOfดี ... มันมากกว่าโดยทางตรง แต่โดยพื้นฐานแล้วเป็นสิ่งเดียวกัน
Jonas Wilms

11
ฉันชอบโซลูชันนี้มากเพราะคุณไม่ได้แทนที่อะไรนอกจากฟังก์ชั่นการรวมวัตถุของตัวเองและมันเป็นเพียงแฮ็คที่สะอาดและอ่านง่ายที่ทำให้ตรรกะประเมินว่าเป็นจริง
อเล็กซ์ Pedersen

28
สุจริตฉันคิดว่านี่เป็นคำตอบที่ดีที่สุด มันไม่เกี่ยวอะไรกับสิ่งที่ผิดปกติเพียงแค่ตั้งค่าบางอย่าง เข้าใจง่ายมากแม้จะมีความรู้พื้นฐาน JS ทำได้ดี.
Zac Delventhal

14
มันทำให้รู้สึกว่ามันมีประโยชน์มาก
แอนดรู

7
ฉันรู้ว่าคำตอบส่วนใหญ่เกี่ยวกับการใช้ในทางที่ผิดtoStringหรือvalueOfอย่างใดอย่างหนึ่ง ฉลาดมากและฉันไม่รู้ว่ามันโทร.joinภายใน แต่มันสมเหตุสมผลดี
GBarroso

268

หากมีการถามว่าเป็นไปได้หรือไม่ (ไม่ใช่ต้อง) ก็สามารถขอให้ "a" ส่งคืนตัวเลขสุ่ม มันจะเป็นจริงถ้ามันสร้าง 1, 2 และ 3 ตามลำดับ

with({
  get a() {
    return Math.floor(Math.random()*4);
  }
}){
  for(var i=0;i<1000;i++){
    if (a == 1 && a == 2 && a == 3){
      console.log("after " + (i+1) + " trials, it becomes true finally!!!");
      break;
    }
  }
}


102
ฉันจงใจจะให้คำตอบนี้แม้ว่าฉันจะรู้วิธีแก้ปัญหาอื่น ๆ เพราะมันตอบคำถาม แต่ไม่ชัดเจนว่าพวกเขาเป็นใคร เล่นเกมที่โง่รับรางวัลโง่ ๆ
ESR

2
แต่ถ้าหากมันใช้การทดลองมากกว่า 1,000 ครั้ง
Piyin

9
@Piyin หากใช้มากกว่า 1,000 ครั้งคุณจะได้รับรางวัล!
Skeets

5
ฉันชอบคำตอบนี้เพราะนำไปสุดโต่งแสดงว่าเป็นไปได้ในภาษาใด ๆหากการลงทะเบียน / แคชของ cpu ได้รับการตีด้วยรังสีคอสมิกที่เพียงพอในขณะที่โปรแกรมกำลังทำงาน หากเงื่อนไขไม่ได้กระโดดจริง
Ponkadoodle

ต่ำสุด: 1, สูงสุด: 412.
KyleFairns

210

เมื่อคุณไม่สามารถทำอะไรได้หากไม่มีการแสดงออกปกติ:

var a = {
  r: /\d/g, 
  valueOf: function(){
    return this.r.exec(123)[0]
  }
}

if (a == 1 && a == 2 && a == 3) {
    console.log("!")
}

มันทำงานได้เพราะvalueOfวิธีการที่กำหนดเองที่เรียกว่าเมื่อเทียบกับวัตถุดั้งเดิม (เช่นจำนวน) เคล็ดลับหลักคือการa.valueOfส่งคืนค่าใหม่ทุกครั้งเนื่องจากมีการเรียกexecใช้นิพจน์ทั่วไปด้วยgแฟล็กซึ่งทำให้เกิดการอัพเดตlastIndexนิพจน์ทั่วไปนั้นทุกครั้งที่พบการจับคู่ ดังนั้นครั้งแรกthis.r.lastIndex == 0มันจับคู่1และอัปเดตlastIndex: this.r.lastIndex == 1ดังนั้นครั้งต่อไปที่ regex จะจับคู่2และต่อไป


22
@Abdillah วัตถุ regex จะจดจำดัชนีล่าสุดที่ตรงกับการโทรexecอีกครั้งจะเริ่มค้นหาจากดัชนีนั้น MDNไม่ค่อยชัดเจน
Simon Chan

ฉันเห็นดังนั้นthis.rวัตถุ regex จำสถานะ / ดัชนี ขอบคุณ!
อับดุลลาห์

ฉันอยากจะแนะนำให้ผ่านสตริงไปexecแม้ว่าไม่ใช่จำนวนเต็มที่จะทำให้เป็นสตริง
Bergi

ใช้ regex และตอนนี้คุณมีสองปัญหา
Aleksey Solovey

191

สามารถทำได้โดยใช้สิ่งต่อไปนี้ในขอบเขตส่วนกลาง สำหรับnodejsใช้globalแทนwindowในรหัสด้านล่าง

var val = 0;
Object.defineProperty(window, 'a', {
  get: function() {
    return ++val;
  }
});
if (a == 1 && a == 2 && a == 3) {
  console.log('yay');
}

คำตอบนี้ใช้ในทางที่ผิดตัวแปรโดยนัยที่จัดทำโดยขอบเขตทั่วโลกในบริบทการดำเนินการโดยการกำหนดให้ทะเยอทะยานเพื่อดึงตัวแปร


สิ่งนี้ถือว่าaเป็นคุณสมบัติthisที่มันไม่ปรากฏ หากaเป็นตัวแปรในตัวเครื่อง (ซึ่งดูเหมือนว่า) สิ่งนี้จะไม่ทำงาน
jfriend00

1
@ jfriend00 คุณหมายถึงถ้าคุณวาง var a; บางแห่ง?
jontro

ใช่. อ้างอิงa == 1หมายถึงกว่าคือบางตัวแปรไม่ได้ทรัพย์สินของa thisในขณะที่มีสถานที่แปลก ๆ เช่นกลมซึ่งทั้งสองอาจเป็นจริงโดยทั่วไปการประกาศตัวแปรด้วยvar aหรือlet aหมายความว่าไม่มีสิ่งใดthisที่ช่วยให้คุณเข้าถึงได้aในฐานะคุณสมบัติเช่นเดียวกับคุณสมมติว่ารหัส ดังนั้นรหัสของคุณเห็นได้ชัดว่าสมมติว่าตัวแปรทั่วโลกแปลก ๆ ตัวอย่างเช่นรหัสของคุณไม่ทำงานใน node.js และไม่ได้อยู่ในโหมดเข้มงวดภายในฟังก์ชั่น คุณควรระบุสถานการณ์ที่แน่นอนว่ามันใช้งานได้และอาจอธิบายว่าทำไมมันทำงาน มิฉะนั้นจะทำให้เข้าใจผิด
jfriend00

@ jfriend00 แน่นอนดี ไม่แน่ใจว่ามันจะเพิ่มมูลค่ามากขึ้นเมื่อรวมกับคำตอบอื่น ๆ แล้ว จะอัปเดตคำตอบ
jontro

14
คำถามคือสิ่งนี้ "เคย" เป็นจริงหรือไม่ และคำตอบคือใช่และนี่เป็นหนึ่งในสถานการณ์สมมติที่อาจเป็นจริง: aไม่ใช่ตัวแปรเฉพาะที่และถูกกำหนดไว้ในขอบเขตส่วนกลางด้วยตัวเพิ่มที่เพิ่มขึ้น
Zac Delventhal

190

สิ่งนี้เป็นไปได้ในกรณีที่ตัวแปรaถูกเข้าถึงโดยพูดกับผู้ทำงานเว็บ 2 คนผ่าน SharedArrayBuffer และสคริปต์หลักบางตัว ความเป็นไปได้ต่ำ แต่ก็เป็นไปได้ว่าเมื่อรหัสจะรวบรวมรหัสเครื่องคนงานเว็บปรับปรุงตัวแปรaเพียงในเวลาดังนั้นเงื่อนไขa==1, a==2และa==3มีความพึงพอใจ

นี่อาจเป็นตัวอย่างของสภาวะการแย่งชิงในสภาพแวดล้อมแบบมัลติเธรดที่จัดทำโดยเว็บเวิร์คและ SharedArrayBuffer ใน JavaScript

นี่คือการใช้งานพื้นฐานด้านบน:

main.js

// Main Thread

const worker = new Worker('worker.js')
const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers
const sab = new SharedArrayBuffer(1)

modifiers.forEach(m => m.postMessage(sab))
worker.postMessage(sab)

worker.js

let array

Object.defineProperty(self, 'a', {
  get() {
    return array[0]
  }
});

addEventListener('message', ({data}) => {
    array = new Uint8Array(data)
    let count = 0
    do {
        var res = a == 1 && a == 2 && a == 3
        ++count
    } while(res == false) // just for clarity. !res is fine
    console.log(`It happened after ${count} iterations`)
    console.log('You should\'ve never seen this')
})

modifier.js

addEventListener('message' , ({data}) => {
    setInterval( () => {
        new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
    })
})

ใน MacBook Air ของฉันมันเกิดขึ้นหลังจากมีการทำซ้ำประมาณ 10,000 ล้านครั้งในครั้งแรก:

ป้อนคำอธิบายรูปภาพที่นี่

ความพยายามครั้งที่สอง:

ป้อนคำอธิบายรูปภาพที่นี่

อย่างที่ฉันบอกว่าโอกาสจะต่ำ แต่ให้เวลามากพอมันจะกระทบกับเงื่อนไข

เคล็ดลับ: หากระบบของคุณใช้เวลานานเกินไป ลองเท่านั้นa == 1 && a == 2และเปลี่ยนไปMath.random()*3 Math.random()*2เพิ่มมากขึ้นในรายการลดโอกาสในการกดปุ่ม


50
สุจริตนี่เป็นคำตอบที่ดีที่สุด คำตอบอื่น ๆ ทั้งหมดต้องใช้ความพยายามอย่างรอบคอบในการทำบางสิ่งบางอย่างโดยไม่ตั้งใจอย่างลึกซึ้ง คำตอบนี้สะท้อนถึงสิ่งที่อาจเกิดขึ้นในโลกแห่งความจริง - สภาพการแข่งขัน
Tom Swirly

34
ไม่เพียงแค่นั้น - ฉันได้เห็นสิ่งนี้เกิดขึ้นจริงในโลกแห่งความจริง ไม่ได้มีเงื่อนไขที่แน่นอนในคำถาม แต่แน่นอนด้วยการตรวจสอบ (a == 1) ที่จุดเริ่มต้นของฟังก์ชั่นและ (a == 2) ต่อมาในฟังก์ชั่นและมีรหัสตีทั้งสองเงื่อนไข FYI ครั้งแรกที่ฉันเห็นสิ่งนี้เกิดขึ้นในตัวควบคุมเครื่องยนต์ของรถยนต์และเราวางมาตรฐานการเข้ารหัสไว้ ครั้งที่สองอยู่ในระบบแกลบและเปลวไฟสำหรับเครื่องบินทหารและในวันแรกของฉันที่ บริษัทฉันพบสิ่งนี้และซ่อมมันในขณะที่ทีมอื่น ๆ ยังคงคุยกันถึงปัญหา (ระดับความรุ่งโรจน์: สูง! :)
เกรแฮม

38
ดังนั้นคุณได้ทำงานกับ "car engine controllers" และ "chaff and flare dispenser system" ซึ่งตั้งโปรแกรมใน javascript กับ web workers หรือไม่? ฉันไม่คิดว่าฉันจะออกไปข้างนอกอีกครั้ง
psaxton

12
@psaxton :) ไม่แน่นอน - แต่เรามีซอฟต์แวร์แบบมัลติเธรดพร้อมข้อมูลที่แชร์ นี่เป็นรูปแบบการต่อต้านสำหรับซอฟต์แวร์แบบมัลติเธรดทั้งหมดไม่เฉพาะเจาะจงกับ Javascript หรือต่อผู้ปฏิบัติงานเว็บ ไม่สำคัญว่าคุณจะเขียนโปรแกรมในภาษาแอสเซมบลี, Brainf * ck, Visual Basic, C หรือ Javascript - ถ้าคุณทำสิ่งนี้กับข้อมูลที่แชร์ในแอปพลิเคชันแบบมัลติเธรดมันจะล้มเหลวเสมอ
เกรแฮม

4
ฉันคิดว่านี่เป็นเสื้อคลุมที่ซับซ้อนรอบคำตอบของ @ jontro
qntm

148

สิ่งนี้ยังเป็นไปได้โดยใช้ชุดของตัวเขียนทับด้วยตนเอง:

(สิ่งนี้คล้ายกับโซลูชันของ jontro แต่ไม่ต้องการตัวแปรตัวนับ)

(() => {
    "use strict";
    Object.defineProperty(this, "a", {
        "get": () => {
            Object.defineProperty(this, "a", {
                "get": () => {
                    Object.defineProperty(this, "a", {
                        "get": () => {
                            return 3;
                        }
                    });
                    return 2;
                },
                configurable: true
            });
            return 1;
        },
        configurable: true
    });
    if (a == 1 && a == 2 && a == 3) {
        document.body.append("Yes, it’s possible.");
    }
})();


61
โปรดทราบว่าวิธีการของการใช้ getter ยังทำงานร่วมกับไม่เพียง=== ==
Makyen

วิธีการแก้ปัญหานี้ขึ้นอยู่thisกับวัตถุทั่วโลกในร่างกายของฟังก์ชั่นลูกศร
Roy Tinker

@Midnightas ฉันจะไม่จัดหมวดหมู่คำตอบอื่น ๆ ใด ๆ ที่เป็น"รหัสปิรามิด"
Patrick Roberts

โปรดทราบว่าวิธีนี้ใช้ได้กับคำสั่งโดยพลการด้วยใช่ไหม ชอบ(a == 3 && a == 2 && a == 1)?
โยฮันเนส

131

หรือคุณสามารถใช้คลาสสำหรับมันและอินสแตนซ์สำหรับการตรวจสอบ

function A() {
    var value = 0;
    this.valueOf = function () { return ++value; };
}

var a = new A;

if (a == 1 && a == 2 && a == 3) {
    console.log('bingo!');
}

แก้ไข

การใช้คลาส ES6 จะมีลักษณะเช่นนี้

class A {
  constructor() {
    this.value = 0;
    this.valueOf();
  }
  valueOf() {
    return this.value++;
  };
}

let a = new A;

if (a == 1 && a == 2 && a == 3) {
  console.log('bingo!');
}


5
เพียงแค่function A() {value = 0;ในช่วงเริ่มต้น?
เดฟ C

valueOfจะถูกแทนที่this method is usually called automatically by JavaScript behind the scenes, and not explicitly in codeดังนั้นเมื่อเราเปรียบเทียบค่าที่มันจริงเพิ่มขึ้น .. มี
danyal Sandeelo

130

ฉันไม่เห็นคำตอบนี้โพสต์แล้วดังนั้นฉันจะโยนคำตอบนี้ไปผสม นี่คล้ายกับคำตอบของเจฟฟ์ที่มีพื้นที่ฮันกึลแบบครึ่งความกว้าง

var a = 1;
var  = 2;
var а = 3;
if(a == 1 &&  == 2 && а == 3) {
    console.log("Why hello there!")
}

คุณอาจสังเกตเห็นความแตกต่างเล็กน้อยกับอันที่สอง แต่ตัวที่หนึ่งและตัวที่สามนั้นเหมือนกับตาเปล่า ทั้ง 3 เป็นตัวละครที่แตกต่าง:

a- ตัวพิมพ์เล็กละติน A
- ตัวกว้างแบบละตินตัวพิมพ์เล็ก A
а - ตัวพิมพ์เล็ก Cyrillic A

คำทั่วไปสำหรับสิ่งนี้คือ "homoglyphs": อักขระยูนิโค้ดที่แตกต่างกันซึ่งมีลักษณะเหมือนกัน โดยทั่วไปแล้วยากที่จะได้รับสามที่แยกไม่ออกอย่างเต็มที่ แต่ในบางกรณีคุณสามารถได้รับโชคดี A, Α, АและᎪจะทำงานได้ดีขึ้น (ละติน -A, กรีกอัลฟ่า , Cyrillic-AและCherokee-Aตามลำดับ แต่น่าเสียดายที่อักษรตัวพิมพ์เล็กกรีกและภาษาเชอโรกีแตกต่างจากละตินa: α,และอื่น ๆ doesn ไม่ช่วยตัวอย่างข้อมูลด้านบน)

มีการโจมตีแบบ Homoglyph ทั้งชั้นโดยทั่วไปมักจะเป็นชื่อโดเมนปลอม (เช่นwikipediа.org(Cyrillic) vs wikipedia.org(ละติน)) แต่สามารถแสดงเป็นรหัสได้เช่นกัน โดยทั่วไปจะเรียกว่าการใช้เล่ห์เหลี่ยม (ดังที่ได้กล่าวไว้ในความคิดเห็นคำถาม[การใช้เล่ห์เหลี่ยม]ตอนนี้เป็นหัวข้อในPPCGแต่เคยเป็นประเภทของความท้าทายที่สิ่งต่างๆเหล่านี้จะปรากฏขึ้น) ฉันใช้เว็บไซต์นี้เพื่อค้นหาคำว่า homoglyph ที่ใช้สำหรับคำตอบนี้


19
"ความคลาดเคลื่อนเล็กน้อย"ไม่ใช่วิธีที่ฉันจะเรียกมันว่า

4
@hvd ทั้งหมดขึ้นอยู่กับการแสดงผลแบบอักษรของคุณ นี่คือสิ่งที่ฉันเห็น
Draco18 ไม่ไว้วางใจ SE

1
@ Jake ใช่กรณีตัวพิมพ์ใหญ่แบบละตินกว้าง A ไม่ใช่ homoglyph ที่ยิ่งใหญ่ที่สุด (แต่ตัวอักษรตัวใหญ่น่าทึ่ง) โดยทั่วไปแม้ว่าคุณต้องการเพียงสองเพื่อให้ได้ผลที่ต้องการ
Draco18 ไม่ไว้วางใจ SE

@ Draco18s ตกลงอีกครั้ง: เพียง 2 คนเท่านั้นที่ต้องการ ทำได้ดีกับข้อมูลพิเศษเช่นกัน!
JakeSteam

10
คุณยังสามารถใช้ตัวเลือกชุดตัวแปร Unicode (U + FE00 .. U + FE0F) ไม่มีของเหล่านี้เป็น:a a︀ a︁ a︂ไม่ต้องกังวลเกี่ยวกับความคลาดเคลื่อนอีกต่อไป
Salman

108

ใช่มันเป็นไปได้! 😎

»จาวาสคริปต์

if‌=()=>!0;
var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    document.write("<h1>Yes, it is possible!😎</h1>")
}

รหัสด้านบนเป็นเวอร์ชั่นสั้น (ขอบคุณ @Forivin สำหรับบันทึกย่อในความคิดเห็น) และรหัสต่อไปนี้เป็นต้นฉบับ:

var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    //console.log("Yes, it is possible!😎")
    document.write("<h1>Yes, it is possible!😎</h1>")
}

//--------------------------------------------

function if‌(){return true;}

หากคุณเห็นด้านบนของรหัสของฉันและเรียกใช้คุณจะพูดว่า WOW ได้อย่างไร

ดังนั้นฉันคิดว่ามันเพียงพอที่จะบอกว่าใช่เป็นไปได้สำหรับคนที่พูดกับคุณ:ไม่มีอะไรที่เป็นไปไม่ได้

เคล็ดลับ: ผมใช้ตัวอักษรที่ซ่อนอยู่หลังที่จะทำให้ฟังก์ชั่นที่ชื่อของมันจะคล้ายกับif ifใน JavaScript เราไม่สามารถแทนที่คำหลักได้ดังนั้นฉันถูกบังคับให้ใช้วิธีนี้ มันเป็นของปลอมifแต่มันเหมาะกับคุณในกรณีนี้!


» C #

นอกจากนี้ฉันเขียนเวอร์ชัน C # ( ด้วยเทคนิคการเพิ่มมูลค่าทรัพย์สิน ):

static int _a;
public static int a => ++_a;

public static void Main()
{
    if(a==1 && a==2 && a==3)
    {
        Console.WriteLine("Yes, it is possible!😎");
    }
}

การสาธิตสด


56
เวอร์ชันจาวาสคริปต์เป็นอาชญากรรมที่แท้จริงต่อมนุษยชาติและความสามารถในการทำเช่นนี้ควรผิดกฎหมายโดยอนุสัญญาสหประชาชาติ ฉันคิดว่ามันเป็นเวลาที่เราจะกำจัดโลกแห่งความรู้ทั้งหมดเกี่ยวกับ javacript
ชัดเจน

2
การประกาศฟังก์ชันอาจสั้นกว่านี้ได้ if‌=()=>!0
Forivin

4
ทำไมคุณถึงใช้บนโลกนี้document.write? นั่นเป็นวิธีที่ไม่ต้องลงแรงโดยไม่คำนึงถึงคำตอบที่เหลือ
Cerbrus

3
@Cerbrus ขอขอบคุณสำหรับข้อความของคุณ ฉันเขียนคำตอบแรกของฉันด้วยconsole.logแต่ฉันเปลี่ยนเป็น document.write จริง ๆ แล้วฉันใช้console.logในรหัสของฉันเสมอแต่ที่นี่ฉันต้องการแสดงข้อความถึงผู้ใช้ในกล่องข้อมูลโค้ด StackOverflow console.logดังนั้นผมจึงอยากจะแสดงข้อความของฉันสวยกว่าข้อความที่สร้างขึ้นโดย คลิกที่Run Code Snippetปุ่มคำตอบของฉันและคำตอบอื่น ๆ SO Code Snippet ให้ฉันใช้ html และ JS และ CSS จากนั้นฉันก็อยากจะใช้มันในคำตอบและทำให้มันดี ฉันคิดว่ามันไม่ได้มีผลข้างเคียงเชิงลบใด ๆ และไม่ได้ทำให้คำตอบของฉันมีขนาดใหญ่หรือรวบรวม
RAM

1
@ ชัดเจนกว่าถ้าการประชุมสหประชาชาติสามารถเปลี่ยนแปลงโลกได้อย่างมีประสิทธิภาพเราควรจะมีโลกที่ดีกว่านี้ เราต้องการบางสิ่งมากกว่าคำสั่งใน UN และจนถึงวันนั้นฉันคิดว่าเราสามารถใช้เคล็ดลับ Javascript นี้ของฉัน;)
RAM

97

JavaScript

a == a +1

ใน JavaScript ไม่มีจำนวนเต็มแต่มีเพียงNumbers เท่านั้นที่นำมาใช้เป็นตัวเลขทศนิยมที่มีความแม่นยำสองเท่า

หมายความว่าหากตัวเลขaมีขนาดใหญ่พอจะถือว่ามีค่าเท่ากับจำนวนเต็มสามตัวติดต่อกัน:

a = 100000000000000000
if (a == a+1 && a == a+2 && a == a+3){
  console.log("Precision loss!");
}

จริงไม่ใช่สิ่งที่ผู้สัมภาษณ์ถาม (มันไม่ทำงาน a=0 ) แต่มันไม่เกี่ยวข้องกับกลอุบายใด ๆ กับฟังก์ชั่นที่ซ่อนอยู่หรือการใช้งานเกินพิกัด

ภาษาอื่น ๆ

สำหรับการอ้างอิงมีa==1 && a==2 && a==3โซลูชั่นใน Ruby และ Python ด้วยการดัดแปลงเล็กน้อยก็เป็นไปได้ใน Java

ทับทิม

ด้วยการกำหนดเอง==:

class A
  def ==(o)
    true
  end
end

a = A.new

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

หรือเพิ่มขึ้นa:

def a
  @a ||= 0
  @a += 1
end

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

หลาม

class A:
    def __eq__(self, who_cares):
        return True
a = A()

if a == 1 and a == 2 and a == 3:
    print("Don't do that!")

ชวา

เป็นไปได้ที่จะแก้ไขIntegerแคช Java :

package stackoverflow;

import java.lang.reflect.Field;

public class IntegerMess
{
    public static void main(String[] args) throws Exception {
        Field valueField = Integer.class.getDeclaredField("value");
        valueField.setAccessible(true);
        valueField.setInt(1, valueField.getInt(42));
        valueField.setInt(2, valueField.getInt(42));
        valueField.setInt(3, valueField.getInt(42));
        valueField.setAccessible(false);

        Integer a = 42;

        if (a.equals(1) && a.equals(2) && a.equals(3)) {
            System.out.println("Bad idea.");
        }
    }
}

27
@ cᴏʟᴅsᴘᴇᴇᴅ: Java, Javascript, potayto, potahto :) มีคำตอบที่ดีพออยู่แล้ว ฉันแค่คิดว่ามันน่าสนใจที่จะแสดงว่ามันสามารถทำได้ในภาษาอื่น ๆ และอาจให้ความคิดกับนักพัฒนา JS
Eric Duminil

2
@ cᴏʟᴅsᴘᴇᴇᴅ: อัปเดตด้วยตัวอย่าง JS
Eric Duminil

1
ทำไมรุ่น Java ใช้ไม่ได้กับInteger a = 42(หรือใช้งาน) ตามที่ฉันเข้าใจ autoboxing Integer a = 42; a == 1 && a == 2 && a == 3ควรใส่ ints ทั้งหมด หรือสิ่งนี้ไม่ได้เป็นกล่องสำหรับการเปรียบเทียบ?
CAD97

@ CAD97: Integer == intดูเหมือนจะส่งผลให้เลิกทำกล่อง แต่ใช้การInteger#equals(int)บังคับออโตบ็อกซิ่งดังนั้นจึงใช้งานได้ ขอบคุณสำหรับความคิดเห็น!
Eric Duminil

@StephanBijzitter: โปรดอธิบาย เท่าที่ฉันรู้มีเฉพาะNumbersใน JS ซึ่งโดยทั่วไปจะเป็นdoubleของ พวกเขาสามารถดูเหมือนจำนวนเต็มและคุณสามารถใช้พวกเขาเช่นจำนวนเต็ม แต่พวกเขายังคงไม่ได้จำนวนเต็ม ฉันไม่คิดว่าn == n + 1เคยสามารถเป็นจริงสำหรับจำนวนเต็มใน Java / หลาม / C / ทับทิม / ...
เอริค DUMINIL

80

นี้เป็นรุ่นที่กลับของ@ เจฟฟ์คำตอบ * ที่ซ่อนตัวอักษร (U + 115F, U + 1160 หรือ U + 3164) ถูกนำมาใช้ในการสร้างตัวแปรที่มีลักษณะเหมือน1, และ23

var  a = 1;
var 1 = a;
var 2 = a;
var 3 = a;
console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );

* คำตอบนั้นสามารถทำให้ง่ายขึ้นได้โดยใช้ผู้ไม่เข้าร่วมความกว้างศูนย์ (U + 200C) และผู้เข้าร่วมความกว้างศูนย์ (U + 200D) อักขระทั้งสองตัวนี้ได้รับอนุญาตภายในตัวระบุ แต่ไม่ใช่จุดเริ่มต้น:

var a = 1;
var a = 2;
var a = 3;
console.log(a == 1 && a == 2 && a == 3);

/****
var a = 1;
var a\u200c = 2;
var a\u200d = 3;
console.log(a == 1 && a\u200c == 2 && a\u200d == 3);
****/

เทคนิคอื่นเป็นไปได้โดยใช้แนวคิดเดียวกันเช่นโดยใช้ตัวเลือกชุดรูปแบบ Unicode เพื่อสร้างตัวแปรที่มีลักษณะเหมือนกัน ( a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true)


75

กฎข้อที่หนึ่งของการสัมภาษณ์ ไม่เคยพูดว่าเป็นไปไม่ได้

ไม่จำเป็นต้องใช้เล่ห์เหลี่ยมของตัวละครที่ซ่อนอยู่

window.__defineGetter__( 'a', function(){
    if( typeof i !== 'number' ){
        // define i in the global namespace so that it's not lost after this function runs
        i = 0;
    }
    return ++i;
});

if( a == 1 && a == 2 && a == 3 ){
    alert( 'Oh dear, what have we done?' );
}


6
อุ๊ยตาย __defineGetter__เป็นจริงไม่เป็นส่วนหนึ่งของภาษา js definePropertyเพียงรุ่นที่น่าเกลียดของ typeofไม่ใช่ฟังก์ชั่นและสิ่งที่ไม่ได้ประกาศiเป็นเพียงแค่ความน่ากลัว ยังดูเหมือนว่าจะมีมูลค่าเพิ่ม 40 โหวต: /
Jonas Wilms

6
@JonasW 41 upvotes :-) ฉันรู้ว่า__defineGetter__เลิกใช้แล้วต่อdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ...... แต่มันทำงานใน FireFox v 57.0.4 อย่างชัดเจนดังนั้นฉันเลือกที่จะแสดงสิ่งนี้แทนdefineProperty()เพราะรหัสดั้งเดิมเป็นของจริงและไม่สามารถปฏิเสธได้ โดยไม่คำนึงถึงความอัปลักษณ์การประกาศiในแบบที่ฉันทำนั้นเป็นพฤติกรรมที่รู้จักกันดี / เป็นเอกสาร บางทีฉันอาจจะอยู่ในอารมณ์ PCG ¯ \ _ (ツ) _ / ¯
MonkeyZeus

68

แม้ว่าจะมีวิธีที่จะประเมินว่าเป็นจริงหรือไม่ก็ตาม (และอย่างที่คนอื่น ๆ ได้แสดงมีหลายวิธี) คำตอบที่ฉันจะมองหาพูดเป็นคนที่ได้ทำการสัมภาษณ์หลายร้อยคนจะเป็นอย่างไร บางสิ่งบางอย่างตามแนวของ:

"อาจจะใช่ภายใต้สถานการณ์แปลก ๆ บางอย่างที่ไม่ชัดเจนสำหรับฉันทันที ... แต่ถ้าฉันพบสิ่งนี้ในรหัสจริงฉันจะใช้เทคนิคการตรวจแก้จุดบกพร่องทั่วไปเพื่อหาว่าทำไมมันถึงทำในสิ่งที่ทำ และจากนั้น refactor รหัสทันทีเพื่อหลีกเลี่ยงสถานการณ์นั้น ... แต่ที่สำคัญกว่านั้น: ฉันจะไม่เขียนโค้ดนั้นตั้งแต่แรกเพราะนั่นคือคำจำกัดความของรหัสที่ซับซ้อนมากและฉันพยายามไม่เขียนโค้ดที่ซับซ้อน "

ฉันเดาว่าผู้สัมภาษณ์บางคนจะขุ่นเคืองกับการมีสิ่งที่เห็นได้ชัดว่าเป็นคำถามที่ยากมาก แต่ฉันไม่รังเกียจนักพัฒนาที่มีความคิดเห็นโดยเฉพาะเมื่อพวกเขาสามารถสำรองข้อมูลด้วยความคิดที่มีเหตุผลและสามารถทำให้คำถามของฉัน คำพูดที่มีความหมายเกี่ยวกับตัวเอง


13
คำถาม (หรือคำถามสัมภาษณ์ทั้งหมด) อาจทดสอบผู้สมัครที่เต็มใจคิดเกี่ยวกับปัญหาโดยเฉพาะคำถามที่ "ชัดเจนชัดเจน" เช่นนี้ คนที่ปฏิเสธที่จะคิดเพราะพวกเขาเชื่อว่าพวกเขา "รู้" คำตอบไม่ใช่การจ้างที่ดี
Shammoo

5
@ Don Hatch No ฉันจะไม่ลงโทษพวกเขาหากพวกเขาตอบด้วยความสุจริตใจและโดยเฉพาะอย่างยิ่งหากพวกเขาให้คำตอบที่ถูกต้องเหมือนที่คนอื่น ๆ ได้แสดง ... วิธีที่ดีในการเขียนรหัสหรือไม่ การมีความรู้และความสามารถในการหาคำตอบที่ "ถูกต้อง" เป็นเพียงส่วนหนึ่งของการเป็นนักพัฒนาที่ดี สิ่งที่สำคัญยิ่งกว่าสำหรับนักพัฒนา "มืออาชีพ" คือการเขียนโค้ดที่เข้าใจและบำรุงรักษาได้บ่อยครั้งโดยนักพัฒนาที่มีความสามารถน้อยกว่า นักพัฒนาที่ฉลาดมากเกินไปนั้นค่อนข้างแย่เหมือน IME ที่ไม่สามารถใช้งานได้
Frank W. Zammetti

16
สิ่งนี้ไม่ตอบคำถาม
TylerH

6
สิ่งที่น่าเศร้าเกี่ยวกับคำตอบนี้คือผู้ใช้ 1 คนตอบว่าเมื่อวานนี้และมีคะแนนโหวต 2 คนทำให้เขาลบคำถามนี้
Jonas Wilms

8
@JohnColeman คำถามถามว่ารหัสสามารถประเมินเป็นจริง ไม่ถามถึงเหตุผลที่ผู้สัมภาษณ์เสนอคำถามตั้งแต่แรก คำตอบนี้ไม่แม้แต่จะพยายามตอบคำถามที่ถูกถามและมุ่งเน้นไปที่เวอร์ชั่น "สิ่งที่ฉันจะทำ" โดยพยายามคาดเดาว่าจุดประสงค์ของผู้สัมภาษณ์คืออะไร ถ้านั่นเป็นคำถามที่ถามก็คงจะกว้างเกินไป ดังนั้นคำตอบนี้ไม่ได้อยู่ที่นี่หรือที่ใดก็ได้ในเว็บไซต์
TylerH

43

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

  1. การเข้ารหัส : ในกรณีนี้ตัวแปรที่คุณกำลังดูไม่ใช่สิ่งที่คุณคิดว่าเป็น สิ่งนี้อาจเกิดขึ้นได้หากคุณจงใจยุ่งกับ Unicode โดยใช้homoglyphsหรือspace spaceเพื่อทำให้ชื่อของตัวแปรดูคล้ายกับตัวแปรอื่น แต่ปัญหาการเข้ารหัสยังสามารถนำไปใช้โดยไม่ตั้งใจเช่นเมื่อคัดลอกและวางโค้ดจากเว็บที่มีรหัส Unicode ที่ไม่คาดคิด คะแนน (เช่นเนื่องจากระบบการจัดการเนื้อหาทำ "การจัดรูปแบบอัตโนมัติ" บางอย่างเช่นการแทนที่flด้วย Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)

  2. สภาพการแข่งขัน : สภาพการแข่งขันอาจเกิดขึ้นเช่นสถานการณ์ที่โค้ดไม่ได้ดำเนินการตามลำดับที่ผู้พัฒนาคาดหวัง เงื่อนไขการแข่งขันมักจะเกิดขึ้นในรหัสแบบมัลติเธรด แต่หลายเธรดไม่จำเป็นสำหรับเงื่อนไขการแข่งขันที่เป็นไปได้ - asynchronicity เพียงพอ (และไม่สับสน, async ไม่ได้หมายความว่ามีการใช้เธรดหลายรายการภายใต้ประทุน )

    โปรดทราบว่า JavaScript จึงไม่ปลอดจากเงื่อนไขการแข่งขันเพียงเพราะเป็นเธรดเดี่ยว ดูที่นี่สำหรับตัวอย่างของเธรดเดี่ยว - แต่ async - ง่ายๆ ในบริบทของคำสั่งเดียวสภาพการแข่งขันจะค่อนข้างยากที่จะตีใน JavaScript

    จาวาสคริปต์กับคนทำงานเว็บนั้นแตกต่างกันเล็กน้อยเนื่องจากคุณสามารถมีหลายเธรด @mehulmpt ได้แสดงให้เราดีหลักฐานของแนวคิดโดยใช้คนงานเว็บ

  3. ผลข้างเคียง : ผลข้างเคียงของการดำเนินการเปรียบเทียบความเท่าเทียมกัน (ซึ่งไม่จำเป็นต้องชัดเจนเหมือนในตัวอย่างที่นี่บ่อยครั้งที่ผลข้างเคียงนั้นบอบบางมาก)

ปัญหาประเภทนี้สามารถปรากฏในภาษาการเขียนโปรแกรมมากมายไม่เพียง แต่ JavaScript ดังนั้นเราจึงไม่เห็นJavaScript WTFsแบบคลาสสิกที่นี่1 1

แน่นอนว่าคำถามสัมภาษณ์และตัวอย่างที่นี่ล้วนดูเป็นสิ่งที่วางแผนไว้มาก แต่พวกเขาเป็นเครื่องเตือนใจที่ดีว่า:

  • ผลข้างเคียงอาจเป็นที่น่ารังเกียจจริงๆและโปรแกรมที่ออกแบบมาอย่างดีควรปราศจากผลข้างเคียงที่ไม่พึงประสงค์
  • สถานะที่มีหลายเธรดและไม่แน่นอนอาจเป็นปัญหาได้
  • การไม่เข้ารหัสอักขระและการประมวลผลสตริงที่ถูกต้องอาจทำให้เกิดข้อบกพร่องที่น่ารังเกียจ

1ตัวอย่างเช่นคุณสามารถหาตัวอย่างในการเขียนโปรแกรมภาษาที่แตกต่างกันโดยสิ้นเชิง (C #) ความ exhibiting ผลข้างเคียง (เห็นได้ชัดอย่างใดอย่างหนึ่ง) ที่นี่


1
จากนั้นคำถามก็กว้างเกินไป ภาษาที่แตกต่างสามารถใช้สิ่งนี้ได้อย่างง่ายดาย คำถามได้รับแรงฉุดมากเนื่องจากเป็นคำถามและคำตอบเฉพาะของ JS แต่นั่นเป็นเพียง 2c ของฉัน
cs95

1
สาเหตุต่างจาก C # และจาวาสคริปต์ดังนั้นคำตอบนี้ไม่ถูกต้อง
Edwin

3
@Edwin: สาเหตุเหมือนกันทุกประการ: Unicode เล่นซอกับร่ายมนตร์ที่มีลักษณะคล้ายกันหรืออักขระเว้นวรรคสภาพการแข่งขันหรือผลข้างเคียงของการดำเนินการเปรียบเทียบ (หลังถูกแสดงในตัวอย่างของฉัน)
Dirk Vollmar

2
@ cᴏʟᴅsᴘᴇᴇᴅ: บางครั้งการมองสิ่งต่าง ๆ จากมุมที่กว้างขึ้นจะช่วยให้เห็นปัญหาที่แท้จริง
Dirk Vollmar

3
ฉันหวังว่าคำตอบนี้สามารถติดแท็กให้กับคำถามนี้ได้บางวิธี "เมตา" หลังจากที่ได้อ่านทุกคำตอบข้างต้นนั้นผมถูกทิ้งความรู้สึกเหมือนมี JS ดังนั้นหลุมจำนวนมาก แต่คุณก็สรุปได้ทุกคำตอบในหนึ่งไป และคุณทำในลักษณะที่ทำให้คำถามนี้กลายเป็นคำถามสัมภาษณ์ดารา (ถ้าลบแท็กเฉพาะภาษา) ในความคิดของฉัน ไชโย!
KCE

41

นี่คือรูปแบบอื่นโดยใช้อาร์เรย์เพื่อแสดงค่าที่คุณต้องการ

const a = {
  n: [3,2,1],
  toString: function () {
    return a.n.pop();
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Yes');
}


31

โอเคแฮ็คอีกเครื่องที่มีกำเนิด:

const value = function* () {
  let i = 0;
  while(true) yield ++i;
}();

Object.defineProperty(this, 'a', {
  get() {
    return value.next().value;
  }
});

if (a === 1 && a === 2 && a === 3) {
  console.log('yo!');
}


คุณบอกว่าแฮ็ค แต่ฉันค่อนข้างแน่ใจว่านี่เป็นกรณีการใช้งานของเครื่องกำเนิดไฟฟ้า ... :) (ดียกเว้นว่าสิ่งนี้จะขึ้นอยู่thisกับวัตถุหน้าต่าง)
โคดี้ G

29

ใช้พร็อกซี่ :

var a = new Proxy({ i: 0 }, {
    get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name],
});
console.log(a == 1 && a == 2 && a == 3);

ผู้รับมอบฉันทะโดยทั่วไปแกล้งทำเป็นวัตถุเป้าหมาย (พารามิเตอร์แรก) แต่การสกัดกั้นการดำเนินการบนวัตถุเป้าหมาย (ในกรณีนี้การดำเนินงาน "รับทรัพย์สิน") เพื่อให้มีโอกาสที่จะทำสิ่งอื่นนอกเหนือจากพฤติกรรมวัตถุเริ่มต้น ในกรณีนี้การกระทำ "รับทรัพย์สิน" จะถูกเรียกaเมื่อ==coerces ประเภทของมันเพื่อเปรียบเทียบกับแต่ละหมายเลข สิ่งนี้เกิดขึ้น:

  1. เราสร้างวัตถุเป้าหมาย{ i: 0 }ที่ที่iคุณสมบัติเป็นตัวนับของเรา
  2. เราสร้างพร็อกซีสำหรับวัตถุเป้าหมายและกำหนดให้ a
  3. สำหรับแต่ละa ==การเปรียบเทียบaประเภทจะถูกบังคับให้มีค่าดั้งเดิม
  4. การข่มขู่ประเภทนี้ส่งผลให้เกิดการโทร a[Symbol.toPrimitive]()ภายใน
  5. พร็อกซีสกัดกั้นการรับ a[Symbol.toPrimitive]ฟังก์ชันโดยใช้ "get handler"
  6. ของพร็อกซี่ "ได้รับการจัดการ" การตรวจสอบว่าทรัพย์สินที่ถูกอากาศคือในกรณีที่เพิ่มขึ้นและจากนั้นส่งกลับเคาน์เตอร์จากวัตถุเป้าหมายไปนี้:Symbol.toPrimitive ++target.iหากมีการเรียกคืนคุณสมบัติอื่นเราเพียงถอยกลับไปคืนค่าคุณสมบัติเริ่มต้นtarget[name]

ดังนั้น:

var a = ...; // a.valueOf == target.i == 0
a == 1 && // a == ++target.i == 1
a == 2 && // a == ++target.i == 2
a == 3    // a == ++target.i == 3

เช่นเดียวกับคำตอบอื่น ๆ ส่วนใหญ่จะใช้งานได้กับการตรวจสอบความเท่าเทียมกันแบบหลวม ( ==) เนื่องจากการตรวจสอบความเท่าเทียมกันอย่างเข้มงวด ( ===) ไม่ได้พิมพ์คำบีบบังคับที่พร็อกซีสามารถสกัดกั้นได้


2
ไม่มีจุดใช้พร็อกซีสำหรับสิ่งนี้แม้ว่า - การกำหนดSymbol.toPrimitiveในลักษณะเดียวกันกับวัตถุจะทำงานได้ดี
Ry-

27

ที่จริงแล้วคำตอบสำหรับส่วนแรกของคำถามคือ "ใช่" ในทุกภาษาการเขียนโปรแกรม ตัวอย่างเช่นนี่เป็นกรณีของ C / C ++:

#define a   (b++)
int b = 1;
if (a ==1 && a== 2 && a==3) {
    std::cout << "Yes, it's possible!" << std::endl;
} else {
    std::cout << "it's impossible!" << std::endl;
}

27
ฉันไม่คิดว่ามันเป็นไปได้ในทุกภาษาการเขียนโปรแกรม ไม่ใช่ทุกภาษาที่มีตัวประมวลผลล่วงหน้าตัวอย่างเช่น สำหรับเรื่องนั้นไม่ใช่ทุกภาษาใช้&&สำหรับตรรกะ "และ"
Keith Thompson

3
ฉันพบวิธีที่ใช้งานได้ทั้งในPythonและC ++ซึ่งใช้ตัวดำเนินการโอเวอร์โหลด
โดนัลด์ดั๊ก

7
และคุณสามารถทำได้ใน Java โดยใช้การสะท้อนและ messing up แคชจำนวนเต็ม
CAD97

7
ไม่สามารถทำมันในภาษาที่สนับสนุน woudn't การกลายพันธุ์ในจุดนั้นเช่นไม่มีอะไรเทียบได้มีอยู่ใน Haskell
เจสันคาร์

4
คำถามนี้ถามเกี่ยวกับ JavaScript ไม่ใช่ C ++
คนงานทุกคนมีความสำคัญ

26

เหมือนกัน แต่แตกต่างกัน แต่ยังคงเหมือนเดิม (สามารถ "ทดสอบ" หลายครั้ง):

const a = { valueOf: () => this.n = (this.n || 0) % 3 + 1}
    
if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

ความคิดของฉันเริ่มต้นจากการทำงานของสมการประเภทวัตถุ Number


4
ทำงานครั้งที่สองด้วย!
ซัลมา

25

คำตอบ ECMAScript 6 ที่ใช้ประโยชน์จาก Symbols:

const a = {value: 1};
a[Symbol.toPrimitive] = function() { return this.value++ };
console.log((a == 1 && a == 2 && a == 3));

เนื่องจาก==การใช้งานจาวาสคริควรจะบีบบังคับให้aเป็นสิ่งที่ใกล้เคียงกับตัวถูกดำเนินการสอง ( 1, 2, 3ในกรณีนี้) แต่ก่อนที่จะพยายามที่จะร่าง coercing ในตัวเอง JavaScript Symbol.toPrimitiveก็พยายามที่จะเรียก หากคุณระบุSymbol.toPrimitiveJavaScript จะใช้ค่าที่ฟังก์ชันของคุณส่งคืน ถ้าไม่ได้, JavaScript valueOfจะเรียก


24

ฉันคิดว่านี่เป็นรหัสขั้นต่ำที่จะใช้:

i=0,a={valueOf:()=>++i}

if (a == 1 && a == 2 && a == 3) {
  console.log('Mind === Blown');
}

การสร้างวัตถุจำลองด้วยการกำหนดเองvalueOfที่เพิ่มตัวแปรส่วนกลางiในการโทรแต่ละครั้ง 23 ตัวอักษร!


14

อันนี้ใช้ defineProperty พร้อมกับผลข้างเคียงที่ดีที่ทำให้เกิดตัวแปรโกลบอล!

var _a = 1

Object.defineProperty(this, "a", {
  "get": () => {
    return _a++;
  },
  configurable: true
});

console.log(a)
console.log(a)
console.log(a)


8
คุณสามารถใช้การปิดบัญชีได้a: get: (a => () => ++a)(0),ไม่จำเป็นต้องใช้ทั่วโลก
Nina Scholz

13
@NinaScholz แน่นอน แต่เรากำลังพูดถึงการปฏิบัติที่ไม่ดีที่นี่ - ให้ฉันได้: D
เบ็น Aubin

1

โดยการเอาชนะvalueOfในการประกาศคลาสก็สามารถทำได้:

class Thing {
    constructor() {
        this.value = 1;
    }

    valueOf() {
        return this.value++;
    }
}

const a = new Thing();

if(a == 1 && a == 2 && a == 3) {
    console.log(a);
}

สิ่งที่เกิดขึ้นคือสิ่งที่valueOfเรียกว่าในแต่ละตัวดำเนินการเปรียบเทียบ ในวันแรกaจะเท่ากัน1ในวันที่สองaจะเท่ากัน2และต่อ ๆ ไปเพราะแต่ละครั้งvalueOfมีการเรียกค่าของaจะเพิ่มขึ้น

ดังนั้น console.log จะใช้ไฟและเอาท์พุท (ในเทอร์มินัลของฉัน) Thing: { value: 4}แสดงว่าเงื่อนไขเป็นจริง

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