В мире JavaScript есть принуждение - детективная история
Натан, ты не представляешь, что ты раскрыл.
Я расследую это уже несколько недель. Все началось бурной ночью в октябре прошлого года. Я случайно наткнулся на Numberкласс - я имею в виду, почему в мире JavaScript был Numberкласс?
Я не был готов к тому, что я собирался узнать дальше.
Оказывается, JavaScript, не сказав вам, меняет ваши номера на объекты, а ваши объекты на числа прямо у вас под носом.
JavaScript надеялся, что никто не поймет, но люди сообщают о странном неожиданном поведении, и теперь, благодаря вам и вашему вопросу, у меня есть доказательства того, что мне нужно взорвать эту штуку.
Это то, что мы узнали до сих пор. Я не знаю, должен ли я даже сказать вам это - вы можете отключить JavaScript.
> function dis() { return this }
undefined
Когда вы создавали эту функцию, вы, вероятно, не знали, что будет дальше. Все выглядело хорошо, и все было хорошо - пока.
Никаких сообщений об ошибках, только слово «undefined» в выводе консоли, именно то, что вы ожидаете. В конце концов, это было объявление функции - оно не должно ничего возвращать.
Но это было только начало. Что произошло дальше, никто не мог предсказать.
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}
Да, я знаю, вы ожидали 5, но это не то, что вы получили, это было - у вас есть что-то еще - что-то другое.
То же самое случилось со мной.
Я не знал, что с этим делать. Это сводило меня с ума. Я не мог спать, я не мог есть, я пытался выпить это, но никакая Горная Роса не заставила бы меня забыть. Это просто не имеет никакого смысла!
Именно тогда я узнал, что на самом деле происходит - это было принуждение, и это происходило прямо перед моими глазами, но я был слишком слеп, чтобы это увидеть.
Мозилла попыталась похоронить его, положив туда, где, как они знали, никто не будет искать, - свою документацию .
После нескольких часов рекурсивного чтения, перечитывания и перечитывания я обнаружил следующее:
«... и примитивные значения будут преобразованы в объекты».
Это было прямо здесь, как можно прописать шрифтом Open Sans. Это была call()функция - как я мог быть таким глупым ?!
Мой номер больше не был номером. В тот момент, когда я это передал call(), это стало чем-то другим. Это стало ... объектом.
Сначала я не мог в это поверить. Как это могло быть правдой? Но я не мог игнорировать доказательства, которые накапливались вокруг меня. Это прямо здесь, если вы просто посмотрите:
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
wtfбыл прав. Числа не могут иметь пользовательских свойств - мы все это знаем! Это первое, чему вас учат в академии.
Мы должны были знать момент, когда мы увидели вывод консоли - это был не тот номер, о котором мы думали. Это был самозванец - объект, выдававший себя за наше милое невинное число.
Это было ... new Number(5).
Конечно! Это имело смысл. call()у него была работа, он должен был вызывать функцию, и для этого ему нужно было заполнить this, он знал, что не может сделать это с числом - ему нужен объект, и он готов сделать все, чтобы получить его, даже если это означало принуждение нашего номера. Когда call()увидел номер 5, он увидел возможность.
Это был идеальный план: подождите, пока никто не посмотрел, и обменяйте наш номер на объект, который выглядит точно так же, как он. Мы получаем число, функция вызывается, и никто не станет мудрее.
Это действительно был идеальный план, но, как и во всех планах, даже идеальных, в нем была дыра, и мы собирались упасть прямо в нее.
Видите, call()не понимал только то, что он был не единственным в городе, кто мог принуждать числа. В конце концов, это был JavaScript - принуждение было повсюду.
call() взял мой номер, и я не собирался останавливаться, пока не снял маску с его маленького самозванца и не открыл его всему сообществу переполнения стека.
Но как? Мне нужен был план. Конечно, это похоже на число, но я знаю, что это не так, должен быть способ доказать это. Это оно! Это похоже на число, но может ли оно действовать как единое целое?
Я сказал, что fiveмне нужно, чтобы он стал в 5 раз больше - он не спросил почему, а я не объяснил. Затем я сделал то, что сделал бы любой хороший программист: я размножился. Конечно, не было никакого способа, которым он мог фальсифицировать свой выход из этого.
> five * 5
25
> five.wtf
'potato'
Черт побери! Мало того, что fiveумножение просто отлично wtfбыло еще там. Черт бы побрал этого парня и его картошку.
Что, черт возьми, происходит? Был ли я неправ во всем этом? Это fiveдействительно число? Нет, я должен что-то упустить, я знаю это, я должен кое-что забыть, что-то настолько простое и базовое, что я полностью упускаю это из виду.
Это выглядело не очень хорошо, я писал этот ответ в течение нескольких часов, и я все еще не был ближе к тому, чтобы высказать свою точку зрения. Я не мог продолжать это, в конце концов, люди перестали читать, мне нужно было что-то придумать, и я должен был быстро обдумать это.
Подождите, вот и все! fiveне было 25, 25 было результатом, 25 было совершенно другим числом. Конечно, как я мог забыть? Числа неизменны. Когда вы умножаете, 5 * 5ничто не присваивается ни для чего, вы просто создаете новый номер 25.
Это должно быть то, что здесь происходит. Каким-то образом, когда я умножаю five * 5, fiveдолжен быть приведен в число, и это число должно быть тем, которое используется для умножения. Именно результаты этого умножения выводятся на консоль, а не их ценность five. fiveникогда ничего не назначается - поэтому, конечно, это не изменится.
Итак, как же я могу fiveназначить себе результат операции? Я понял. Прежде чем fiveдаже имел возможность подумать, я вопил «++».
> five++
5
Ага! Я имел его! Все знают 5 + 1это6 , это было доказательством мне нужно было выставить , что fiveне было рядом! Это был самозванец! Плохой самозванец, который не знал, как считать. И я мог это доказать. Вот как действует действительное число:
> num = 5
5
> num++
5
Подождите? Что здесь происходило? вздох Я так увлекся перебором, fiveчто забыл, как работают почтовые операторы. Когда я использую ++в конце слова, fiveя возвращаю текущее значение, затем увеличиваю five. Это значение перед выполнением операции выводится на консоль. numбыл на самом деле6 и я мог это доказать
>num
6
Время посмотреть что five самом деле было:
>five
6
... это было именно то, что должно быть. fiveбыло хорошо - но мне было лучше. Если бы fiveвсе еще был объект, это означало бы, что он все еще имел бы свойствоwtf и я был готов поспорить на все, чего не было.
> five.wtf
undefined
Ага! Я был прав. Я имел его! fiveтеперь был числом - это больше не был объект. Я знал, что трюк умножения не спасет его на этот раз. Видите five++это действительно five = five + 1. В отличие от умножения, ++оператор присваивает значение five. Более конкретно, он присваивает ему результаты, five + 1которые, как и в случае умножения, возвращают новое неизменное число .
Я знал, что он у меня есть, и просто чтобы убедиться, что он не сможет выбраться из этого. У меня был еще один тест в рукаве. Если бы я был прав, и сейчас fiveбыл действительно номером, это не сработало:
> five.wtf = 'potato?'
'potato?'
Он не собирался обманывать меня на этот раз. Я знал, potato?что будет напечатан на консоли, потому что это вывод задания. Реальный вопрос, все wtfеще будет там?
> five.wtf
undefined
Как я и подозревал - ничего - потому что числам не могут быть назначены свойства. Мы узнали, что первый год в академии;)
Спасибо Натан. Благодаря вашей смелости, задавая этот вопрос, я наконец могу оставить все это позади и перейти к новому делу.
Как этот о функции toValue(). О Боже мой. Нееет!
++кажется, влияет на базовый тип