Pull to refresh

Comments 64

Когда в очередной раз читаю про типы и их приведения в JS, вспоминаю это
Спасибо — я это еще не видел, очень весело!
Докладчик в том видео рассказывает смешно, но есть ошибки в его примерах.
Например, там где он говорит про object + object ( {} + {} )
Первый object — это совсем не объект, а пустой блок кода, т.е. остается только +{}, что, естесственно, приводится к NaN
Про []+{} автор сказал что получается объект, но на самом деле это строка "[object Object]"
Можно долго спорить про строгую-нестрогую типизацию, но приведение типов в js сделано вполне с умом
Рас уж начал, то в {} + [] та же ошибка, {} — это пустой блок кода
Я бы даже уточнил и сказал бы, что там по сути складывается undefined, а undefined+undefined(или просто) +undefined приводится к NaN
Все-таки нет, первые скобки — это таки пустой блок кода, который если его запустить отдельно действительно вернет undefined. Но перед знаком + он ничего не значит.
Вторые скобки уже распарсятся как объект. Иначе []+{} выдало бы «undefined», а не "[object Object]"
Это лучший язык программирования который (был написан) можно было бы написать за две недели (ц) 2kan
Можно ещё вынести, что лучше создать полноценный объект, вместо того, чтобы использовать примитивы, если предполагается вызов методов у них, особенно неоднократный.
Да, согласен. Хороший совет. Действительно, если планируется частый вызов методов, то не стоит постоянно нагружать интерпретатор созданием обёртки. И наоборот, если нужно хранить только строку или число, которое потом просто будет выводится на экран, то стоит сделать это исключительно примитивом. Спасибо!
> Объект — это структура данных(целый их набор), представленный в виде набора пар «ключ-значение».

Правильнее будет хэш.
Можно еще назвать 'Ассоциативный массив', но лучше называть все своими иенами, в javascript-е это объект.
Объектами также является всё, что создаётся оператором new:

typeof new Number(2); // 'object'

// пробуем создать свойство
var a = 2,
      b = new Number(3);
a.prop = true;
b.prop = true;

a.prop; // undefined
b.prop // true
Поэтому лучше различать объекты и хэши (да, ассоциативные массивы, если угодно).
Очень красочный пример. я как раз говорил о том почему a.prop; // undefined
По поводу new в следующей статье
Ключ может быть как числовой(нумерованный), так и буквенный(именованный)


В JavaScript-е ключи имеют строковой тип!. Поэтому все что вы передаете в качестве ключа приводится к строке, будь то number, object, boolean, undefined или null.

И как я их называю «философские типы»:
— null (v = null)
— undefined (u=undefined)


Null и Undefined — можно еще называть тривиальными типами данных, т.е. они имеют только одно значение.

12. toString(); //число не станет переменной но его уже можно использовать как объект


Тут ошибка!

v4 = String(2); //строковая глобальная переменная вызванная через конструктор. Создаст переменную window.v4


Не глобальная переменная, а свойство глобального объекта (window как частный случай глобального объекта).

Они есть для всех примитивов (Number(), Boolean(), String(), Object())


Причем здесь Object? Вы же сами написали что Object не примитивный тип данных.
Да и функции-обертки тоже как то странно звучит, это конструкторы (если применять их с оператором new, Object можно и без new).

На самом деле, забегая наперёд, во время оборачивания примитива в объект, выстраивается целая цепочка наследования (как это организовано мы поговорим позже), но по сути получается такая вот «матрёшка»:

Object(Number(<примитив>)).


Не будет такой матрешки не вводите в заблуждение! Посмотрите в спецификации.
Number(param) — возвращает числовое примитивное значение соответствующее переданному значению.
Object(param) — возвращает объектное представление соответствующее переданному параметру (Встроенная фабрика), если передан объект то он просто возвращается.

Проще:
Object() и new Object() всегда возвращает object
Number() всегда возвращает number
new Number() всегда возвращает object ([Object Number])


(ECMAScript v3)

P.S.

Это то что мне бросилось в глаза, если я не прав где то, то
обязательно поправьте меня!


Надеюсь что польза от этого комментария будет.
По поводу фразы:«Они есть для всех примитивов (Number(), Boolean(), String(), Object())» — я действительно увлекся. Есть много конструкторов среди которых и выше перечисленные, но Object(), конечно же не имеет никакого отношения к конструкторам примитивов — он действительно вернет объект.Исправлю.
Польза очень большая, пишите больше таких комментариев!
— 12. toString(); //число не станет переменной но его уже можно использовать как объект
Тут ошибка!
А в чем если не секрет?

— v4 = String(2); //строковая глобальная переменная вызванная через конструктор. Создаст переменную window.v4
Не глобальная переменная, а свойство глобального объекта (window как частный случай глобального объекта).
Я пока не старался настолько влезать в тонкости, хотя вы и правы. Но в простонародье на данном уровне статьи, формально можно сказать что это глобальная переменная

— На самом деле, забегая наперёд, во время оборачивания примитива в объект, выстраивается целая цепочка наследования (как это организовано мы поговорим позже), но по сути получается такая вот «матрёшка»:

Object(Number(<примитив>)).

Не будет такой матрешки не вводите в заблуждение! Посмотрите в спецификации.
Number(param) — возвращает числовое примитивное значение соответствующее переданному значению.
Object(param) — возвращает объектное представление соответствующее переданному параметру (Встроенная фабрика), если передан объект то он просто возвращается.
Матрёшка будет, поскольку «оборачивание» происходит с помощью вызова конструктора через new и это приведет к созданию объекта, который в свою очередь будут унаследованы от Object. А вот то что вы говорите произойдет если вызов будет без new — тогда и вправду вернется примитив.
> undefined – означает, что в переменную присвоили пустоту

А чем не устраивается прямой перевод «неопределенность — значение не определено»?
Да как угодно. Это не суть важно. Кому как проще для понимания. Вы кстати заметили — уже начинается философия вокруг этих двух понятий )). Это же не принципиально, к чему такие комментарии?
Просто зачем вводить какие-то свои термины, если простой перевод хорошо раскрывает смысл.
> Ключ может быть как числовой(нумерованный)
Лож. Ключ может быть только строкой:
Раз уж говорите сложно о простом, то:
o = {1:'a', 2:'b'}
o[3] = 'c'
for(var i in o) console.log( typeof i )
>(3) string

____

> Значением может быть любой из типов данных — тогда это будет свойство объекта, или даже функция — тогда это будет метод объекта.
Не функция, а ссылка на функцию. С объектами то же самое.
____

var v = null;
typeof v;
Стоит упомянуть, что в новых версиях ES typeof null === 'null'
____

> Object(Number(<примитив>))
Это что за шутки? Вы бы сперва с излагаемым материалом разобрались, в то вы мне напоминаете некоторых преподавателей из моего университета.
new Number наследует свойства Object только потому, что второй существует в цепочке родителей первого:
Number.prototype instanceof Object

А точнее:
 (new Number).__proto__.__proto__.constructor === Object

____

> Оператор же instanceof – проверяет принадлежит ли что-то к указанному типу данных.
Тип данных в JS о_0? instanceof проверяет, есть ли в цепочке родителей соответствующий конструктор.
> Object(Number(<примитив>))
Это что за шутки? Вы бы сперва с излагаемым материалом разобрались, в то вы мне напоминаете некоторых преподавателей из моего университета.
new Number наследует свойства Object только потому, что второй существует в цепочке родителей первого:

Отлично — я с вами согласен. Нельзя ли следуя из вашего замечания говорить, что условно получается такая вот «матрёшка» как я сказал?!? Постарайтесь понять, что я писал эту статью не только для таких молодцов как вы, знающих уже все нюансы, но и для тех кто только начал. Я не хотел перегружать информацией первую статью(а это будет цикл) и в некоторых моментах просто абстрагировался для более простого понимания. В дальнейших статьях я конечно расскажу и про наследования и про прототипы и про конструкторы.
И что вас собственно смутило в словосочетании «типы данных» в JS?!?

> Значением может быть любой из типов данных — тогда это будет свойство объекта, или даже функция — тогда это будет метод объекта.
Не функция, а ссылка на функцию. С объектами то же самое.

Вопрос собственно тот же: «Зачем пока на данном этапе это, если далее я более подробно опишу как устроен объект и конструкторы их создающие?»
«instanceof проверяет, есть ли в цепочке родителей соответствующий конструктор»
как вы думаете, если бы я так объяснил в первой статье, не появилось бы у новичка больше вопросов чем ответов??? И почему вы не прочитали следующую за этой фразу «Как он это делает, я расскажу в следующей статье»?
Т.е. вы решили сразу поделить всех, да?
:)

«О философии», к практике здесь это не имеет никакого отношения.

Наверняка есть множество подходов к изложению материала, только что придумал несколько, навскидку:

Можно начинать с азов, и смотреть как скучно «продвинутым».
Можно начинать с «жести» и смотреть как отсеялись почти «все остальные».

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

Можно вообще «не начинать».

Можно избрать «тон наставника», можно попытаться «стать своим парнем».

Не знаю как лучше, но лично мне не нравится деление людей по принципу «далёкие \ не далёкие», пусть они сами выбирают, какие они. В этом случае, если «не в коня корм» у них будет возможность отступить.

Здесь же получилось, что всё время интересно «что же там будет в следующей статье, чего нет здесь», поэтому мне не понравилось ощущение от прочтения в целом.

Поэтому такой резкий комментарий.
И, да, я не люблю «менторов».

Очень неприятно что у вас сложилось обо мне такое мнение что я, извольте, ментор. Я ещё очень много не знаю и надеялся, что комментарии здесь будут в стиле советов, а не нравоучений и что я и сам после написания ещё что-то новое узнаю. Но к сожалению сложилось мнение что большинство хабролюдей считают, что коль ты выложил здесь статью то должен знать абсолютно все, а если где-то пропустил, то не совет тебе а минус)) Очень жаль, но тоже опыт!
Делить я никого не хотел, просто понимаю что есть люди которые только синтаксис учат, а есть которые уже и опыт имеют. А угодить хотелось всем. Прочувствовал это, поскольку перед публикацией провел небольшую лекцию по данной теме у себя в фирме и появлялись очень «глупые» вопросы даже на таком уровне абстрагирования в некоторых моментах. Что было бы если бы я сразу начал углубляться — я не знаю, но в статье этого делать не стал.
:)

Мне 30 лет, я женат, у меня есть сын и я преподаю экономику.
Это чтобы расставить все точки и показать, что никому лично до Вас здесь никакого дела нет.
Простите за такие вынужденные меры.

>> Очень неприятно что у вас сложилось обо мне такое мнение что я, извольте, ментор. >>

Простите, но, не изволю, ведь я теперь тоже :)

Дело не в Вас, я Вас не знаю, и подозреваю, что раз уж Вы нашли в себе силы оставить предыдущий комментарий, то Вы, пожалуйста простите за несносность термина — «нормальный и адекватный человек».

Лично моя реакция это лишь отражение того, как статью воспринял я, это субъективно очень. Мы же все индивидуальности, на «вкус и цвет все фломастеры разные».

>> Я ещё очень много не знаю и надеялся, что комментарии здесь будут в стиле советов, а не нравоучений и что я и сам после написания ещё что-то новое узнаю. >>

Помните историю про обезьян и банан? Когда их поливали водой и постепенно меняли и в итоге ни одна обезьяна не знала почему банан брать нельзя, но не позволяла этого делать никому…

Соглашусь с Вами в очередной раз :)

>> Но к сожалению сложилось мнение что большинство хабролюдей считают, что коль ты выложил здесь статью то должен знать абсолютно все >>

Как правило это тоже так и есть.
Чтобы не «попадать» на эти грабли можно пытаться доносить всё с максимально точными формулировками.
Лично у меня это в основном не получается.

>> Очень жаль, но тоже опыт! >>

У меня прошло.
Это ведь тоже не важно, важно как и что Вы делаете.
Вот мне, например, однажды было интересно, что я буду есть сегодня вечером.
Было интересно потому, что я не смог понять то, что мне пытались объяснить.
Заметьте, в той ситуации я оставил виноватым себя, а Вы бы как поступили?

>> Делить я никого не хотел, просто понимаю что есть люди которые только синтаксис учат, а есть которые уже и опыт имеют. >>

Увы, да «упрощение» — это не метод, по крайней мере, видимо, не для этой конкретной статьи.

>> А угодить хотелось всем. >>

Простите ещё раз, но, например, я на завтрак и ужин предпочитаю ароматный кофе салу и борщу. Не откажусь и от сигареты, или трубки…
Есть здесь ещё такие же?

>> Прочувствовал это, поскольку перед публикацией провел небольшую лекцию по данной теме у себя в фирме и появлялись очень «глупые» вопросы даже на таком уровне абстрагирования в некоторых моментах. >>

Скажу честно, я до сих пор не верю, что в конце цепочки прототипов null, и каждый раз это проверяю.
Просто потму, что коворят, что он там должен быть…

>> Что было бы если бы я сразу начал углубляться — я не знаю, но в статье этого делать не стал. >>

Вот если бы мне кто-нибудь помог понять, почему у меня Scope (область видимости переменной) сейчас меняется…

— Да, прошу прощения за «Вы» с большой буквы у Вас и у Всех кто прочел этот комментарий, я так привык… С моей точки зрения это дань уважения (разделять и властвовать — не мой удел).

По поводу типов данных я погорячился.

Но, instanceof не проверяет на тип, он ищет соответствующего родителя в [[Prototype]]. А вот typeof — другое дело.

> Отлично — я с вами согласен. Нельзя ли следуя из вашего замечания говорить, что условно получается такая вот «матрёшка» как я сказал?!?
Так можно было не жадничать и сказать, что все типы приводятся к объекту так:
Object(Object(Object(...(Object(Number(x))...)))
Не бред ли?

Я бы вас попросил либо:
1. Не продолжать свой цикл.
2. Изменить часть заголовка на что-то типа «Для начинающих». Когда я увидел «Сложно о простом» и предложение «Потому что всё, что я буду рассказывать я буду рассказывать учитывая особенности работы интерпретатора, начиная с типов данных» подумал, что в статье будут описываться простые вещи с подробным и, что важно, истинным описанием их работы. Тем более эта ниша уже занята Поповым, который тоже нифига не понимает, но пытается учить.
Ну продолжать мне или нет я сам как-то решу(Могу лишь вам посоветовать читать или нет). А с чего вы взяли это: «Object(Object(Object(...(Object(Number(x))...)))» я не знаю. действительно бред.
Object(Number(x)) — который якобы добавляется интерпретатором — не меньший бред.

> Ну продолжать мне или нет я сам как-то решу
Продолжайте. Но сперва изучите излагаемый материал. Сейчас ваша статья плюсуется только теми, у кого уровень знаний явно ниже вашего, это вам позволяет нести любую ахинею.
Вы наверно не совсем поняли меня.Под «матрёшкой» Object(Number(x)) я не имел ввиду стек вызовов, я имел ввиду абстрактное представление примитива в случае обращения к нему как к объекту. Ну мол если с числом 5 будут обращаться как с объектом, то оно временно преобразуется(обернется) в объект при помощи new Number(5), а Number в свою очередь имеет в родителях Object. Именно данную иерархию наследования я пока и назвал «матрёшкой» и попытался отобразить в такой записи Object(Number(x), но это конечно не стек вызовов.
Такого бреда не будет, как вы написали. Если вы в консоли напишете b = new Number(2) а потом b.__proto__ то увидите, что b «унаследовано» от Number. Если продолжите и напишете b.__proto__.__proto__, то узнаете что Number унаследовано от Object. И если уж совсем не лень написать b.__proto__.__proto__.__proto__, то узнаете что Object не имеет наследников, он произведен от null. А что вы за бред написали я не знаю.
>… не строго типизированный язык. Это значит, что в момент объявления переменной мы не обязаны указать какого она типа, и более того во время работы программы в эту переменную можно ложить данные абсолютного любого типа.

Это свойство «не статической типизации».
Вот например Питону описанное тоже присуще, но он строго типизированный.
А С++ не присуще, но он НЕ строго типизированный.
Динами́ческая типиза́ция — приём, широко используемый в языках программирования и языках спецификации, при котором переменная связывается с типом в момент присваивания значения, а не в момент объявления переменной. Таким образом, в различных участках программы одна и та же переменная может принимать значения разных типов. Примеры языков, где есть динамическая типизация — Smalltalk, Python, Objective-C, C#, Ruby, PHP, Perl, JavaScript, Lisp, xBase.
ru.wikipedia.org/wiki/%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D1%82%D0%B8%D0%BF%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F
Что вы этим хотели сказать?
Да, я вместо «динамическая типизация» написал «не статическая типизация», вы на это намекаете?
Нет, я хотел эти сказать, что моя формулировка о которой вы написали в первом своем комментарии верна. Или вы не утверждали что она ошибочна и я вас не так понял?!
Она не верна.

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

> приём, широко используемый в языках программирования и языках спецификации, при котором переменная связывается с типом в момент присваивания значения, а не в момент объявления переменной. Таким образом, в различных участках программы одна и та же переменная может принимать значения разных типов. Примеры языков, где есть динамическая типизация — Smalltalk, Python, Objective-C, C#, Ruby, PHP, Perl, JavaScript, Lisp, xBase.

Ваше предложение со статьи и комментарий с википедии говорят о тех же вещах.
Но на википедии говориться о динамической типизации, вы же это приписываете не строгой типизации — а это ортогональные свойства.
Мне кажется вы не правы.
«Строгая типизация подразумевает выполнение следующих обязательных условий:
1. Любой объект данных (переменная, константа, выражение) в языке всегда имеет строго определённый тип, который фиксируется на момент компиляции программы (статическая типизация) или определяется во время выполнения (динамическая типизация).
2. Допускается присваивание переменной только значения, имеющего строго тот же тип данных, что и переменная, те же ограничения действуют в отношении передачи параметров и возврата результатов функций.
3. Каждая операция требует параметров строго определённых типов.
4. Неявное преобразование типов не допускается (то есть транслятор воспринимает любую попытку использовать значение не того типа, который был описан для переменной, параметра, функции или операции, как синтаксическую ошибку).»
Следовательно для нестрогой типизации(о которой я говорю в статье) действуют обратные принципы(которые я и описал в статье). В чем моя ошибка или не точность? Я не понимаю.
Я понял. Проблема не в вас, проблема в википедии.
Первых два пункта не относятся к строгой типизации.
Что интересно, там ниже указан Питон, для которого кстати эти два первых пункта и не выполняются — противоречие блин.
Короче нужно осторожней с википедией=)
Обожаю когда удается прийти к консенсусу! Спасибо за хоть и такое, но все же внимание к моей статье.
Кстати по-этому вам следовало бы подправить ваше определение «не строгой» типизации, и указать, что в описываемом языке у функций не указываются типы параметров (это НЕ-«третий пункт с вики») и что значения могут неявно преобразовываться, например, с числа в строку (это НЕ-«четвертый пункт с вики»).
На мой взгляд несколько сумбурно получилось. Подождем второй части.
При примитивы и объекты в JS мне понравилась вот эта статья (англ.)
Мне все-таки кажется, что стоило упомянуть о типе данных function, который наследуется от Object.
Например:
var f = new function( ){ };
или так
var f = function ( ){ }
или так:
function(){};
или так:
function f(){}
и подобно…
Я собираюсь описать это во второй части когда речь пойдет о конструкторах. Там они как-то более к месту будут!
Конструктор для него необязателен, как и для Object
Да, я это понимаю. Просто конструктор и функции как-то более связные понятия нежели типы данных и функции в данном языке, как мне кажется.
Хотя, в принципе, вы правы.
Стоило бы рассказать о блоках, прежде чем говорить о функциях.
Мне, все-таки, кажется что больше связи тут в «блоках кода» и «функции»… Просто о блоках всегда забывают.
Прошу прощения, что отвлекаю от дела «просвещения масс», но не могли бы Вы точно сформулировать разницу между «null» и «undefined».
Дело в том, что раз уж собираетесь рассказывать о конструкторах, то очень интересно зачем в JS два объекта, которые по сути «для одного и того же ведь, да?»?

«Забегая вперёд» скажу, что в конце цепочки прототипов объекта находится «null», для этого он и нужен, т.к. объект не может унаследоваться от «undefined»…

Это как раз и является ответом на вопрос «почему instanceof null === object», хотя в последнее время это и решили изменить, как написал Finom выше.

А так же всё таки не перемешивать контекст JS браузера, который в нем содержит огромное число примесей, с контекстом JS «сферическим в вакууме».

JS очень популярный язык, не путайте неофитов, говорите правду сразу!
Спасибо за интересный вопрос и сразу же за ответ который не дали мне высказать самостоятельно(а жаль). =)
Вы вероятно поторопились и написали глупость(поскольку instanceof не может равняться object — он возвращает true/false). Возможно вы имели ввиду typeof(null) — но тут причина в том что это значение берется из таблицы как я уже писал в статье.
Да, я там взял это в кавычки, а именно «почему instanceof null === object».
Это специально, чтобы если Вы прочитаете, было бы «что ответить», уж простите за «проверку» на разницу между typeof и instanceof — было не совсем ясно.

Простите, что не дал высказать самостоятельно :)
И, раз уж «пошла такая пъянка», то null там тоже не всегда, очень зависит от конкретной реализации и того, с чем работаете в данный момент, далеко не все придерживаются стандарта, да и кому вообще какое дело что там в конце цепочки прототипов, на что это может повлиять в реальном боевом коде?

Часто, например, прототипом для объекта «window» в браузере является он же сам, т.к. «здесь разработчики просто решили что контекст будет такой, ну, для удобства» :)
Я указал в перечне Хабов этой статьи Веб-разработка, что подразумевает, что я пишу о JS в контексте браузера(по крайней мере я так думал). По этому я не стал уточнять тонкости других реализаций. Ну а смысла спора по поводу null и undefined и то как я их описал я не вижу. Концептуальных ошибок я кажется не сделал!
Да, это пожалуй в самом деле вообще не важно.
Что же, буду ждать следующей статьи :)
«Родителем любого объекта в JS, так или иначе, будет Object.»
Это просто фигура речи, или вы расскажете об этом в следующих сериях?
расскажу, обязательно расскажу.
«в эту переменную можно ложить данные абсолютного любого типа. „

Что значит “ложить»?
Насколько я понимаю, все значения «ложатся» в кучу, кроме, может быть, констант.
А перменная или свойство объекта связывается с положенным в кучу объектом.

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

Вобщем, я лучше пойду на javascript.ru
Вы знаете я например не очень люблю придираться настолько к словам. Тем более в вашем случае я вообще не понимаю что вам не понравилось.
«А перменная или свойство объекта связывается с положенным в кучу объектом.»
Я не о каких свойствах объекта в указанном вами отрывке не говорил. А если вам интересно, то переменные хранятся в так называемом «объекте переменных» (Variable object, сокращённо VO) – это объект имеющий связь с контекстом исполнения. Он хранит в себе например:
— переменные (var);
— декларации функций (FunctionDeclaration, сокращённо FD);
— и формальные параметры функции,
объявленных в данном контексте.
Мне не понравилось, что в статье, заявленной как "сложно о простом", с учётом работы интерпретатора, вы пишите в прямо противопоолжной форме: в простых терминах, не имеющих отношения к работе интерпретатора.
Ну не все сразу Уважаемый, я так же сказал что это цикл статей. Я кончено мог в одной статье расшифровать все термины стразу, но это была бы книга а не статья. Постепенно я буду раскрывать суть терминов. И про кучи поговорим, и про области видимости и про то чем отличается var a=2 от a=2. Терпение!
Философские по тому, что null означает, что переменной присвоено ничего, а undefined – означает, что в переменную присвоили пустоту. Чем отличается «ничего» от «пустоты» в данном случае – поразмыслите на досуге.


Поразмыслил я тут на досуге, и понял, что как бы новички в JS и программировании не размышляли, они все равно не поймут, почему нужны эти два типа, и что в реальности они представляют. Потому что ноги растут из ЯП со строго типизированными типами данных. undefined обычно означает, что имени этой переменной нет в таблице переменных. В JS это немного не так, потому что var x все же «регистрирует» имя переменной, но не присваивает ей никакого значения. null же пришел из мира указателей, когда переменная ссылалась в никуда, т.е. нельзя получить никакого значения. В JS это снова же искажено и применяется для обозначения не примитивного значения и не ссылки на объект, но переменная при этом должна быть определена и иметь какое-то значение.

Так что ничего и пустота — неверные аналогии.
Sign up to leave a comment.

Articles