Питання Можна (а == 1 && a == 2 && a == 3) коли-небудь оцінити до істинності?


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

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

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


2253
2018-01-15 20:20


походження


Це фантастичне питання інтерв'ю. Я ніколи не стикався з цим (або таким, як це) сам, але це набагато краще, ніж той, про який я почув про залучення циклів у пов'язаних списках. Це все ще недостатньо, і я б не дискваліфікував когось із цього питання самостійно, але я б, напевно, підтримав кандидатів, які могли б визнати, що щось підростає. - Draco18s
Якщо це дещо репрезентує такий код, який мешкає в кодовій базі цієї компанії ... біжіть  - FeifanZ
Це просто потрясаюча інтерв'ю ... - ghord
Людям, які, очевидно, проголосували за цю справу занадто широкий: це копати в Javascript, говорячи, що існує забагато правильних відповідей? - tomsmeding
Примітка модератора: Стічні переповнення мали історію людей, на яких з'являються відповіді на різних мовах. Ці є спроби відповісти на це питання, оскільки вони є рішенням загальної проблеми, хоча і на іншій мові. Будь ласка, утримайтеся від позначення їх як "не відповідь". Сказавши це, будь ласка, також утримайтеся від публікації більшої кількості відповідей на різних мовах - є причина, що це питання специфічно для JavaScript, як зазначено в коментарі за деякими цими іншими відповідями, і є причина, якою ми любимо наші специфічні для мови запитання залишитися таким. - BoltClock♦


Відповіді:


Якщо ви скористаєтесь як == працює, ви можете просто створити об'єкт з індивідуальним замовленням 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, движок потім намагався перетворити рядок на число, що дає нам той же кінцевий результат, хоча з трохи більш довгим шляхом.


3097
2018-01-15 20:35



Не могли б ви це досягти, змінивши натяк valueOf() операція - Sterling Archer
Так, значенняOf працює замість toString з тієї ж причини - Kevin B
Коментарі не для розширеної дискусії; ця розмова була переїхав в чат. - deceze♦
Відповідно до це Перший такий буде спробувати конверсію числа valueOf трохи краще. - Salman A
@Pureferret ліва частина порівняння рівності є об'єктом, а не числом. Це об'єкт має власність числа i не турбує двигун. ;) - tomsmeding


Я не міг опиратися - інші відповіді, безумовно, правда, але ви дійсно не можете пройти повз наступного коду:

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

Зверніть увагу на дивний інтервал у if твердження (що я скопіював з вашого питання). Це половина ширина хангул (це корейська для тих, хто не знайомий), який є символом Юнікоду, який не інтерпретується скриптом 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!")
}


1917
2018-01-16 05:14



Судячи з непарного інтервалу в оригінальному питанні, я думаю, що це саме те, що відповідає на питання співбесіди - використовуючи непрофільні символи, які виглядають як пробіли. Гарне місце! - Baracus
@Baracus Це був Рон Джон, який помітив дивний інтервал у своєму коментар на відповідь Кевіна, яка нагадала мені про цю (жахливу) техніку, тому я не можу взяти кредит на виявлення його. Я був приємно здивований тим, що ніхто вже не відповідав на це, хоча, як це було декілька років тому через мою роботу тому, що блог поштою кудись - я вроде припускав, що це було досить загальновідомою на сьогодні. - Jeff
Звичайно, це заборонено як стандартна лазівка, що також стосується інтерв'ю. [необхідна цитата] - Sanchises
Зважаючи на початковий інтервал, це може бути ще гірше, тобто змінною var ᅠ2 = 3 був використаний; тому існують три змінні aᅠᅠ= 1, ᅠ2 = 3, a = 3 (a␣ = 1, ␣2 = 3, a = 3, так що (a␣==1 && a==␣2 && a==3)) ... - Holger
@EdmundReed: Я можу уявити, як химерний персонаж потрапляє в вихідний код, а потім кожен, хто має диявола, намагається знайти помилку. (Зокрема, якщо хтось кодував в Кореї.) - Martin Bonner


МОЖЛИВО!

var i = 0;

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

Це використовує getter усередині a with Заява дозволити a оцінити до трьох різних значень.

... це ще не означає, що це слід використовувати в реальному коді ...


567
2018-01-15 20:35



Так, я намагався того ж:) Таким чином, правильна відповідь в інтерв'ю буде: "Це не може відбутися мій код, тому що я ніколи не користуюсь with" - Pointy
@Pointy - І я програму в строгому режимі де with не дозволено. - jfriend00
@Pointy в прийнятій відповіді вони роблять щось подібне без with так це може статися - Jungkook
@JonasW Багато людей як і раніше користуються == але я не бачив with оскільки ... насправді ніколи не виходить за межі документації JS, де вона говорить "Будь ласка, не використовуйте це". У будь-якому випадку це гарне рішення. - wortwart
@Pointy Ви можете це зробити без цього with: stackoverflow.com/a/48288170/65387 - mpen


Приклад без гетерів або значення: О:

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

Це працює тому, що == викликає toString який дзвонить .join для масивів.

Інше рішення, використовуючи Symbol.toPrimitive який є еквівалентом 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, ну ... його більш опосередкований, але в основному однакова річ. - Jonas Wilms
Мені дуже подобається це рішення, тому що ви не перевизначаєте нічого, крім об'єктів власної функції приєднання, і це просто дуже чистий і легко читати хак, що робить логіку оцінкою істиною. - Alex Pedersen
Чесно кажучи, я думаю, що це найкраща відповідь. Вона не вимагає нічого від звичайного, просто встановлюючи кілька значень. Дуже легко зрозуміти навіть з базовим знанням JS. Добре зроблено - Zac Delventhal
Це робить так багато сенсу, що він майже відчуває себе корисним. - Andrew
Я знав, що більшість відповідей буде про зловживання toString або valueOf але це мене зовсім не охороняло. Дуже розумний, і я не знав, що це подзвонив .joinвнутрішньо, але це має загальний сенс. - GBarroso


Якщо запитають, чи можливо (не обов'язково), він може попросити "а" повернути випадкове число. Це було б правильно, якщо послідовно генерувати 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;
    }
  }
}


249
2018-01-16 06:21



Горрі за --богозорт - богогенерація? - Baldrickk
Я навмисно дам цю відповідь, навіть якщо б я знав інші рішення, тому що він відповідає на питання, але, очевидно, не те, що вони були після. Грай дурних ігор, вигравай дурні нагороди. - Edmund Reed
Але що, якщо це займе більше 1000 випробувань? - Piyin
@Piyin Якщо це займає більше 1000 судових процесів, ви виграєте приз! - Skeets
Мені подобається ця відповідь, тому що, беручи її до крайності, можна сказати, що це можливо будь-який мова, якщо в процесі роботи програми запускаються регістри / кеш-пам'ять процесора, або якщо він навмисно виконує збій живлення такий, що гілка несправності conditional не належить. - Ponkadoodle


Коли ви не можете робити що-небудь без регулярних виразів:

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

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

Це працює звичаєм valueOf метод, який викликається при об'єкті порівняно з примітивним (наприклад, числом). Основний трюк полягає в тому, що a.valueOf повертає нове значення кожного разу, оскільки це викликає exec на регулярному виразі з g прапор, що викликає оновлення lastIndex цього регулярного виразу кожного разу, коли знайдено відповідність. Так перший раз this.r.lastIndex == 0, це співпадає 1 і оновлення lastIndex: this.r.lastIndex == 1, тому наступного разу регулярний вираз буде відповідати 2 і так далі.


196
2018-01-16 19:35



Ой, як це працює? - Abdillah
@Abdillah об'єкт регулярного виразу буде пам'ятати останній індекс, який він збігається, виклик exec знову почне пошук з цього індексу. MDN не дуже зрозуміло. - Simon Chan
Я бачу, так що this.r regex object пам'ятає стан / index. Дякую! - Abdillah
! - Patrick Roberts
Я б рекомендував передати рядок в exec хоча, не ціле число, яке буде стрифіковано. - Bergi


Це можна здійснити, використовуючи наступне в глобальному масштабі. Для nodejs використовувати global замість window в наведеному нижче коді.

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

Ця відповідь зловживає неявними змінами, наданими глобальною областью в контексті виконання, визначаючи getter для отримання змінної.


183
2018-01-15 20:37



Це припускає a є власністю компанії this що це не здається. Якщо a була локальною змінною (яка вона виглядає), то це не спрацює. - jfriend00
@ jfriend00 ви маєте на увазі, якщо ви розмістили var a; десь? - jontro
Так. Посилання a == 1 має на увазі, ніж a є змінною де-небудь, а не властивістю this. У той час як є місце oddball як globals, де обидва можуть бути правдою, загалом, оголошення змінної з var a або let a означає, що немає this що дозволяє вам отримати доступ a як властивість, як ви вважаєте кодом. Отже, ваш код, мабуть, припускає якусь дивну глобальну змінну річ. Наприклад, ваш код не працює в node.js, а не в суворій режимі всередині функції. Ви повинні вказати точні обставини, де він працює, і, можливо, пояснити, чому він працює. В іншому випадку це вводить в оману. - jfriend00
@ jfriend00 добре впевнені Не впевнений, що це додасть значно більшу цінність у поєднанні з іншими вже відповідями. Оновити відповідь - jontro
Питання було, чи може це "коли-небудь" бути правдою. І відповідь - так, і це один з сценаріїв, де це може бути правдою: a не є локальною змінною і визначається у глобальному масштабі за допомогою додаткового геттера. - Zac Delventhal


Це можливо в разі змінної a доступ до якого, скажімо, 2 веб-працівники через SharedArrayBuffer, а також деякий основний скрипт. Можливість низька, але можливо, що коли код скомпільований до машинного коду, веб-працівники оновлюють змінну a саме вчасно, таким чином, умови a==1, a==2 і a==3 задоволені.

Це може бути прикладом стану перегонів в багатопотоковій середовищі, що надається веб-працівниками та SharedArrayBuffer в JavaScript.

Ось основна реалізація вище:

main.js

// Main Thread

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

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

worker.js

let array

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

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

modifier.js

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

На моєму MacBook Air це сталося після приблизно 10 мільярдів ітерацій на першій спробі:

enter image description here

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

enter image description here

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

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


171
2018-01-17 07:39



Чесно кажучи, це найкраща відповідь. Вся інша відповідь вимагає навмисної спроби зробити щось глибоко неінфункціональне. Ця відповідь фактично відображає те, що може статися в реальному світі - умовам перегонів. - Tom Swirly
Не тільки це - я дійсно бачив це відбувається в реальному світі. Не з точною умовою в питанні, але, звичайно ж, з перевіркою (a == 1) на початку функції і (a == 2) пізніше в функції, і наявність коду призвело до обидва умов. FYI, перший раз, коли я бачив, що це відбувається, було в контролері двигуна автомобіля, і ми встановили стандарти кодування. Другий час в пуховій машині і дозатор для військових літаків, і на моєму дуже перший день у компанії Я знайшов це і виправив це, а решта команди все ще обговорювали проблему. (Kudos рівень: високий! :) - Graham
Отже, ви працювали на "контролерах автомобільних двигунів" та "системах розливу та розливу", які запрограмовані в JavaScript у веб-працівників? Я не думаю, що знову вийду зовні. - psaxton
@ pscxton :) Звичайно, немає - але у нас є багатопотокове програмне забезпечення з загальними даними. Це анти-схема для всього багатопоточного програмного забезпечення, не специфічного для Javascript або веб-працівників. Неважливо, чи програмуєте ви на ассемблері, Brainf * ck, Visual BASIC, C або Javascript - якщо ви робите це з загальними даними у багатопотоковій програмі, це буде завжди невдача - Graham
Я думаю, що це зараз детальна обгортка навколо відповіді @ jontro. - qntm


Це також можливо за допомогою серії власних перезаписуваних геттерів:

(Це схоже на рішення 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.");
    }
})();


141
2018-01-16 11:37



Зауважте, що також використовується підхід використання getter ===, не лише ==. - Makyen
Зауважте, що це також працює з меншим відступом. - Evert
Це надмірна ... - Patrick Roberts
На це покладається this будучи глобальним об'єктом всередині тіла функції стрілки. - Roy Tinker
@ Патрик Робертс А все інше тут немає? - Midnightas