(A == 1 && a == 2 && a == 3) có bao giờ đánh giá thành true không?

2525
Dimpu Aravind Buddha 2018-01-16 10:20.

Lưu ý của người điều hành: Vui lòng không muốn 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 nên giả mạo một cách không cần thiết. Nếu bạn đang ở trong trại "khoảng trắng là không đáng kể", bạn sẽ có thể chấp nhận mã như hiện tại.

Có bao giờ điều đó (a== 1 && a ==2 && a==3)có thể đánh giá truetrong JavaScript không?

Đâ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ố gắng 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 mình, nhưng tôi tò mò.

26 answers

3364
Kevin B 2018-01-16 10:35.

Nếu bạn tận dụng được cách thức ==hoạt động , bạn có thể chỉ cần tạo một đối tượng với một hàm toString(hoặc valueOf) tùy chỉnh thay đổi những gì nó trả về mỗi khi 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 điều này hoạt động là do việc sử dụng toán tử bình đẳng lỏng lẻo. Khi sử dụng đẳng thức lỏng, nếu một trong các toán hạng có kiểu khác với toán hạng khác, công cụ sẽ cố gắng chuyển đổi từ này sang kiểu kia. Trong trường hợp một đối tượng ở bên trái và một số ở bên phải, nó sẽ cố gắng chuyển đổi đối tượng thành một số bằng cách gọi đầu tiên valueOfnếu nó có thể gọi được, và thất bại, nó sẽ gọi toString. Tôi sử dụng toStringtrong trường hợp này đơn giản vì đó là những gì tôi nghĩ đến, valueOfsẽ có ý nghĩa hơn. Thay vào đó, nếu tôi trả về một chuỗi từ đó toString, thì công cụ sẽ cố chuyển đổi chuỗi thành một số cho chúng ta cùng một kết quả cuối cùng, mặc dù với một đường dẫn dài hơn một chút.

2074
Jeff 2018-01-16 19:14.

Tôi không thể cưỡng lại - các câu trả lời khác chắc chắn là đúng, nhưng bạn thực sự không thể vượt 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 ifcâu lệnh (mà tôi đã sao chép từ câu hỏi của bạn). Đó là Hangul nửa độ rộng (đó là tiếng Hàn đối với những người không quen thuộc) là một ký tự dấu cách Unicode không được tập lệnh ECMA giải thích là một ký tự khoảng trắng - điều này có nghĩa là nó là một ký tự hợp lệ cho một số nhận dạng. Do đó, có ba biến hoàn toàn khác nhau, một với Hangul sau dấu a, một với nó trước và biến cuối cùng chỉ với a. Thay thế khoảng trắng bằng _để dễ đọc, mã tương tự sẽ 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 rằng đó là một gợi ý cho loại câu trả lời này.

Đừng làm điều này. 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 một biến), các ký tự nối 0-widthcác ký tự không phải nối 0-width cũng được phép trong tên biến - xem JavaScript xáo trộn với các ký tự không-width - ư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!")
}

627
Jonas Wilms 2018-01-16 10:35.

Đ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 một withcâu lệnh để cho phép ađánh giá đến 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 ...

Thậm chí tệ hơn, thủ thuật này cũng sẽ hoạt động với việc sử dụng ===.

  var i = 0;

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

526
georg 2018-01-18 01:37.

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 bởi vì ==gọi toStringmà gọi .joincho Mảng.

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

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

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

268
ocomfd 2018-01-16 20:21.

Nếu nó được hỏi là có thể (KHÔNG PHẢI), nó có thể yêu cầu "a" trả về một số ngẫu nhiên. Sẽ đú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;
    }
  }
}

211
Kos 2018-01-17 09:35.

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 nhờ valueOfphương thức tùy chỉnh được gọi khi Đối tượng được so sánh với nguyên thủy (chẳng hạn như Số). Thủ thuật chính là a.valueOftrả về giá trị mới mọi lúc vì nó đang gọi execbiểu thức chính quy với gcờ, điều này gây ra việc cập nhật lastIndexbiểu thức chính quy đó mỗi khi tìm thấy đối sánh. Vì vậy, lần đầu tiên this.r.lastIndex == 0, nó khớp 1và cập nhật lastIndex: this.r.lastIndex == 1, vì vậy lần sau regex sẽ khớp 2, v.v.

192
jontro 2018-01-16 10:37.

Nó có thể được thực hiện bằng cách sử dụng những điều sau đây trong phạm vi toàn cầu. Để nodejssử dụng globalthay vì windowtrong mã dưới đây.

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 ngầm định được cung cấp bởi phạm vi toàn cục trong ngữ cảnh thực thi bằng cách xác định một getter để truy xuất biến.

190
mehulmpt 2018-01-17 21:39.

Điều này có thể xảy ra trong trường hợp biến ađược truy cập bởi 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 nó có thể là khi mã được biên dịch sang mã máy, các công nhân trang web cập nhật các biến achỉ trong thời gian như vậy điều kiện a==1, a==2a==3được thỏa mãn.

Đâ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 web worker và SharedArrayBuffer trong JavaScript.

Đây là cách triển khai 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:

Lần thử thứ hai:

Như tôi đã nói, cơ hội sẽ thấp, nhưng nếu có đủ thời gian, nó sẽ đạt được điều kiện.

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

148
Patrick Dark 2018-01-17 01:37.

Điều này cũng có thể thực hiện được bằng cách sử dụng một loạt các getters tự ghi đè:

(Điều này tương tự như giải pháp của jontro, nhưng không yêu cầu biến bộ đếm.)

(() => {
    "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.");
    }
})();

131
Nina Scholz 2018-01-17 05:11.

Ngoài ra, bạn có thể sử dụng một lớp cho nó và một thể hiện để kiểm tra.

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

var a = new A;

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

BIÊN TẬP

Sử dụng các lớp ES6, nó sẽ giống như thế này

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!');
}

130

Tôi không thấy câu trả lời này đã được đăng, vì vậy tôi cũng sẽ ném câu trả lời này vào hỗn hợp. Điều này tương tự như câu trả lời của Jeff với không gian Hangul nửa chiều rộng.

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

Bạn có thể nhận thấy một chút khác biệt với cái thứ hai, nhưng cái thứ nhất và thứ ba giống hệt nhau bằng mắt thường. Cả 3 đều là các ký tự riêng biệt:

a- Chữ thường
Latinh A
а- Chữ thường Latinh có Chiều rộng Đầy đủ A - Chữ thường chữ Kirin A

Thuật ngữ chung cho điều này là "homoglyphs": các ký tự unicode khác nhau trông giống nhau. Thông thường, rất khó để có được ba chiếc mà hoàn toàn không thể phân biệt được, nhưng trong một số trường hợp, bạn có thể gặp may. A, Α, А, và Ꭺ sẽ làm việc tốt hơn (Latin-A, Hy Lạp Alpha , Cyrillic-A , và Cherokee-A tương ứng; tiếc là Hy Lạp và Cherokee thấp hơn trường hợp chữ quá khác nhau từ tiếng Latinh a: α, , và do đó doesn không giúp được gì với đoạn mã trên).

Có cả một lớp các cuộc tấn công Homoglyph ở đó, phổ biến nhất là trong các tên miền giả mạo (ví dụ: wikipediа.org(Cyrillic) so với wikipedia.org(Latin)), nhưng nó cũng có thể hiển thị trong mã; thường được gọi là bị ám chỉ (như đã đề cập trong một nhận xét, các câu hỏi [ám chỉ] hiện không chủ đề trên PPCG , nhưng từng là một loại thử thách mà những thứ này sẽ hiển thị). Tôi đã sử dụng trang web này để tìm các chữ đồng nhất được sử dụng cho câu trả lời này.

111
RAM 2018-01-21 15:59.

Vâng, nó có thể! 😎

»JavaScript

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

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

Đoạn mã trên là một phiên bản ngắn (cảm ơn @Forivin đã ghi chú trong phần bình luận) và đoạn mã sau là bản gốc:

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

Nếu bạn chỉ nhìn thấy mặt trên của mã của tôi và chạy nó, bạn nói WOW, làm thế nào?

Vì vậy, tôi nghĩ chỉ cần nói Có, có thể với ai đó đã nói với bạn: Không gì là không thể

Thủ thuật: Tôi đã sử dụng một ký tự ẩn sau ifđể tạo một hàm tương tự như tên của nó if. Trong JavaScript, chúng tôi không thể ghi đè từ khóa nên tôi buộc phải sử dụng cách này. Nó là một giả if, nhưng nó hiệu quả cho bạn trong trường hợp này!


» C #

Ngoài ra, tôi đã viết một phiên bản C # ( với kỹ thuật gia tăng giá trị tài sản ):

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

Bản thử trực tiếp

97
Eric Duminil 2018-01-18 00:14.

JavaScript

a == a +1

Trong JavaScript, không có số nguyên mà chỉ có Numbers, được triển khai dưới dạng số dấu phẩy động có độ chính xác kép.

Có nghĩa là nếu một Số ađủ lớn, nó có thể được coi là bằng ba số nguyên liên tiếp:

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

Đúng, nó không chính xác những gì người phỏng vấn yêu cầu (nó không hoạt động với a=0), nhưng nó không liên quan đến bất kỳ thủ thuật nào với các hàm ẩn hoặc quá tải toán tử.

Những ngôn ngữ khác

Để tham khảo, có a==1 && a==2 && a==3các giải pháp bằng Ruby và Python. Với một chút sửa đổi, nó cũng có thể thực hiện được trong Java.

Ruby

Với một tùy chỉnh ==:

class A
  def ==(o)
    true
  end
end

a = A.new

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

Hoặc ngày càng tăng a:

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

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

Python

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

Java

Có thể sửa đổi Integerbộ đệm 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.");
        }
    }
}
81
Salman A 2018-01-19 00:51.

Đây là một phiên bản ngược của @ Jeff câu trả lời * nơi một nhân vật ẩn (U + 115F, U + 1160 hoặc U + 3164) được sử dụng để tạo ra các biến mà nhìn như 1, 23.

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

* Câu trả lời đó có thể được đơn giản hóa bằng cách sử dụng bộ nối không có độ rộng bằng không (U + 200C) và bộ nối có độ rộng bằng 0 (U + 200D). Cả hai ký tự này đều được phép bên trong số nhận dạng nhưng không được phép ở đầu:

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);
****/

Các thủ thuật khác có thể sử dụng cùng một ý tưởng, ví dụ bằng cách sử dụng bộ chọn biến thể Unicode để tạo các biến trông giống hệt nhau ( a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true).

75
MonkeyZeus 2018-01-17 07:27.

Quy tắc số một khi phỏng vấn; không bao giờ nói không thể.

Không cần thủ thuật ẩn ký tự.

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?' );
}

68
Frank W. Zammetti 2018-01-17 11:57.

Thành thật mà nói, cho dù có cách nào để nó đánh giá là đúng hay không (và như những người khác đã chỉ ra, có nhiều cách), câu trả lời mà tôi đang tìm kiếm, nói với tư cách là một người đã thực hiện hàng trăm cuộc phỏng vấn, sẽ là một cái gì đó dọc theo dòng của:

"Chà, có thể có trong một số tình huống kỳ lạ mà tôi không rõ ràng ngay lập tức ... nhưng nếu tôi gặp phải điều này trong mã thực thì tôi sẽ sử dụng các kỹ thuật gỡ lỗi phổ biến để tìm ra cách thức và lý do tại sao nó hoạt động như thế nào và sau đó ngay lập tức cấu trúc lại mã để tránh tình huống đó ... nhưng quan trọng hơn: Tôi tuyệt đối KHÔNG BAO GIỜ viết mã đó ngay từ đầu vì đó là định nghĩa của mã phức tạp và tôi cố gắng không bao giờ viết mã phức tạp ".

Tôi đoán rằng một số người phỏng vấn sẽ cảm thấy khó chịu khi có những gì rõ ràng là một câu hỏi rất khó được gọi ra, nhưng tôi không ngại những nhà phát triển có ý kiến, đặc biệt là khi họ có thể sao lưu nó với suy nghĩ hợp lý và có thể hiểu câu hỏi của tôi thành một câu nói ý nghĩa về bản thân họ.

43
Dirk Vollmar 2018-01-18 02:57.

Nếu bạn từng nhận được một câu hỏi phỏng vấn như vậy (hoặc nhận thấy một số hành vi bất ngờ tương tự trong mã của bạn), hãy nghĩ về những thứ có thể gây ra một hành vi thoạt nhìn là không thể:

  1. Mã hóa : Trong trường hợp này, biến bạn đang xem không phải là biến bạn nghĩ. Điều này có thể xảy ra nếu bạn cố tình gây rối với Unicode bằng cách sử dụng các ký tự đồng nhất hoặc ký tự khoảng trắng để làm cho tên của một biến trông giống một biến khác, nhưng các vấn đề mã hóa cũng có thể vô tình được đưa ra, ví dụ: khi sao chép và dán mã từ Web có chứa mã Unicode không mong muốn điểm (ví dụ: vì hệ thống quản lý nội dung đã thực hiện một số "tự động định dạng", chẳng hạn như thay thế flbằng Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).

  2. Điều kiện cuộc đua : Tình trạng cuộc đua có thể xảy ra, tức là một tình huống trong đó mã không thực thi theo trình tự mà nhà phát triển mong đợi. Điều kiện cuộc đua thường xảy ra trong mã đa luồng, nhưng nhiều luồng không phải là yêu cầu để điều kiện đua có thể thực hiện được - tính không đồng bộ là đủ (và đừng nhầm lẫn, không đồng bộ không có nghĩa là nhiều luồng được sử dụng dưới mui xe ).

    Lưu ý rằng do đó JavaScript cũng không thoát khỏi các điều kiện chủng tộc chỉ vì nó là một luồng. Xem tại đây để biết ví dụ đơn giản về một luồng - nhưng không đồng bộ -. Tuy nhiên, trong ngữ cảnh của một câu lệnh, điều kiện chủng tộc sẽ khó đạt được trong JavaScript.

    JavaScript với web worker hơi khác một chút, vì bạn có thể có nhiều luồng. @mehulmpt đã cho chúng ta thấy một bằng chứng tuyệt vời về khái niệm sử dụng nhân viên web .

  3. Tác dụng phụ : Một tác dụng phụ của phép toán so sánh bình đẳng (không nhất thiết phải rõ ràng như trong các ví dụ ở đây, các tác dụng phụ thường rất nhỏ).

Những vấn đề kiểu này có thể xuất hiện trong nhiều ngôn ngữ lập trình, không chỉ JavaScript, vì vậy chúng tôi không thấy một trong các WTF JavaScript cổ điển ở đây 1 .

Tất nhiên, câu hỏi phỏng vấn và các mẫu ở đây đều trông rất giả tạo. Nhưng chúng là một lời nhắc nhở tốt rằng:

  • Các tác dụng phụ có thể thực sự khó chịu và một chương trình được thiết kế tốt sẽ không có các tác dụng phụ không mong muốn.
  • Đa luồng và trạng thái có thể thay đổi có thể là vấn đề.
  • Không thực hiện đúng mã hóa ký tự và xử lý chuỗi có thể dẫn đến các lỗi khó chịu.

1 Ví dụ, bạn có thể tìm thấy một ví dụ bằng một ngôn ngữ lập trình hoàn toàn khác (C #) thể hiện một tác dụng phụ (một hiệu ứng hiển nhiên) tại đây .

41
Théophile 2018-01-17 10:00.

Đây là một biến thể khác, sử dụng một mảng để bật ra bất kỳ giá trị nào bạn muốn.

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

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

31
BaggersIO 2018-01-17 11:33.

Được rồi, một cuộc tấn công khác với máy phát điện:

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!');
}

29
IceCreamYou 2018-01-20 12:19.

Sử dụng proxy :

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

Về cơ bản proxy giả vờ là một đối tượng đích (tham số đầu tiên), nhưng chặn các hoạt động trên đối tượng đích (trong trường hợp này là hoạt động "lấy thuộc tính") để có cơ hội thực hiện điều gì đó khác với hành vi của đối tượng mặc định. Trong trường hợp này, hành động "lấy thuộc tính" được gọi akhi ==cưỡng chế kiểu của nó để so sánh nó với từng số. Điều này xảy ra:

  1. Chúng tôi tạo một đối tượng đích { i: 0 }, nơi thuộc itính là bộ đếm của chúng tôi
  2. Chúng tôi tạo một Proxy cho đối tượng đích và gán nó cho a
  3. Đối với mỗi a ==so sánh, akiểu của được ép buộc thành một giá trị nguyên thủy
  4. Kiểu ép buộc này dẫn đến việc gọi a[Symbol.toPrimitive]()nội bộ
  5. Proxy chặn nhận a[Symbol.toPrimitive]chức năng bằng cách sử dụng "get handler"
  6. "Có được xử lý" kiểm tra của Proxy mà tài sản bị nhận là Symbol.toPrimitive, trong trường hợp này nó increments và sau đó quay lại đếm từ đối tượng mục tiêu: ++target.i. Nếu một thuộc tính khác đang được truy xuất, chúng tôi chỉ quay lại trả về giá trị thuộc tính mặc định,target[name]

Vì thế:

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

Như với hầu hết các câu trả lời khác, điều này chỉ hoạt động với kiểm tra bình đẳng lỏng lẻo ( ==), bởi vì kiểm tra bình đẳng nghiêm ngặt ( ===) không thực hiện cưỡng chế loại mà Proxy có thể chặn.

27
Gustavo Rodríguez 2018-01-17 09:56.

Thực ra câu trả lời cho phần đầu tiên của câu hỏi là "Có" trong mọi ngôn ngữ lập trình. Ví dụ, đây là trường hợp của 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;
}
26
Preda7or 2018-01-18 04:18.

Giống nhau, nhưng khác nhau, nhưng vẫn giống nhau (có thể "thử nghiệm" nhiều lần):

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!');
}

Ý tưởng của tôi bắt đầu từ cách thức hoạt động của phương trình kiểu đối tượng Số.

25
Omar Alshaker 2018-01-18 05:21.

Một câu trả lời ECMAScript 6 sử dụng các Biểu tượng:

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

Do ==sử dụng, JavaScript có nghĩa vụ phải ép buộc avào một cái gì đó gần với toán hạng thứ hai ( 1, 2, 3trong trường hợp này). Nhưng trước khi JavaScript cố gắng tự tìm cách ép buộc, nó sẽ cố gắng gọi Symbol.toPrimitive. Nếu bạn cung cấp Symbol.toPrimitiveJavaScript sẽ sử dụng giá trị mà hàm của bạn trả về. Nếu không, JavaScript sẽ gọi valueOf.

24
gafi 2018-01-22 06:31.

Tôi nghĩ đây là mã tối thiểu để triển khai nó:

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

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

Tạo một đối tượng giả với một tùy chỉnh valueOflàm tăng biến toàn cục itrên mỗi lần gọi. 23 ký tự!

14
Ben Aubin 2018-01-17 09:04.

Cái này sử dụng defineProperty với một hiệu ứng phụ gây ra biến toàn cục!

var _a = 1

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

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

3
Jonathan Kuhl 2018-11-05 08:55.

Bằng cách ghi đè valueOftrong khai báo lớp, nó có thể được thực hiện:

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

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

const a = new Thing();

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

Điều gì xảy ra được valueOfgọi trong mỗi toán tử so sánh. Trên lần đầu tiên, asẽ bằng nhau 1, trên lần thứ hai, asẽ bằng nhau 2, v.v., bởi vì mỗi lần valueOfđược gọi, giá trị của ađược tăng lên.

Do đó, console.log sẽ kích hoạt và xuất ra (trong thiết bị đầu cuối của tôi) Thing: { value: 4}, cho biết điều kiện là đúng.

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Trong Saturday Night Live, The Bachelor is Bland và Tina Fey trở lại với vai 'Crazy' Sarah Palin

Trong Saturday Night Live, The Bachelor is Bland và Tina Fey trở lại với vai 'Crazy' Sarah Palin

Sau khi Sarah Palin tán thành Donald Trump vào đầu tuần này, gần như không thể tránh khỏi việc Tina Fey sẽ trở lại Saturday Night Live để thăm lại ấn tượng Palin cổ điển của cô. Và Fey chắc chắn đã không làm thất vọng, cô ấy đã đưa ra một lời khen ngợi không hề nhẹ về bài phát biểu chứng thực Iowa quanh co và khó hiểu của Palin trong khi Trump của Darrell Hammond đưa ra bình luận xuyên suốt.

Đây có phải là sự khởi đầu cho sự kết thúc của việc giam giữ Brittney Griner?

Đây có phải là sự khởi đầu cho sự kết thúc của việc giam giữ Brittney Griner?

Brittney Griner (r.) Ngay từ đầu, thân phận của Brittney Griner đã là tình huống con tin Mỹ độc nhất trong lịch sử hiện đại.

Tom Brady là bộ tứ vệ đầu tiên cuối cùng có thể giúp Julio Jones có hơn 10 lần chạm bóng trong một mùa giải

Tom Brady là bộ tứ vệ đầu tiên cuối cùng có thể giúp Julio Jones có hơn 10 lần chạm bóng trong một mùa giải

Chúng ta có thể thấy nhiều hơn nữa về một Julio Jones khỏe mạnh trong khu vực cuối năm nay. John Parker Wilson, Greg McElroy, A.

Đó phải là Đức

Đó phải là Đức

Đối với đội tuyển Anh, không có kẻ thủ ác nào lớn hơn Hầu hết các cổ động viên Anh, nếu không muốn nói là tất cả, hẳn sẽ phải gật gù khi tiếng còi mãn cuộc của trận bán kết lượt về W Euro 2022 vang lên. Bởi vì nó báo hiệu rằng Đức sẽ chờ đợi ở Wembley trong trận chung kết với Anh và là điều duy nhất giữa Anh và chiếc cúp lớn đầu tiên của đội tuyển nữ.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Language