Câu hỏi Có thể (a == 1 && a == 2 && a == 3) từng đánh giá đúng không?


Ghi chú của người kiểm duyệt: Vui lòng chống lại yêu cầu chỉnh sửa mã hoặc xóa thông báo này. Mẫu khoảng trắng có thể là một phần của câu hỏi và do đó không được giả mạo không cần thiết. Nếu bạn đang ở trong "khoảng trắng là không đáng kể" trại, bạn sẽ có thể chấp nhận mã như vậy.

Có bao giờ có thể (a== 1 && a ==2 && a==3) có thể đánh giá true trong JavaScript?

Đây là một câu hỏi phỏng vấn được hỏi bởi một công ty công nghệ lớn. Nó xảy ra hai tuần trước, nhưng tôi vẫn đang cố tìm câu trả lời. Tôi biết chúng tôi không bao giờ viết mã như vậy trong công việc hàng ngày của chúng tôi, nhưng tôi tò mò.


2253
2018-01-15 20:20


gốc


Đây là một câu hỏi phỏng vấn tuyệt vời. Tôi chưa bao giờ gặp cái này (hoặc một cái như thế này) bản thân mình, nhưng điều này tốt hơn nhiều so với cái mà tôi đã nghe về việc liên quan đến việc tìm kiếm các vòng trong các danh sách liên kết. Nó vẫn còn bị đánh lừa và tôi sẽ không loại trừ một người nào đó trong câu hỏi này một mình, nhưng tôi chắc chắn sẽ ủng hộ các ứng cử viên có thể nhận ra rằng một cái gì đó underhanded có thể đang xảy ra. - Draco18s
Nếu điều này phần nào đại diện cho loại mã nằm trong codebase của công ty đó ... hãy chạy ‍️ - FeifanZ
Đây chỉ là câu hỏi phỏng vấn đơn giản ... - ghord
Đối với những người dường như đã bỏ phiếu cho điều này quá rộng: là đào tại Javascript, nói rằng có quá nhiều câu trả lời hợp lệ? - tomsmeding
Ghi chú của người kiểm duyệt: Stack Overflow đã có một lịch sử của những người chiming in với câu trả lời trong các ngôn ngữ khác nhau cho một trong những câu hỏi. Những là cố gắng trả lời câu hỏi vì chúng là giải pháp cho vấn đề chung, mặc dù trong một ngôn ngữ khác. Vui lòng không gắn cờ chúng là "không phải là câu trả lời". Có nói rằng, xin vui lòng cũng không đăng câu trả lời nhiều hơn trong các ngôn ngữ khác nhau - có một lý do câu hỏi này là cụ thể cho JavaScript, như chỉ ra bởi ý kiến ​​theo một số các câu trả lời khác, và có một lý do chúng tôi thích câu hỏi ngôn ngữ cụ thể của chúng tôi để duy trì như vậy. - BoltClock♦


Các câu trả lời:


Nếu bạn tận dụng lợi thế của làm sao == công trinh, bạn có thể chỉ cần tạo một đối tượng với một tùy chỉnh toString (hoặc là valueOf) chức năng thay đổi những gì nó trả về mỗi lần nó được sử dụng sao cho nó thỏa mãn cả ba điều kiện.

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

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


Lý do công trình này là do việc sử dụng các nhà điều hành bình đẳng lỏng lẻo. Khi sử dụng bình đẳng lỏng lẻo, nếu một trong các toán hạng thuộc loại khác với động cơ khác, động cơ sẽ cố gắng chuyển đổi một cái khác. Trong trường hợp của một đối tượng ở bên trái và một số ở bên phải, nó sẽ cố chuyển đổi đối tượng thành một số bằng cách gọi trước valueOf nếu nó được gọi, và thất bại, nó sẽ gọi toString. Tôi đã sử dụng toString trong trường hợp này đơn giản chỉ vì đó là những gì tôi nghĩ, valueOf sẽ có ý nghĩa hơn. Nếu tôi thay vì trả lại một chuỗi từ toString, động cơ sẽ cố gắng chuyển đổi chuỗi thành một số cho chúng ta kết quả cuối cùng, mặc dù với đường dẫn dài hơn một chút.


3097
2018-01-15 20:35



Bạn có thể đạt được điều này bằng cách thay đổi hàm ý valueOf() hoạt động? - Sterling Archer
Có, valueOf hoạt động thay cho toString vì cùng một lý do - Kevin B
Nhận xét không dành cho thảo luận mở rộng; cuộc hội thoại này đã đã chuyển sang trò chuyện. - deceze♦
Theo điều này chuyển đổi số sẽ được thử trước valueOf là tốt hơn một chút. - Salman A
@Pureferret phía bên trái của so sánh bình đẳng là một đối tượng, không phải là một số. Rằng đối tượng đó có thuộc tính số trên i không làm phiền động cơ. ;) - tomsmeding


Tôi không thể cưỡng lại được - những câu trả lời khác chắc chắn là đúng, nhưng bạn thực sự không thể đi qua đoạn mã sau:

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

Lưu ý khoảng cách kỳ lạ trong if tuyên bố (mà tôi đã sao chép từ câu hỏi của bạn). Đó là Hangul nửa chiều rộng (đó là tiếng Hàn cho những người không quen thuộc) là một ký tự không gian Unicode không được diễn giải bởi kịch bản ECMA như một ký tự khoảng trắng - điều này có nghĩa là nó là ký tự hợp lệ cho số nhận dạng. Vì vậy, có ba biến hoàn toàn khác nhau, một với Hangul sau khi một, một với nó trước và cuối cùng chỉ với một. Thay thế không gian bằng _ để dễ đọc, mã giống như sau:

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

Kiểm tra xác thực trên trình xác nhận tên biến của Mathias. Nếu khoảng cách kỳ lạ đó thực sự được đưa vào câu hỏi của họ, tôi cảm thấy chắc chắn đó là một gợi ý cho loại câu trả lời này.

Đừng làm thế. Nghiêm túc.

Chỉnh sửa: Tôi nhận thấy rằng (mặc dù không được phép bắt đầu biến) Công cụ ghép không có chiều rộng bằng 0 và Không-joiner các ký tự cũng được cho phép trong các tên biến - xem Làm xáo trộn JavaScript với các ký tự có độ rộng bằng 0 - ưu và nhược điểm?.

Điều này sẽ giống như sau:

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!")
}


1917
2018-01-16 05:14



Đánh giá bởi khoảng cách kỳ lạ trong câu hỏi ban đầu, tôi nghĩ đây chính là câu trả lời mà câu hỏi phỏng vấn đang tìm kiếm - khai thác các ký tự không gian trông giống như không gian. Điểm tốt! - Baracus
@Baracus Đó là RonJohn, người chú ý đến khoảng cách kỳ lạ trong bình luận của anh về câu trả lời của Kevin, điều này khiến tôi nhớ đến kỹ thuật này (khủng khiếp), vì vậy tôi không thể nhận được tín dụng để phát hiện ra nó. Tôi đã rất ngạc nhiên khi không ai đã trả lời với điều này mặc dù, vì nó đã đi xung quanh công việc của tôi một vài năm trước đây vì một bài đăng blog ở đâu đó - tôi đã cho rằng đó là một kiến ​​thức khá phổ biến. - Jeff
Tất nhiên, điều này bị cấm như một lỗ hổng tiêu chuẩn, cũng áp dụng cho các cuộc phỏng vấn. [cần dẫn nguồn] - Sanchises
Xem xét khoảng cách ban đầu, nó có thể còn tồi tệ hơn, tức là một biến var ᅠ2 = 3 đã được dùng; do đó, có ba biến aᅠᅠ= 1, ᅠ2 = 3, a = 3 (a␣ = 1, ␣2 = 3, a = 3, để (a␣==1 && a==␣2 && a==3))… - Holger
@ EdmundReed: Tôi có thể tưởng tượng một nhân vật sai lầm xâm nhập vào mã nguồn, và sau đó tất cả mọi người có ác quỷ của một công việc cố gắng tìm lỗi. (Đặc biệt nếu ai đó đang viết mã ở Hàn Quốc.) - Martin Bonner


ĐIỀU ĐÓ LÀ CÓ THỂ!

var i = 0;

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

Điều này sử dụng một getter bên trong của một with tuyên bố để cho a đánh giá ba giá trị khác nhau.

... điều này vẫn không có nghĩa là điều này nên được sử dụng trong mã thực ...


567
2018-01-15 20:35



Có, tôi đã cố gắng điều tương tự :) Vì vậy, câu trả lời đúng trong cuộc phỏng vấn sẽ là, "Nó không thể xảy ra trong của tôi mã vì tôi không bao giờ sử dụng with. " - Pointy
@Pointy - Và, tôi lập trình ở chế độ nghiêm ngặt with không được phép. - jfriend00
@Pointy trong câu trả lời được chấp nhận họ làm một cái gì đó tương tự mà không có with để nó có thể xảy ra - Jungkook
@ JonasW. Rất nhiều người vẫn sử dụng == nhưng tôi chưa từng thấy with vì ... thực sự không bao giờ nằm ​​ngoài tài liệu JS, nơi nó nói "xin đừng dùng nó". Dù sao, một giải pháp tốt đẹp. - wortwart
@Pointy Bạn có thể làm điều đó mà không cần with: stackoverflow.com/a/48288170/65387 - mpen


Ví dụ không có getters hoặc valueOf:

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

Điều này hoạt động vì == gọi toString cuộc gọi nào .join cho mảng.

Một giải pháp khác, sử dụng Symbol.toPrimitive tương đương với ES6 toString/valueOf:

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

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


431
2018-01-17 11:37



without valueOf, vâng ... nó gián tiếp hơn nhưng về cơ bản là giống nhau. - Jonas Wilms
Tôi thực sự thích giải pháp này bởi vì bạn không ghi đè bất cứ điều gì nhưng các đối tượng sở hữu chức năng tham gia, và nó chỉ là một hack rất sạch sẽ và dễ đọc mà làm cho logic đánh giá đúng sự thật. - Alex Pedersen
Thành thật mà nói tôi nghĩ đây là câu trả lời tốt nhất. Nó không liên quan gì đến điều bình thường, chỉ cần thiết lập một vài giá trị. Rất dễ hiểu ngay cả với kiến ​​thức JS cơ bản. Làm tốt. - Zac Delventhal
Điều này làm cho rất nhiều ý nghĩa nó gần như cảm thấy hữu ích. - Andrew
Tôi biết hầu hết các câu trả lời sẽ là lạm dụng toString hoặc là valueOf nhưng cái này khiến tôi hoàn toàn mất cảnh giác. Rất thông minh và tôi không biết nó đã gọi .jointrong nội bộ, nhưng nó có ý nghĩa tổng thể. - GBarroso


Nếu nó được hỏi nếu nó có thể (không PHẢI), nó có thể yêu cầu "a" trả về một số ngẫu nhiên. Nó sẽ là đúng nếu nó tạo ra 1, 2, và 3 tuần tự.

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;
    }
  }
}


249
2018-01-16 06:21



Horray cho - bogosort-- bogogeneration? - Baldrickk
Tôi cố tình đưa ra câu trả lời này ngay cả khi tôi biết các giải pháp khác, bởi vì nó trả lời câu hỏi nhưng rõ ràng không phải là những gì họ đã làm sau đó. Chơi trò chơi ngu ngốc, giành giải thưởng ngu ngốc. - Edmund Reed
Nhưng nếu cần nhiều hơn 1000 thử nghiệm thì sao? - Piyin
@Piyin Nếu phải mất hơn 1000 thử nghiệm bạn giành được giải thưởng! - Skeets
Tôi thích câu trả lời này bởi vì lấy nó đến cùng cực cho thấy rằng điều này là có thể bất kì ngôn ngữ nếu thanh ghi / bộ nhớ của cpu bị ảnh hưởng với đủ các tia vũ trụ trong khi chương trình đang chạy, hoặc nếu một cố tình thực hiện một trục trặc điện sao cho nhánh thất bại của điều kiện nếu không thực sự nhảy. - Ponkadoodle


Khi bạn không thể làm bất cứ điều gì mà không có biểu thức chính quy:

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

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

Nó hoạt động vì tùy chỉnh valueOf phương thức được gọi khi Object so với nguyên thủy (như Số). Bí quyết chính là a.valueOf trả về giá trị mới mỗi lần bởi vì nó đang gọi exec trên biểu thức chính quy với g cờ, gây ra cập nhật lastIndex của biểu thức chính quy đó mỗi lần khớp được tìm thấy. Vì vậy, lần đầu tiên this.r.lastIndex == 0, nó phù hợp 1 và cập nhật lastIndex: this.r.lastIndex == 1, vì vậy thời gian tới regex sẽ khớp 2 và vân vân.


196
2018-01-16 19:35



Umm .. nó hoạt động như thế nào? - Abdillah
@Abdillah một đối tượng regex sẽ nhớ chỉ mục cuối cùng phù hợp, gọi exec một lần nữa sẽ bắt đầu tìm kiếm từ chỉ mục đó. MDN không rõ lắm. - Simon Chan
Tôi hiểu rồi, vậy nên this.r đối tượng regex nhớ trạng thái / chỉ mục. Cảm ơn! - Abdillah
! - Patrick Roberts
Tôi khuyên bạn nên chuyển một chuỗi exec mặc dù, không phải là một số nguyên được xâu chuỗi. - Bergi


Nó có thể được thực hiện bằng cách sử dụng sau đây trong phạm vi toàn cầu. Dành cho nodejs sử dụng global thay vì window trong mã bên dưới.

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

Câu trả lời này lạm dụng các biến tiềm ẩn được cung cấp bởi phạm vi toàn cục trong ngữ cảnh thực thi bằng cách định nghĩa một getter để lấy biến.


183
2018-01-15 20:37



Giả định này a là tài sản của this mà nó không xuất hiện. Nếu a là một biến cục bộ (mà nó trông giống như), sau đó điều này sẽ không hoạt động. - jfriend00
@ jfriend00 bạn có nghĩa là nếu bạn đặt var a; một vài nơi? - jontro
Ừ. Tham chiếu a == 1 ngụ ý hơn a là một biến ở đâu đó, không phải là tài sản của this. Trong khi có một nơi kỳ quặc như hình cầu, nơi cả hai có thể đúng, nói chung, khai báo một biến với var a hoặc là let a có nghĩa là không có this cho phép bạn truy cập a như một tài sản như bạn đang giả định mã. Vì vậy, mã của bạn dường như giả định một số điều biến toàn cầu kỳ lạ. Ví dụ: mã của bạn không hoạt động trong node.js và không hoạt động ở chế độ nghiêm ngặt bên trong một hàm. Bạn nên xác định các trường hợp chính xác mà nó hoạt động và có thể giải thích lý do tại sao nó hoạt động. Nếu không, nó gây hiểu lầm. - jfriend00
@ jfriend00 cũng chắc chắn. Không chắc chắn rằng nó sẽ thêm giá trị nhiều hơn nữa kết hợp với các câu trả lời khác đã được trả lời. Sẽ cập nhật câu trả lời - jontro
Câu hỏi đặt ra là, điều này có thể "đúng" không. Và câu trả lời là có, và đây là một trong những tình huống mà nó có thể đúng: a không phải là một biến cục bộ và được định nghĩa trên phạm vi toàn cục với một getter tăng dần. - Zac Delventhal


Điều này có thể xảy ra trong trường hợp biến a được truy cập bởi, giả sử 2 nhân viên web thông qua SharedArrayBuffer cũng như một số tập lệnh chính. Khả năng là thấp, nhưng có thể là khi mã được biên dịch thành mã máy, công nhân web cập nhật biến a chỉ trong thời gian để các điều kiện a==1, a==2 và a==3 hài lòng.

Đây có thể là một ví dụ về điều kiện chủng tộc trong môi trường đa luồng được cung cấp bởi công nhân web và SharedArrayBuffer trong JavaScript.

Đây là cách thực hiện cơ bản ở trên:

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
    })
})

Trên MacBook Air của tôi, nó xảy ra sau khoảng 10 tỷ lần lặp lại trong lần thử đầu tiên:

enter image description here

Lần thứ hai:

enter image description here

Như tôi đã nói, cơ hội sẽ thấp, nhưng đã đủ thời gian, nó sẽ rơi vào tình trạng.

Mẹo: Nếu quá lâu trên hệ thống của bạn. Chỉ thử a == 1 && a == 2 và thay đổi Math.random()*3 đến Math.random()*2. Thêm nhiều hơn và nhiều hơn nữa để danh sách giảm cơ hội đánh.


171
2018-01-17 07:39



Thành thật mà nói, đây là câu trả lời tốt nhất. Tất cả các câu trả lời khác đòi hỏi một nỗ lực cố ý để làm một cái gì đó sâu sắc không trực quan. Câu trả lời này thực sự phản ánh điều gì đó có thể xảy ra trong thế giới thực - một điều kiện chủng tộc. - Tom Swirly
Không chỉ vậy - tôi đã thực sự thấy điều này xảy ra trong thế giới thực. Không phải với điều kiện chính xác trong câu hỏi, nhưng chắc chắn với việc kiểm tra (a == 1) khi bắt đầu một hàm và (a == 2) sau đó trong hàm, và có mã nhấn cả hai điều kiện. FYI, lần đầu tiên tôi thấy điều này xảy ra là trong một bộ điều khiển động cơ xe hơi, và chúng tôi đặt các tiêu chuẩn mã hóa tại chỗ. Lần thứ hai là trong một hệ thống phân phối chaff và flare cho máy bay quân sự, và trên ngày đầu tiên tại công ty Tôi tìm thấy điều này và sửa nó, trong khi phần còn lại của nhóm vẫn đang thảo luận vấn đề. (Mức kudo: cao! :) - Graham
Vì vậy, bạn đã làm việc trên "bộ điều khiển động cơ xe hơi" và "chaff và flare hệ thống phân phối" được lập trình trong javascript với công nhân web? Tôi không nghĩ mình sẽ ra ngoài nữa. - psaxton
@psaxton :) Tất nhiên là không - nhưng chúng tôi có phần mềm đa luồng với dữ liệu được chia sẻ. Đây là một mô hình chống cho tất cả các phần mềm đa luồng, không dành riêng cho Javascript hoặc cho các công nhân web. Nó không quan trọng cho dù bạn đang lập trình trong ngôn ngữ lắp ráp, Brainf * ck, Visual BASIC, C hoặc Javascript - nếu bạn làm điều này với dữ liệu được chia sẻ trong một ứng dụng đa luồng, nó Se luôn luôn Thất bại. - Graham
Tôi nghĩ rằng đây là một wrapper phức tạp xung quanh câu trả lời của @ jontro. - qntm