Что происходит в этом коде с объектами Number, сохраняющими свойства и увеличивающими число?

Недавний твит содержал этот фрагмент JavaScript.

Может кто-нибудь объяснить, что происходит в нем шаг за шагом?

> function dis() { return this }
undefined
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
> five * 5
25
> five.wtf
"potato"
> five++
5
> five.wtf
undefined
> five.wtf = 'potato?'
"potato?"
> five.wtf
undefined
> five
6

В частности, мне не ясно:

  • почему результат dis.call(5) является Number с каким-либо свойством a [[PrimitiveValue]], но результаты five++ и five * 5 кажутся просто равными числами 5 и 25 (не Number s)
  • почему свойство five.wtf исчезает после приращения five++
  • почему свойство five.wtf больше не устанавливается после приращения five++, несмотря на то, что назначение five.wtf = 'potato?', по-видимому, устанавливает значение.

Ответ 1

OP здесь. Забавно видеть это при переполнении стека:)

Прежде чем перейти к поведению, важно прояснить несколько вещей:

  • Числовое значение и Числовой объект (a = 3 vs a = new Number(3)) очень другой. Один из них примитивен, другой - объект. Вы не можете назначать атрибуты примитивам, но можете создавать объекты.

  • Принуждение между ними неявно.

    Например:

    (new Number(3) === 3)  // returns false
    (new Number(3) == 3)   // returns true, as the '==' operator coerces
    (+new Number(3) === 3) // returns true, as the '+' operator coerces
    
  • Каждое выражение имеет возвращаемое значение. Когда REPL читает и выполняет выражение, это то, что он отображает. Возвращаемые значения часто не означают, что вы думаете, и подразумеваете вещи, которые просто не соответствуют действительности.

Хорошо, мы идем.

Original image of the JavaScript code

Залог.

> function dis() { return this }
undefined
> five = dis.call(5)
[Number: 5]

Определите функцию dis и call с помощью 5. Это будет выполнять функцию с 5 как контекст (this). Здесь он принуждается от значения Number к объекту Number. Очень важно отметить, что мы были в строгом режиме этого не произошло бы.

> five.wtf = 'potato'
'potato'
> five.wtf
'potato'

Теперь мы устанавливаем атрибут five.wtf на 'potato', а с пятью в качестве объекта, достаточно уверен, что он принимает Простое присваивание.

> five * 5
25
> five.wtf
'potato'

С five в качестве объекта я гарантирую, что он все равно сможет выполнять простые арифметические операции. Оно может. Сохраняются ли его атрибуты? Да.

Поворот.

> five++
5
> five.wtf
undefined

Теперь мы проверим five++. Трюк с постфиксным приращением состоит в том, что все выражение будет оценивать исходное значение, а затем увеличивать значение. Похоже, что five все еще пять, но на самом деле выражение оценивается до пяти, затем установите five в 6.

Не только five получил значение 6, но он был возвращен обратно в значение Number, и все атрибуты были потеряны. Поскольку примитивы не могут содержать атрибуты, five.wtf - undefined.

> five.wtf = 'potato?'
'potato?'
> five.wtf
undefined

Я снова пытаюсь переназначить атрибут wtf на five. Возвращаемое значение подразумевает, что оно хранится, но на самом деле это не потому, что five - это значение Number, а не объект Number. Выражение оценивается как 'potato?', но когда мы проверяем, мы видим, что оно не было назначено.

Престиж.

> five
6

С момента приращения постфикса five был 6.

Ответ 2

Существует два разных способа представления числа:

var a = 5;
var b = new Number(5);

Первый - это примитив, второй - объект. Для всех целей и задач оба ведут себя одинаково, за исключением того, что они выглядят по-разному при печати на консоли. Важным отличием является то, что в качестве объекта new Number(5) принимает новые свойства так же, как и любые простые {}, тогда как примитив 5 не выполняет:

a.foo = 'bar';  // doesn't stick
b.foo = 'bar';  // sticks

Что касается начальной части dis.call(5), см. Как работает ключевое слово "his" ?. Скажем, что первый аргумент call используется как значение this, и эта операция заставляет число в более сложную форму объекта Number. * Позже ++ заставляет его вернуться в примитив формы, потому что операция сложения + приводит к новому примитиву.

> five = dis.call(5)  // for all intents and purposes same as new Number(5)
Number {[[PrimitiveValue]]: 5}
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
Объект

A Number принимает новые свойства.

> five++

++ приводит к новому примитивному значению 6...

> five.wtf
undefined
> five.wtf = 'potato?'
"potato?"
> five.wtf
undefined

... который не имеет и не принимает пользовательские атрибуты.

* Обратите внимание, что в строгом режиме аргумент this обрабатывается по-разному и не будет преобразован в Number. См. http://es5.github.io/#x10.4.3 для деталей реализации.

Ответ 3

Там принуждение в мире JavaScript - история детектива

Нафан, ты понятия не имеешь, что ты раскрыл.

Я изучаю это уже несколько недель. Все началось в бурный вечер в октябре прошлого года. Я случайно наткнулся на класс Number - я имею в виду, почему в мире JavaScript имел класс Number?

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

Оказывается, JavaScript, не сообщая вам, меняет ваши номера на объекты и ваши объекты на цифры прямо под вашим носом.

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

Это то, что мы выяснили до сих пор. Я не знаю, должен ли я даже сказать вам это: вы можете отключить свой JavaScript.

> function dis() { return this }
undefined

Когда вы создали эту функцию, вы, вероятно, понятия не имели, что будет дальше. Все выглядело прекрасно, и все было хорошо - пока.

Нет сообщений об ошибках, просто слово "undefined" в выводе на консоль, что вы ожидаете. В конце концов, это было объявление функции - оно ничего не должно возвращать.

Но это было только начало. Что случилось дальше, никто не мог предсказать.

> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}

Да, я знаю, вы ожидали 5, но это не то, что вы получили, было ли это - у вас есть что-то еще - что-то другое.

То же самое случилось со мной.

Я не знал, что с этим делать. Это подтолкнуло меня. Я не мог спать, я не мог есть, я пытался выпить его, но никакая горная роса не заставила бы меня забыть. Это просто не имело никакого смысла!

Что, когда я узнал, что действительно происходит, это было принуждение, и это происходило прямо перед моими глазами, но я был слишком слеп, чтобы увидеть это.

Mozilla попыталась похоронить его, поставив его там, где они знали, что никто не будет выглядеть - их документация.

После нескольких часов рекурсивного чтения и повторного чтения и повторного чтения я нашел это:

"... и примитивные значения будут преобразованы в объекты."

Это было прямо там, как может быть написано в шрифте Open Sans. Это была функция call() - как я мог быть настолько глупым?!

Мой номер больше не был числом. В тот момент, когда я передал его в call(), это стало чем-то другим. Он стал... объектом.

Сначала я не мог поверить. Как это могло быть правдой? Но я не мог игнорировать доказательства, которые возникали вокруг меня. Это прямо там, если вы просто посмотрите:

> five.wtf = 'potato'
"potato"

> five.wtf
"potato"

wtf был прав. Номера не могут иметь пользовательские свойства - мы все это знаем! Это первое, что они учат вас в академии.

Мы должны были знать момент, когда мы увидели выход консоли - это был не тот номер, который мы так и думали. Это был самозванец - объект, передающий себя как наш сладкий невинный номер.

Это было... new Number(5).

Конечно! Это имело смысл. call() У него была работа, ему нужно было вызвать функцию, и для этого ему нужно было заполнить this, он знал, что не может сделать это с номером - ему нужен был объект, и он был готов сделать все, чтобы получить его, даже если это означало принуждение нашего номера. Когда call() увидел номер 5, он увидел возможность.

Это был идеальный план: дождитесь, пока никто не смотрит и не меняет наш номер для объекта, который выглядит так же, как он. Мы получаем число, функция вызывается, и никто не станет мудрее.

Это был идеальный план, но, как и все планы, даже совершенные, в нем была дыра, и мы собирались упасть прямо в него.

Видите, что call() не понимал, что он не единственный в городе, который мог бы принуждать цифры. Это был JavaScript в конце концов - принуждение было повсюду.

call() взял мой номер, и я не собирался останавливаться, пока не вытащил маску от своего маленького самозванца и не разоблачил его до всего сообщества Stack Overflow.

Но как? Мне нужен был план. Конечно, это похоже на число, но я этого не знаю, должен быть способ доказать это. Это! Он выглядит как число, но может ли он действовать как один?

Я сказал 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 is 6, это было доказательством того, что мне нужно было показать, что five не был числом! Это был самозванец! Плохой самозванец, который не знал, как считать. И я могу это доказать. Здесь, как действует действительное число:

> num = 5
5
> num++
5

Подождите? Что здесь происходило? вздох, я так увлекся тем, что забыл, как работают почтовые операторы. Когда я использую ++ в конце 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(). О Боже мой. Нееет!

Ответ 4

01 > function dis() { return this }
02 undefined
03 > five = dis.call(5)
04 Number {[[PrimitiveValue]]: 5}
05 > five.wtf = 'potato'
06 "potato"
07 > five.wtf
08 "potato"
09 > five * 5
10 25
11 > five.wtf
12 "potato"
13 > five++
14 5
15 > five.wtf
16 undefined
17 > five.wtf = 'potato?'
18 "potato?"
19 > five.wtf
20 undefined
21 > five
22 6

01 объявляет функцию dis, которая возвращает объект контекста. Что this представляет изменения в зависимости от того, используете ли вы строгий режим или нет. Весь пример имеет разные результаты, если функция была объявлена ​​как:

> function dis() { "use strict"; return this }

Это подробно описано в разделе в разделе 10.4.3 в спецификации ES5

  • Если код функции является строгим кодом, установите значение ThisBinding для этогоArg.
  • Если значение thisArg равно null или undefined, установите этот привязку для глобального объекта.
  • В противном случае, если Type (thisArg) не является объектом, установите значение ThisBinding для ToObject (thisArg).

02 - это возвращаемое значение объявления функции. undefined должен быть понятным здесь.

03 переменная five инициализируется возвращаемым значением dis при вызове в контексте примитивного значения 5. Поскольку dis не находится в строгом режиме, эта строка идентична вызову five = Object(5).

04 Возвращаемое значение нечетного Number {[[PrimitiveValue]]: 5} представляет собой представление объекта, который обертывает примитивное значение 5

05 Свойству five object wtf присваивается строковое значение 'potato'

06 - это возвращаемое значение присваивания и должно быть самоочевидным.

07 проверяется свойство five object wtf

08 поскольку five.wtf ранее был установлен в 'potato', он возвращает 'potato' здесь

09 объект five умножается на примитивное значение 5. Это ничем не отличается от любого другого объекта, который размножается и объясняется в разделе 11.5 спецификации ES5. Особо следует отметить, как объекты передаются в числовые значения, которые рассматриваются в нескольких разделах.

9.3 ToNumber:

  • Пусть primValue является ToPrimitive (входной аргумент, номер подсказки).
  • Возврат ToNumber (primValue).

9.1 ToPrimitive:

Возвращает значение по умолчанию для объекта. Значение по умолчанию для объекта извлекается, вызывая внутренний метод [[DefaultValue]] объекта, передавая необязательный подсказку PreferredType. Поведение внутреннего метода [[DefaultValue]] определяется этой спецификацией для всех собственных объектов ECMAScript в 8.12.8.

8.12.8 [[DefaultValue]]:

Пусть valueOf является результатом вызова внутреннего метода [[Get]] объекта O с аргументом "valueOf".

  • Если IsCallable (valueOf) истинно, то

    • Пусть val является результатом вызова внутреннего метода [[Call]] значенияOf, с O в качестве этого значения и пустым списком аргументов.
    • Если val является примитивным значением, верните val.

Это все окольный способ сказать, что функция object valueOf вызывается, и в уравнении используется возвращаемое значение этой функции. Если вы хотите изменить функцию valueOf, вы можете изменить результаты операции:

> five.valueOf = function () { return 10 }
undefined
> five * 5
50

10 как функция five valueOf не изменилась, она возвращает завернутое примитивное значение 5, так что five * 5 оценивается как 5 * 5, что приводит к 25

11 свойство five object wtf оценивается снова, несмотря на то, что оно не изменилось с момента его назначения на 05.

12 'potato'

13 Оператор Postfix Increment Operator вызывается на five, который получает числовое значение (5, мы рассмотрели, как раньше), сохраняет значение так что он может быть возвращен, добавляет 1 к значению (6), присваивает значение five и возвращает сохраненное значение (5)

14, как и прежде, возвращаемое значение - это значение, прежде чем оно будет увеличено

15 Доступно свойство wtf примитивного значения (6), хранящегося в переменной five. Раздел 15.7.5 спецификации ES5 определяет это поведение. Числа получают свойства от Number.prototype.

16 Number.prototype не имеет свойства wtf, поэтому undefined возвращается

17 five.wtf присваивается значение 'potato?'. Назначение определено в 11.13.1 спецификации ES5. В основном присваиваемое значение возвращается, но не сохраняется.

18 'potato?' был возвращен оператором присваивания

19 снова five, доступ к которому имеет значение 6, и снова Number.prototype не имеет свойства wtf

20 undefined, как описано выше

Доступ к

21 five

22 6 возвращается, как описано в 13

Ответ 5

Это довольно просто.

function dis () { return this; }

Возвращает контекст this. Итак, если вы делаете call(5), вы передаете число как объект.

Функция call не предоставляет аргументы, первый аргумент, который вы даете, представляет собой контекст this. Обычно, если вы хотите его использовать в контексте, вы даете ему {} so dis.call({}), что означает, что this в функции пуст this. Однако, если вы пройдете 5, кажется, что он будет преобразован в объект. См. .call

Таким образом, возврат object

Когда вы выполняете five * 5, JavaScript видит объект five как примитивный тип, поэтому он эквивалентен 5 * 5. Интересно, что do '5' * 5, он все равно равен 25, поэтому JavaScript явно подбрасывается под капот. В этой строке не выполняется никаких изменений в базовом типе five

Но когда вы сделаете ++, он преобразует объект в примитивный тип number, удалив при этом свойство .wtf. Поскольку вы затрагиваете базовый тип

Ответ 6

У примитивных значений не может быть свойства. Но когда вы пытаетесь получить доступ к свойству на примитивном значении, он прозрачно транслирует на временный объект Number.

Итак:

> function dis() { return this }
undefined
// Like five.dis(), so dis return the temporaty Number object and 
// reference it in five
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}

// Write the wtf attribut on the Number object referenced by five
> five.wtf = 'potato'
"potato"
// Read the wtf attribut on the Number object referenced by five
> five.wtf
"potato"

// Return 5*5 but dont change the reference of five
> five * 5
25
// Read the same wtf attribut on the Number object referenced by five
> five.wtf
"potato"

// Change the five reference to a new primitive value (5+1). Five
// reference a primitive now.
> five++
5

// Read the wtf attribut on a new temporary Number object construct from
// the primitive referenced by five. So wtf does not exist.
> five.wtf
undefined

// Write the wtf attribut on a new temporary Number object construct from
// the primitive referenced by five. But this object not referenced by
// five. It will be lost.
> five.wtf = 'potato?'
"potato?"

// Read the wtf attribut on a new temporary Number object construct from
// the primitive referenced by five. So wtf does not exist.
> five.wtf
undefined
> five
6

Ответ 7

Объявить функцию dis. Функция возвращает свой контекст

function dis() { return this }
undefined

Вызвать dis с помощью контекста 5. Примитивные значения вставляются в коробку при передаче в контексте в строгом режиме (MDN). Таким образом, five теперь является объектом (число в коробке).

five = dis.call(5)
Number {[[PrimitiveValue]]: 5}

Объявить свойство wtf в переменной five

five.wtf = 'potato'
"potato"

Значение five.wtf

five.wtf
"potato"

five помещается в коробку 5, поэтому число и объект одновременно (5 * 5 = 25). Он не изменяет five.

five * 5
25

Значение five.wtf

five.wtf
"potato"

Разблокировать five здесь. five теперь просто примитивен number. Он печатает 5, а затем добавляет 1 в five.

five++
5

five - это примитивное число 6, теперь в нем нет никаких свойств.

five.wtf
undefined

примитивы не могут иметь свойств, вы не можете установить этот

five.wtf = 'potato?'
"potato?"

вы не можете прочитать это, потому что он не был установлен

five.wtf
undefined

five - 6 из-за увеличения пошагового сообщения выше

five
6

Ответ 8

Прежде всего, похоже, что это выполняется через консоль nodejs.

1.

    function dis() { return this }

создает функцию dis(), но поскольку она не была установлена ​​как var, для возврата не было значения, поэтому undefined был результатом, хотя был определен dis(). В sidenote this не был возвращен, потому что функция не была выполнена.

2.

    five = dis.call(5)

Это возвращает объект javascript Number, потому что вы просто устанавливаете значение функции dis() this для примитива 5.

3.

   five.wtf = 'potato'

Первая возвращает "potato", потому что вы просто установили свойство wtf из five в 'potato'. Javascript возвращает значение переменной, которую вы установили, что упрощает привязку нескольких переменных и устанавливает их в одно и то же значение: a = b = c = 2.

4.

    five * 5

Это возвращает 25, потому что вы просто умножили примитивное число 5 на five. Значение five определялось значением объекта Number.

5.

    five.wtf

Я пропустил эту строку раньше, потому что я бы повторил ее здесь. Он просто возвращает значение свойства wtf, которое вы установили выше.

6.

    five++

Как сказал @Callum, ++ преобразует тип в Number из того же значения из объекта Number {[[PrimitiveValue]]: 5}}.

Теперь, поскольку five является Number, вы больше не можете устанавливать свойства, пока не выполните следующее:

    five = dis.call(five)
    five.wtf = "potato?"

или

    five = { value: 6, wtf: "potato?" }

Также обратите внимание, что второй способ будет иметь другое поведение, чем использование первого метода, поскольку он определяет общий объект вместо объекта Number, который был создан ранее.

Надеюсь, это поможет, javascript любит принимать вещи, поэтому он может запутаться при смене объекта Number на примитив Number. Вы можете проверить, что это такое, используя ключевое слово typeof, записывая       тип пять после инициализации он возвращает 'object', а после five++ он возвращает 'number'.

@deceze очень хорошо описывает разницу между объектом Number и примитивным числом.

Ответ 9

Области JavaScript создаются из контекстов выполнения. Каждый контекст выполнения имеет лексическую среду (внешние/глобально ограниченные значения), переменную среду (локально привязанные значения) и эту привязку.

Эта привязка является очень важной частью контекста выполнения. Использование call - это один из способов изменить эту привязку, и это автоматически создаст объект для заполнения привязки с помощью.

Функция .prototype.call() (из MDN)

Синтаксис
fun.call(thisArg[, arg1[, arg2[, ...]]])

thisArg
Ценность этого обеспечила для удовольствия. Обратите внимание, что это может быть не фактическое значение, которое видит метод: если метод является функцией в коде нестрого режима, то null и undefined будут заменены глобальным объектом, а примитивные значения будут преобразованы в объекты. (акцент мой)

Как только очевидно, что 5 преобразуется в new Number(5), остальное должно быть довольно очевидным. Обратите внимание, что другие примеры также будут работать, пока они являются примитивными значениями.

function primitiveToObject(prim){
  return dis.call(prim);
}
function dis(){ return this; }

//existing example
console.log(primitiveToObject(5));

//Infinity
console.log(primitiveToObject(1/0));

//bool
console.log(primitiveToObject(1>0));

//string
console.log(primitiveToObject("hello world"));
<img src="http://i.stack.imgur.com/MUyRV.png" />

Ответ 10

Несколько понятий объясняют, что происходит

5 - это число, примитивное значение

Number {[[PrimitiveValue]]: 5} - это экземпляр Number (пусть он вызывает обертку объекта)

Всякий раз, когда вы получаете доступ к свойству/методу на примитивном значении, JS-движок создает обертку объекта соответствующего типа (Number для 5, String для 'str' и Boolean для true) и разрешить вызов доступа к ресурсу/методу на этой обертке объекта. Это то, что происходит, когда вы делаете true.toString(), например.

При выполнении операций над объектами они преобразуются в примитивные значения (используя toString или valueOf) для разрешения этих операций - например, при выполнении

var obj = { a : 1 };
var string = 'mystr' + obj;
var number = 3 + obj;

String будет содержать конкатенацию строк mystr и obj.toString() и Number будет содержать добавление 3 и obj.valueOf().

Теперь, чтобы собрать все вместе

five = dis.call(5)

dis.call(5) ведет себя точно так же, как (5).dis(), если 5 имел метод dis. Чтобы разрешить вызов метода, создается обертка объекта и разрешается вызов метода. На этом этапе пять точек к обертке объекта вокруг примитивного значения 5.

five.wtf = 'potato'

Установка свойства объекта, здесь ничего не интересного.

five * 5

Это фактически five.valueOf() * 5 получение примитивного значения из обертки объекта. five все еще указывает на исходный объект.

five++

Это фактически five = five.valueOf() + 1. До этой строки five хранится обертка объекта вокруг значения 5, а после этой точки five выполняется примитивное значение 6.

five.wtf
five.wtf = 'potato?'
five.wtf

five больше не является объектом. Каждая из этих строк создает новый экземпляр Number, чтобы разрешить доступ к свойству .wtf. Экземпляры независимы, поэтому установка свойства на одном не будет видна на другом. Код полностью эквивалентен этому:

(new Number(6)).wtf;
(new Number(6)).wtf = 'potato?';
(new Number(6)).wtf;