Чи може (a == 1 && a == 2 && a == 3) коли-небудь оцінити справжнє?


2484

Примітка модератора: Будь ласка, протистоять бажанню редагувати код або видалити це повідомлення. Шаблон пробілів може бути частиною питання, і тому його не слід підробляти без необхідності. Якщо ви перебуваєте в таборі "пробіл несуттєвий", ви повинні мати можливість прийняти код таким, який є.

Чи можливо коли-небудь, що (a== 1 && a ==2 && a==3)могли б оцінити trueв JavaScript?

Це питання про інтерв'ю, яке задає велика технологічна компанія. Це сталося два тижні тому, але я все ще намагаюся знайти відповідь. Я знаю, що ми ніколи не пишемо такого коду в своїй щоденній роботі, але мені цікаво.


9
Коментарі не для розширеного обговорення; ця розмова була переміщена до чату .
деге

109
Людям, які, мабуть, проголосували за те, що це заперечують як занадто широке : це копатись у Javascript, кажучи, що занадто багато дійсних відповідей?
Томмінг

24
Деякі люди сидять навколо філософствуючи про те, що можливо. Інші акцентують свої зусилля на тому, чи будують вони життєздатні, правильні для бізнесу продукти для своїх клієнтів. ІМО, це питання не має практичної користі, крім того, що ви ніколи не повинні задавати подібні питання в інтерв'ю чи писати подібний код. Тому його слід закрити. Я маю на увазі справді, чи усвідомлює бізнес, що вони платили комусь реальні гроші, щоб вони сиділи і говорили про ці речі?
P.Brian.Mackey

15
Прочитавши відповіді, мораль розповіді полягає в тому, що: не використовуйте, ==коли маєте на увазі ===, не використовуйте стандарт кодування, який забороняє імена змінних, що не належать до ASCII, і маєте процес зв’язування, який застосовує попередні дві моралі.
Джессі К. Слікер

87
Примітка модератора: Переповнення стека мала історію, коли люди підкоряються відповідями на різних мовах до тієї, про яку йде мова. Вони є спробою відповісти на питання , тому що вони є рішенням загальної проблеми, хоча і на іншій мові. Утримайтеся від позначення їх як "не відповіді". Сказавши це, будь ласка, утримайтеся від публікації більше відповідей різними мовами - є причина, що це питання є специфічним для JavaScript, на що вказують коментарі під деякими з цих інших відповідей, і є причина, що нам подобаються наші конкретні питання. залишатися таким.
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якщо він називається, а якщо цього не вдасться, він зателефонує toString. Я використовував toStringу цьому випадку просто тому, що саме те, що прийшло в голову, valueOfмало б більше сенсу. Якби я замість цього повернув рядок toString, двигун би спробував перетворити рядок у число, даючи нам такий самий кінцевий результат, хоча з дещо довшим шляхом.


70
Чи можете ви досягти цього, змінивши мається на увазі valueOf()операцію?
Стерлінг Арчер

43
Так, valueOf працює замість toString з тієї ж причини
Кевін B

4
Коментарі не для розширеного обговорення; ця розмова була переміщена до чату .
деге

13
Згідно з цим, спершу спробується перетворення чисел, тому valueOfтрохи краще.
Салман А

6
@ Приблизно лівою частиною порівняння рівності є об'єкт, а не число. Те, що на цьому об'єкті є властивість числа 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, одна з нею раніше і остання з просто a. Замінивши простір _на читабельність, той самий код буде виглядати приблизно так:

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

Перевірте перевірку валідатора імені змінної Mathias . Якщо цей дивний проміжок був насправді включений у їх запитання, я впевнений, що це підказка для такого виду відповіді.

Не робіть цього. Серйозно.

Редагувати: Мені подобається, що (хоча заборонено запускати змінну) столярний знак не ширини та нульової ширини також дозволений у назвах змінних - див. Очищення 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
Судячи з незвичайного інтервалу в оригінальному запитанні, я думаю, що це ТОЧЧЕ відповідь, на яке було шукано питання інтерв'ю - експлуатування непросторових символів, схожих на пробіли. Гарне місце!
Баракус

18
@Baracus Саме РонДжон помітив дивні відстані у своєму коментарі до відповіді Кевіна, який нагадав мені про цю (жахливу) методику, тому я не можу брати на себе кредит за її поміщення. Я був начебто здивований, ніхто вже не відповідав на це, хоча, як це пішло навколо моєї роботи кілька років тому через повідомлення в блозі десь - я начебто припустив, що це було досить загальновідомим на даний момент.
Джефф

102
Звичайно, це заборонено як стандартну лазівку , що стосується і інтерв'ю. [потрібна цитата]
Санчіз

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 і a - додатковий символ є Простір половини ширини Хангул.
Джефф

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щоб це могло статися
Jungkook

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, ну ... його більш непряме, але в основному те саме.
Йонас Вілмс

11
Мені дуже подобається це рішення, оскільки ви нічого не перекриваєте, окрім об'єктів, що мають власну функцію приєднання, і це просто дуже чистий і простий для читання хак, що змушує логіку оцінювати як істинну.
Алекс Педерсен

28
Чесно кажучи, я вважаю, що це найкраща відповідь. Він не передбачає нічого незвичайного, просто встановлення кількох значень. Дуже легко зрозуміти навіть з базовими знаннями JS. Молодці.
Зак Дельвенталь

14
Це має такий сенс, що він майже відчуває себе корисним.
Андрій

7
Я знав, що більшість відповідей стосуватимуться зловживань toStringабо, valueOfале ця застала мене цілком поза охороною. Дуже розумний, і я не знав, що він дзвонив .joinвсередину, але це має тотальний сенс.
ГБаррозу

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
Але що робити, якщо потрібно більше 1000 випробувань?
Пійін

9
@Piyin Якщо потрібно більше 1000 випробувань, ви виграєте приз!
Skeets

5
Мені подобається ця відповідь, тому що виведення її до крайності говорить про те, що це можливо будь-якою мовою, якщо регістри / кеш процесора потрапляють з достатньою кількістю космічних променів під час роботи програми, або якщо свідомо виконується перелом енергії, такий, що відмова гілки якщо умовно насправді не стрибає.
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методу, який викликається, коли Object порівнюється з примітивним (наприклад, Number). Основна хитрість полягає в тому, що a.valueOfкожен раз повертає нове значення, оскільки він викликає execрегулярне вираження gпрапором, що призводить до оновлення lastIndexцього регулярного виразу кожного разу, коли буде знайдено збіг. Отже, перший раз this.r.lastIndex == 0, він відповідає 1та оновлює lastIndex:, this.r.lastIndex == 1тож наступний раз регулярний вирівнювання буде відповідати 2тощо.


22
@Abdillah об’єкт регулярного вираження запам’ятає останній індекс, якому він відповідає, дзвоніть execзнову, почне пошук із цього індексу. MDN не дуже зрозумілий.
Саймон Чан

Я бачу, тому this.rоб'єкт регулярного вираження запам'ятовує стан / індекс. Дякую!
Абділла

Я б рекомендував передати рядок до, execхоча, а не до цілого числа, що має бути рядком.
Бергі

використовуйте регекс, і тепер у вас є дві проблеми
Олексій Соловей

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 добре. Не впевнений, що це додасть набагато більшої цінності в поєднанні з іншими вже відповідями.
Оновить

14
Питання було, чи може це "коли-небудь" бути правдою. І відповідь - так, і це один із сценаріїв, де це може бути правдою: aне є локальною змінною і визначається в глобальному масштабі за допомогою збільшення коефіцієнта.
Zac Delventhal

190

Це можливо, якщо доступ до змінної a, скажімо, двома веб-працівниками через 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)

робітник.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 мільярдів ітерацій з першої спроби:

введіть тут опис зображення

Друга спроба:

введіть тут опис зображення

Як я вже говорив, шанси будуть низькими, але якщо буде достатньо часу, це вдарить за умовою.

Порада. Якщо у вашій системі знадобиться занадто довго Спробуйте лише a == 1 && a == 2змінити Math.random()*3на Math.random()*2. Якщо все більше і більше додавати до списку, випадаєте шанси нанести удар.


50
Чесно кажучи, це найкраща відповідь. Всі інші відповіді вимагають свідомої спроби зробити щось глибоко неінтуїтивне. Ця відповідь насправді відображає щось, що може статися в реальному світі, - стан перегонів.
Tom Swirly

34
Мало того - я насправді бачив, як це відбувається в реальному світі. Не з точною умовою у питанні, але, безумовно, з перевіркою (a == 1) на початку функції та (a == 2) пізніше в функції, і з кодом потрапили обидві умови. FYI, вперше я це побачив у контролері двигуна автомобіля, і ми встановили стандарти кодування. Вдруге потрапив у систему розпушування та розпалу воєнного літального апарату, і в перший же день в компанії я знайшов це і виправив, тоді як решта команди ще обговорювали цю проблему. (Рівень Kudos: високий! :)
Грехем

38
Отже, ви працювали над "контролерами двигунів автомобілів" та "системами розсіювання і розмивання", які запрограмовані в javascript з веб-працівниками? Я не думаю, що я знову вийду на вулицю.
псакстон

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
Зауважте, що підхід використання геттера також працює ===, не тільки ==.
Макіен

Це рішення покладається на thisте, що він є глобальним об'єктом всередині тіла функції стрілки.
Рой Тінкер

@Midnightas Я б не класифікував жодних інших відповідей як "пірамідний код" .
Патрік Робертс

Зауважте, це також працює з довільним порядком, чи не так? Мовляв (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!');
}

EDIT

Використовуючи класи 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тому, коли ми порівнюємо значення, воно фактично збільшується ..
Данял Сандеело,

130

Я не бачу цієї відповіді вже опублікованою, тому я також кину цю суміш. Це схоже на відповідь Джеффа з пробілом Хангула на півширини.

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

Ви можете помітити невелику невідповідність другому, але перша і третя однакові неозброєним оком. Усі 3 є різними символами:

a- Малі латинські регістри А
- Повна ширина Латинські малі регістри А
а- Малі літери кирилиці А

Узагальненим терміном для цього є "гомогліфи": різні символи унікоду, які виглядають однаково. Зазвичай важко отримати трьох , які зовсім не відрізняються, але в деяких випадках можна пощастити. A, Α, А, і Ꭺ буде працювати краще (Latin-A, грецький Альфа , кирилиця-A , і Cherokee-A відповідно, на жаль, грецькі і черокі малі літери занадто відрізняються від латинського a: α, і так Байдуже не допоможу з вищевказаним фрагментом).

Там є цілий клас атаки гомогліфів, найчастіше в підроблених доменних іменах (наприклад, wikipediа.org(кирилиця) проти wikipedia.org(латинська)), але він може відображатися і в коді; як правило, вони називаються неприхованими (як згадується в коментарі, [недоцільні] питання зараз поза темою щодо PPCG , але раніше були типовим викликом, коли подібні речі з'являтимуться). Я використовував цей веб-сайт, щоб знайти гомогліфи, використані для цієї відповіді.


19
"Незначна невідповідність" - це не те, як я б це назвав.

4
@hvd Цілком залежить від візуалізації вашого шрифту. Це я бачу .
Draco18s більше не довіряє SE

1
@Jake Так, латинські регістри повної ширини A - це не найбільший гомогліф (але варіанти з великої літери - дивовижні). Як правило, вам потрібні лише два, щоб отримати бажаний ефект.
Draco18s більше не довіряє SE

@ Draco18s Погодився: лише 2 зазвичай потрібні. Гарна робота і над додатковою інформацією!
JakeSteam

10
Ви також можете використовувати селектор варіантів Unicode (U + FE00..U + FE0F). Жоден з них не є a: a︀ a︁ a︂. Більше не турбуйтеся про розбіжності.
Салман А

108

Так, це можливо! 😎

»JavaScript

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
Версія javascript - справжній злочин проти людства, і здатність це робити, повинна бути незаконною конвенціями ООН. Я думаю, настав час, коли ми очистимо світ від усіх знань про javacript.
Ясніше

2
Оголошення функції може бути ще коротшим. if‌=()=>!0
Форівін

4
Чому на землі ти використовував document.write? Це вірний спосіб не прийняти на роботу, незалежно від решти відповідей.
Чербрус

3
@Cerbrus, Дякую за вашу замітку. Свою відповідь я написав спочатку, console.logале змінив її на document.write. Дійсно завжди використовую console.logу своїх кодах, але тут я просто хочу показати користувачеві текст у вікні фрагмента коду StackOverflow. Тому я хотів показати своє повідомлення красивішим, ніж повідомлення, породжене console.log. Натисніть Run Code Snippetкнопку на мою відповідь та на інші відповіді. Фрагмент коду SO дозволив мені використовувати html та JS та CSS, тоді я хотів використати його у своїй відповіді та зробити це приємним. Я думаю, що це не має жодних негативних побічних ефектів і не зробило моєї відповіді великим чи завершеним.
ОЗУ

1
@Clearer, Якщо Конвенції ООН могли б ефективно змінити світ, тоді у нас повинен бути кращий світ. Нам потрібно дещо більше, ніж заява в ООН, і до цього дня я думаю, що ми можемо використовувати цей трюк Javascript мій;)
ОЗУ

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

Java

Можливо змінити 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. Я просто думав, що буде цікаво показати, як це можна зробити іншими мовами, і, можливо, дати розробникам JS кілька ідей.
Ерік Думініл

2
@ cᴏʟᴅsᴘᴇᴇᴅ: Оновлено прикладом JS.
Ерік Думініл

1
Чому версія Java не працює Integer a = 42(або не працює)? Як я розумію автобоксинг,Integer a = 42; a == 1 && a == 2 && a == 3 повинен встановити всі всі вставки. Або це відкривається для порівняння?
CAD97

@ CAD97: Integer == intсхоже, це призводить до розпакування. Але використовуючиInteger#equals(int) сили автобоксингу, це працює. Дякуємо за коментар!
Ерік Думініл

@StephanBijzitter: Будь ласка, поясніть. Наскільки я знаю, є лише Numbersв JS, які в основному схожіdouble s. Вони можуть виглядати як цілі числа, і ви можете використовувати їх як цілі числа, але вони все ще не цілі числа. Я не думаю, що n == n + 1коли-небудь може бути правдою для цілих чисел у Java / Python / C / Ruby / ...
Eric Duminil

80

Це перевернутий варіант @ відповідь Джеффа * , де прихований символ (U + 115F, U + 1160 або U + 3164) використовується для створення змінних , які виглядають як 1, 2і 3.

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 нагород: /
Йонас

6
@JonasW. 41 upvotes :-) Я знаю, що __defineGetter__застаріло на developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…, але це чітко виконується в моєму FireFox v 57.0.4, тому я вирішив показати це замість defineProperty()оскільки застарілий код справжній і його не можна ігнорувати. Незалежно від потворності, заявляти iпро те, що я робив - це добре відома / документально підтверджена поведінка. Можливо, я був просто в настрої PCG ¯ \ _ (ツ) _ / ¯
MonkeyZeus

68

Чесно кажучи, чи є спосіб, щоб він оцінив справжність чи ні (і як показали інші, існує кілька способів), я б шукав відповідь, виступаючи як хтось, хто провів сотні інтерв'ю. щось по лінії:

"Ну, може, так, за якихось дивних обставин, які мені не відразу очевидні ... але якщо я зіткнувся з цим у реальному коді, тоді я застосував би загальні методи налагодження, щоб з'ясувати, як і чому він робить те, що робить? а потім негайно перефактуруйте код, щоб уникнути такої ситуації ... але що ще важливіше: я б абсолютно НІКОЛИ не писав цей код в першу чергу, тому що це саме визначення згорнутого коду, і я прагну ніколи не писати перекручений код ".

Я думаю, що деякі інтерв'юєри ображатимуться на те, що викликається те, що, очевидно, має бути дуже складним питанням, але я не заперечую проти розробників, які мають таку думку, особливо коли вони можуть обґрунтувати це аргументованою думкою і можуть вирішити моє запитання змістовне твердження про себе.


13
Питання (або всі запитання про співбесіду), ймовірно, перевіряє готовність кандидатів думати про проблему, особливо ті, які "очевидно очевидні", як ця. Той, хто відмовляється думати, тому що вважає, що "знає", відповідь не є хорошим наймом.
Шамму

5
@Don Hatch Ні, я б не штрафував їх, якби вони відповіли добросовісно, ​​особливо, якщо вони дали правильну відповідь, як показали інші ... хороший спосіб написати код чи ні. Знання та вміння придумати "правильну" відповідь - лише частина хорошого розробника. Набагато важливішим для "професійного" розробника є написання коду, зрозумілого та підтриманого в дорозі, часто не менш спроможних розробників. Надмірно розумні розробники майже так само погані, як і нездатні IME.
Френк В. Замметті

16
Це не відповідає на запитання.
TylerH

6
Сумно про цю відповідь полягає в тому, що користувач 1rep відповів на це вчора і отримав 2 анкети, що змусили його видалити це питання.
Йонас Вілмс

8
@JohnColeman у запитанні задається питання, як код міг би оцінити істину. Це не задає причини, по яких інтерв'юер запропонував це питання в першу чергу. Ця відповідь навіть не намагається вирішити поставлене питання, а натомість повністю зосереджується на версії "що я б робила" спроби вгадати, якою була мета інтерв'юера. Якби це запитання, було б занадто широким. Тому ця відповідь не належить тут і ніде на сайті.
TylerH

43

Якщо ви коли-небудь отримуєте таке запитання про інтерв'ю (або помічаєте у вашому коді якусь не менш несподівану поведінку), подумайте, які речі можуть викликати поведінку, яка на перший погляд виглядає неможливою:

  1. Кодування : У цьому випадку змінна, яку ви дивитесь, не є такою, яку ви думаєте. Це може статися, якщо ви навмисно возилися з Unicode, використовуючи гомогліфи чи символи пробілу, щоб зробити ім'я змінної схожим на іншу, але проблеми кодування також можуть бути введені випадково, наприклад, при копіюванні та вставці коду з Інтернету, який містить несподіваний код Unicode бали (наприклад, через те, що система управління вмістом зробила деяке "автоматичне форматування", наприклад, замінивши flUnicode "LATIN SMALL LIGATURE FL" (U + FB02)).

  2. Умови перегонів : може виникнути умова перегону , тобто ситуація, коли код не виконується в послідовності, яку очікує розробник. Умови перегонів часто трапляються в багатопотоковому коді, але кілька потоків не є вимогою до можливих умов перегонів - асинхронність є достатньою (і не плутати, асинхронізація не означає, що під капотом використовується кілька потоків ).

    Зауважте, що тому JavaScript також не вільний від перегонових умов лише тому, що він є однопоточним. Дивіться тут простий приклад з однопоточним, але асинхронним. У контексті одного твердження, умова гонки, однак, буде досить важко потрапити в JavaScript.

    JavaScript з веб-працівниками трохи відрізняється, оскільки у вас може бути кілька потоків. @mehulmpt показав нам чудовий доказ концепції використання веб-працівників .

  3. Побічні ефекти : побічний ефект операції порівняння рівності (який не повинен бути настільки очевидним, як у прикладах тут, часто побічні ефекти є дуже тонкими).

Такого роду питання може з'являтися в багатьох мовах програмування, а не тільки JavaScript, тому ми не бачимо один з класичного JavaScript WTFs тут 1 .

Звичайно, питання інтерв'ю та зразки тут виглядають дуже надуманими. Але вони є гарним нагадуванням про те, що:

  • Побічні ефекти можуть стати справді неприємними, і що добре розроблена програма повинна бути позбавлена ​​небажаних побічних ефектів.
  • Багатопоточне та змінне стан може бути проблематичним.
  • Якщо не кодувати символи та обробляти рядки правильно, це може призвести до неприємних помилок.

1 Наприклад, ви можете знайти приклад в абсолютно іншій мові програмування (C #) експонування побічного ефекту (очевидний) тут .


1
Тоді питання стає занадто широким. Різні мови можуть реалізувати це з різним ступенем легкості. Питання набуло такої великої тяги, оскільки це специфічні питання щодо JS, але це лише мій 2с.
cs95

1
причини різні C # та javascript, тому ця відповідь не є законною.
Едвін

3
@ Edwin: Причини абсолютно однакові: Unicode ковзає із схожими на вигляд гліфами або символами пробілу, умовами перегонів або побічними ефектами операції порівняння (останні показані в моєму прикладі).
Дірк Волмар

2
@ cᴏʟᴅsᴘᴇᴇᴅ: Іноді погляд на речі з ширшого кута допомагає побачити актуальну проблему.
Дірк Волмар

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коли ==примушує її тип, щоб порівняти її з кожним числом. Це відбувається:

  1. Ми створюємо цільовий об'єкт { i: 0 }, деi властивість є нашим лічильником
  2. Ми створюємо проксі для цільового об’єкта і присвоюємо йому a
  3. Для кожного a ==порівнянняa тип 's примушується до примітивного значення
  4. Цей тип примусу призводить до виклику a[Symbol.toPrimitive]() внутрішнього
  5. Проксі перехоплює отримання a[Symbol.toPrimitive] функції за допомогою "отримати обробник"
  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таким самим чином на об’єкті працювало б так само добре.
Ри-

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
Я не думаю, що це можливо в кожній мові програмування. Наприклад, не всі мови мають препроцесори. З цього питання не всі мови використовують &&для логічних "і".
Кіт Томпсон

3
Я знайшов спосіб, який працює і в Python, і в C ++, який використовує перевантаження оператора.
Дональд Дак

7
А ви можете зробити це на Java, використовуючи відображення та псуючи цілий кеш.
CAD97

7
Не можу це зробити мовами, які б не підтримували мутацію в цьому місці, наприклад, нічого подібного немає в haskell
Jason Carr

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, що використовує символи:

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

Завдяки ==використанню, JavaScript повинен примушувати aв щось близьке до другої операнд ( 1, 2, 3в даному випадку). Але перш ніж 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),глобально не потрібно.
Ніна Шольц

13
@ NinaScholz впевнений, але ми говоримо про погані практики тут - просто дозвольте мені це: D
Бен Оббін

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}, вказуючи на те, що умовне значення було вірно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.