В недавнем твите содержался этот фрагмент 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) является число с каким-то свойством [[PrimitiveValue]], а результатами five++ и five * 5 являются обычные числа 5 и 25 (не числа)
  • .
  • почему свойство five.wtf исчезает после инкремента five++
  • почему свойство five.wtf больше не может быть установлено после five++ инкремента, несмотря на то, что присвоение five.wtf = 'potato?' очевидно устанавливает значение.

Nathan Long

Ответов: 10

Ответы (10)

ОП здесь. Забавно видеть это на Stack Overflow :)

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

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

  2. Согласование между этими двумя понятиями является неявным.

    Например:

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

Ок, поехали.

Оригинальное изображение кода JavaScript

Обязательство.

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

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

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

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

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

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

Поворот.

> five++
5
> five.wtf
undefined

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

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

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

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

Престиж.

> five
6

С тех пор как появился постфикс, five стало 6.

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

1.

    function dis() { return this }

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

2.

    five = dis.call(5)

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

3.

   five.wtf = 'potato'

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

4.

    five * 5

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

5.

    five.wtf

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

6.

    five++

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

Теперь, поскольку five является число, вы больше не можете задавать ему свойства, пока не сделаете что-то вроде этого:

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

или

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

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

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

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

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

.
  1. Если код функции является строгим кодом, установите ThisBinding на thisArg.
  2. Если thisArg равен null или неопределен, установите ThisBinding на глобальный объект.
  3. Если Type(thisArg) не является Object, установите ThisBinding на ToObject(thisArg).

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

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

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

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

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

07 исследуется свойство five объекта wtf

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

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

9.3 ToNumber:

  1. Пусть primValue будет ToPrimitive(входной аргумент, подсказка Number).
  2. Возврат ToNumber(primValue).

9.1 ToPrimitive:

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

.

8.12.8 [[Значение по умолчанию]]:

.

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

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

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

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

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

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

.

11 свойство five объекта wtf оценивается вновь, несмотря на то, что оно не изменилось с момента присвоения в 05.

12 'potato'

13 на five вызывается Postfix Increment Operator, который получает числовое значение (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 не определено, как объяснялось выше

21 five is accessed

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

Пара концепций объясняет, что происходит

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

Число {[[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;

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

.

Натан, вы даже не представляете, что вы открыли.

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

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

Оказывается, JavaScript, не говоря вам об этом, меняет ваши числа на объекты, а объекты на числа прямо у вас под носом.

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

Это то, что мы выяснили на данный момент. Не знаю, стоит ли вообще говорить вам об этом - возможно, вы захотите отключить JavaScript.

> function dis() { return this }
undefined

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

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

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

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

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

Со мной произошло то же самое.

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

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

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 не было 25, 25 было результатом, 25 было совершенно другим числом. Конечно, как я мог забыть? Числа неизменны. Когда вы умножаете 5 * 5, ничего не присваивается, вы просто создаете новое число 25.

Вот что здесь происходит. Каким-то образом, когда я умножаю five * 5, five должно быть принудительно превращено в число, и это число должно быть использовано для умножения. В консоль выводится результат умножения, а не само значение five. five никогда ничего не присваивается - поэтому, конечно, оно не меняется.

Так как же мне заставить five присвоить себе результат операции. У меня получилось. Прежде чем five успел подумать, я крикнул "++".

> five++
5

Ага! Я поймал его! Все знают, что 5 + 1 равно 6, это было то доказательство, которое мне было нужно, чтобы показать, что пять не было числом! Это был самозванец! Плохой самозванец, который не знал, как считать. И я мог это доказать. Вот как ведет себя настоящее число:

> num = 5
5
> num++
5

Погодите? Что здесь происходило? вздох Я так увлекся разбиением five, что забыл, как работают операторы post. Когда я использую ++ в конце five, я говорю, что возвращаю текущее значение, а затем увеличиваю five. В консоль выводится значение до выполнения операции. num на самом деле было 6, и я могу это доказать:

>num
6

Время посмотреть, чем на самом деле была пятерка:

>five
6

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

> five.wtf
undefined

Ага! Я был прав. Он был у меня! five теперь было числом - это больше не был объект. Я знал, что трюк с умножением не спасет его на этот раз. Видите ли, five++ - это на самом деле five = five + 1. В отличие от умножения, оператор ++ присваивает значение five. Точнее, он присваивает ему результат five + 1, который, как и в случае умножения, возвращает новое неизменяемое число.

Я знал, что поймал его, и чтобы убедиться, что он не сможет выкрутиться. У меня был еще один тест в рукаве. Если я прав, и пять теперь действительно число, то это не сработает:

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

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

> five.wtf
undefined

Как я и предполагал - ничего - потому что номерам нельзя присваивать свойства. Это мы узнали на первом курсе академии ;)

Спасибо, Натан. Благодаря твоей смелости в задании этого вопроса я наконец-то могу оставить все это позади и перейти к новому делу.

Нравится вот эта про функцию toValue(). О боже. Неееет!

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

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

Function.prototype.call() (из MDN)

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

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

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

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

//существующий пример
console.log(primitiveToObject(5));

//бесконечность
console.log(primitiveToObject(1/0));

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

//строка
console.log(primitiveToObject("hello world"));

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

Примитивные значения не могут иметь свойства. Но когда вы пытаетесь получить доступ к свойству примитивного значения, оно прозрачно транстипируется во временный объект 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

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

function dis () { return this; }

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

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

Так что возвратом является object

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

.

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

.

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

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), пожалуйста, смотрите Как работает ключевое слово "this"? . Скажем лишь, что первый аргумент 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"

Объект Number принимает новые свойства.

> five++

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

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

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

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

Объявите функцию 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 теперь является просто примитивным число. Оно печатает 5, а затем добавляет 1 к five.

five++
5

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

five.wtf
undefined

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

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

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

five.wtf
undefined

5 стало 6 из-за инкрементирования постов выше

five
6

2022 WebDevInsider