it-swarm-vi.com

Có thể (a == 1 && a == 2 && a == 3) có thể đánh giá là đúng không?

Lưu ý của người điều hành: Vui lòng chống lại sự thôi thúc chỉnh sửa mã hoặc xóa thông báo này. Mô hình của khoảng trắng có thể là một phần của câu hỏi và do đó không nên bị can thiệp 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ờ (a== 1 && a ==2 && a==3) có thể đánh giá thành true trong 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ò.

2331
Dimpu Aravind Buddha

Nếu bạn tận dụng cách == hoạt động , bạn có thể chỉ cần tạo một đối tượng với 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 công việc này là do việc sử dụng toán tử đẳng thức lỏng lẻo. Khi sử dụng đẳng thức lỏng lẻo, nếu một trong các toán hạng có loại khác với loại khác, động cơ sẽ cố gắng chuyển đổi loại này sang loại khác. 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 valueOf đầu tiên nếu nó có thể gọi được và không thành công, nó sẽ gọi toString. Tôi đã sử dụng toString trong trường hợp này đơn giản chỉ vì nó xuất hiện trong đầu, valueOf sẽ có ý nghĩa hơn. Thay vào đó, nếu tôi trả về một chuỗi từ toString, thì công cụ đó đã 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.

3185
Kevin B

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

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 thực tên biến của Mathias . Nếu khoảng cách kỳ lạ đó thực sự được bao gồm trong 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ông cụ nối không có độ rộng bằng khôngKhông tham gia không có độ rộng bằng không ký tự cũng được phép trong các tên biến - xem Làm mờ JavaScript với các ký tự có độ rộng bằng không - ưu và nhược điểm? .

Điều này sẽ trô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!")
}

1969
Jeff

NÓ IS KHẢ NĂNG!

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âu lệnh with để cho a đánh giá thành 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.");
  }

591
Jonas Wilms

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 gọi .join cho Mảng.

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

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

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

458
georg

Nếu được hỏi nếu 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ẽ đúng nếu nó tạo 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;
    }
  }
}

259
mmmaaa

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

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

203
Kos

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. Đối với 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 ẩ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 xác định một getter để lấy biến.

186
jontro

Đ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ể khi mã được biên dịch thành mã máy, nhân viên web cập nhật biến a ngay để các đ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 các nhân viê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ử thứ hai:

 enter image description here

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 mất quá nhiều thời gian trên hệ thống của bạn. Chỉ thử a == 1 && a == 2 và thay đổi Math.random()*3 thành Math.random()*2. Thêm nhiều hơn và nhiều hơn vào danh sách giảm cơ hội đánh.

182
mehulmpt

Điều này cũng có thể 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 số truy cập.)

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

145
Patrick Dark

Tôi không thấy câu trả lời này đã được đăng, vì vậy tôi cũng sẽ đưa câu trả lời này vào hỗn hợp. Điều này tương tự với 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 sự khác biệt nhỏ với cái thứ hai, nhưng cái thứ nhất và thứ ba giống hệt với mắt thường. Cả 3 đều là những ký tự riêng biệt:

a - Chữ thường A
- Toàn bộ chữ thường Latin
а - Chữ thường chữ 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 khó có được ba 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 mắn. A, А và sẽ hoạt động tốt hơn (Latin-A, tiếng Hy Lạp Alpha , Cyrillic-A , và Cherokee-A , không may là tiếng Hy Lạp và các chữ cái viết thường của Cherokee quá khác biệt so với chữ Latinh a: α, , và do đó không giúp ích gì cho đoạn trích trên).

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

127
Draco18s

Ngoài ra, bạn có thể sử dụng một lớp cho nó và một thể hiện cho 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!');
}

CHỈNH SỬA

Sử dụng các lớp ES6 nó sẽ trô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!');
}

123
Nina Scholz

JavaScript

a == a +1

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

Điều đó có nghĩa là nếu 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, đó không chính xác là những gì người phỏng vấn đã hỏi (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 chức năng ẩn hoặc quá tải toán tử.

Những ngôn ngữ khác

Để tham khảo, có các giải pháp a==1 && a==2 && a==3 trong Ruby và Python. Với một sửa đổi nhỏ, nó cũng có thể có trong Java.

Hồng ngọc

Với == 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 tăng a:

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

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

Con trăn

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 bộ đệm Java Integer :

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.");
        }
    }
}
93
Eric Duminil

Vâng, nó là 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 (nhờ @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ĩ rằng đủ để nói Vâng, điều đó là có thể với ai đó đã nói với bạn: Không có 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 có tên tương tự như 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à if giả, nhưng nó hoạt động 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 tăng giá trị thuộc tính):

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

90
RAM

Đây là phiên bản đảo ngược của @ Jeff's answer * trong đó một ký tự ẩn (U + 115F, U + 1160 hoặc U + 3164) được sử dụng để tạo các biến giống 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 công cụ không tham gia chiều rộng bằng không (U + 200C) và công cụ tham gia chiều rộng bằng không (U + 200D). Cả hai ký tự này đều được phép bên trong số nhận dạng nhưng không phải ở đầ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 các 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).

78
Salman A

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

Không cần phải lừa nhân vật ẩn.

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

72
MonkeyZeus

Thành thật mà nói, liệu có cách nào để đánh giá đúng hay không (và như những người khác đã chỉ ra, có nhiều cách), câu trả lời tôi đang tìm kiếm, nói như 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:

"Chà, có lẽ là có trong một số tình huống kỳ lạ không rõ ràng đối với tôi ... 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 sửa lỗi phổ biến để tìm ra cách thức và lý do tại sao nó đang làm những gì nó đang làm 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 hoàn toàn KHÔNG BAO GIỜ viết mã đó ngay từ đầu bởi vì đó là định nghĩa về 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 một số người phỏng vấn sẽ xúc phạm khi có câu hỏi rõ ràng là một câu hỏi rất khó, nhưng tôi không bận tâm đến 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ể phù hợp với câu hỏi của tôi một tuyên bố có ý nghĩa về bản thân họ.

66
Frank W. Zammetti

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

41
Théophile

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ề loại điều nào có thể gây ra hành vi có vẻ không thể ngay từ cái nhìn đầu tiên:

  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 làm rối với Unicode bằng cách sử dụng homoglyphs hoặc ký tự khoảng trắng để làm cho tên của một biến giống như một biến khác, nhưng cũng có thể vô tình đưa ra các vấn đề mã hóa, ví dụ: khi sao chép và dán mã từ Web có chứa các điểm mã Unicode không mong muốn (ví dụ: vì hệ thống quản lý nội dung đã thực hiện một số "định dạng tự động" như thay thế fl bằng Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).

  2. Điều kiện cuộc đua: A điều kiện cuộc đua có thể xảy ra, tức là tình huống mã không được 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 với điều kiện cuộc đua là có thể - sự không đồng bộ là đủ (và không bị 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à luồng đơn. Xem tại đây để biết ví dụ đơn luồng - nhưng không đồng bộ -. Tuy nhiên, trong bối cảnh của một tuyên bố, điều kiện cuộc đua sẽ khá khó khăn trong JavaScript.

    JavaScript với nhân viên web 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 khái niệm sử dụng nhân viên web .

  3. Tác dụng phụ: Hiệu ứng phụ của hoạt động so sánh bằng (không cần phải rõ ràng như trong các ví dụ ở đây, thường là các tác dụng phụ rất tinh tế). 

Các loại vấn đề 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 những ngôn ngữ cổ điển JavaScript WTFs tại đây1

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 tốt rằng:

  • Các tác dụng phụ có thể trở nên thực sự khó chịu và một chương trình được thiết kế tốt sẽ không có tác dụng phụ không mong muốn.
  • Đa luồng và trạng thái đột biến có thể có vấn đề.
  • Không thực hiện mã hóa ký tự và xử lý chuỗi đúng 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 ngôn ngữ lập trình hoàn toàn khác (C #) thể hiện hiệu ứng phụ (một điều hiển nhiên) ở đây .

37
Dirk Vollmar

Được rồi, một hack 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!');
}

31
BaggersIO

Trên thực tế, 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à trong 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;
}
27
Gustavo Rodríguez

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

Các proxy về cơ bản 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 một việc khác ngoài hành vi đối tượng mặc định. Trong trường hợp này, hành động "lấy tài sản" được gọi vào a khi == ép buộc loại 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 }, trong đó thuộc tính i là đối tượng của chúng tôi
  2. Chúng tôi tạo Proxy cho đối tượng đích và gán nó cho a
  3. Đối với mỗi so sánh a ==, loại a bị ép buộc thành một giá trị nguyên thủy
  4. Loại cưỡng chế này dẫn đến việc gọi a[Symbol.toPrimitive]() trong nội bộ
  5. Proxy chặn chức năng a[Symbol.toPrimitive] bằng cách sử dụng "get handler"
  6. "Trình xử lý" của Proxy kiểm tra xem thuộc tính đang nhận là Symbol.toPrimitive, trong trường hợp đó, nó tăng lên và sau đó trả về bộ đếm từ đối tượng đích: ++target.i. Nếu một thuộc tính khác đang được truy xuất, chúng ta sẽ 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 đẳng thức lỏng lẻo (==), bởi vì kiểm tra đẳng thức nghiêm ngặt (===) không thực hiện ép buộc mà Proxy có thể chặn.

27
IceCreamYou

Giống nhau, nhưng khác nhau, nhưng vẫn giống nhau (có thể được "kiểm tra" 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 phương trình Số đối tượng hoạt động.

26
Preda7or

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ụ ép buộc a thành một thứ gần với toán hạng thứ hai (1, 2, 3 trong 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.toPrimitive JavaScript sẽ sử dụng giá trị mà hàm của bạn trả về. Nếu không, JavaScript sẽ gọi valueOf .

23
Omar Alshaker

Tôi nghĩ rằng đây là mã tối thiểu để thực hiện 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 valueOf tùy chỉnh làm tăng biến toàn cục i trên mỗi cuộc gọi. 23 ký tự!

23
Gaafar

Cái này sử dụng phần xác định với hiệu ứng phụ Nice 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)

11
Ben Aubin

Bằng cách ghi đè valueOf trong khai báo lớp, có thể 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 là valueOf được gọi trong mỗi toán tử so sánh. Ở lần đầu tiên, a sẽ bằng 1, vào lần thứ hai, a sẽ bằng 2, v.v., vì mỗi lần gọi valueOf, giá trị của a được tăng lên.

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

0
Jonathan Kuhl