Именно так. class в JS сахар над прототипами, появившийся в ES6 чтобы не писать Object.create() и Object.defineProperty() руками.
Go в этом смысле честнее: нет притворяющегося классом синтаксиса. Структура это данные. Методы отдельно. Композиция через встраивание явная. Никто не ожидает поведения "настоящего" ООП и не удивляется, когда его нет.
В JS классы создали иллюзию привычного ООП для людей из Java/C#. Иллюзия работает, пока не полезешь в _proto_ или не попробуешь сделать множественное наследование. Тогда вспоминаешь, что под капотом всё те же прототипы.
Про криворуких кодеров согласен, от них не спасёт никакой язык. Можно и на Rust написать что-то, что будет падать, если очень постараться. Но речь не о защите от злого умысла, речь о том, какой код получается по умолчанию.
Про ?. (optional chaining) справедливое замечание. Действительно, с ES2020 ситуация стала лучше:
const name = user?.profile?.name ?? "Anonymous";
Но тут два нюанса:
?. это костыль поверх проблемы, а не её решение. Вы всё равно должны помнить, где нужен ?., а где нет. В Go нулевое значение это дефолт, а не исключение. Разница в когнитивной нагрузке. ?. появился в 2020. Sentry-ошибки из статьи это реальный опыт 2017-2019 годов. Легаси-код без optional chaining живёт и здравствует.
Но вы правы, в современном JS эта проблема смягчена. Можно было упомянуть ?. как контрпример. Статья фокусируется на различиях в философии языков, а не на современных workaround'ах, но замечание учту, спасибо.
Про package и организацию модулей. Да, я сознательно упростил. Статья для JS-разработчиков, которые только смотрят в сторону Go. Полноценное объяснение go.mod, go.work, рабочих пространств и случаев несовпадения имени пакета и директории это отдельная статья. Здесь ментальная модель "пакет = папка" работает в 95% случаев для входа в язык.
Но согласен, что фраза "видят друг друга полностью" технически неаккуратна. Файлы видит go, а не друг друга. И ваш пример с go run m_v3.go p1.go p2.go vs go run . отличная иллюстрация того, как упрощение может сбить с толку. Исправлю формулировку.
Про := и "новую" согласен на 100%. Там действительно нужно слово "новую", иначе при x, err := …; y, err := … начинающий запутается. Спасибо, поправлю.
Про undefined/null и "удвоение проблемы". Тут я остаюсь при своём. Три состояния "известно / неизвестно / не спрашивали" это нюанс, который появляется в конкретных доменных задачах. Для 80% кода это просто два способа получить TypeError. Про "решил" - вопрос вкуса. Моё мнение: если типичный вопрос на собеседовании "в чём разница между null и undefined" это признак неудачного дизайна, а не решения проблемы.
Про обработку ошибок согласен частично. Для сложных сценариев Go-подход действительно удобнее благодаря явности. Но try/catch тоже не просто так существуют 30+ лет. Оба подхода имеют своё место. Статья намеренно показывает Go в положительном свете. Это материал для тех, кто рассматривает переход.
Именно так.
classв JS сахар над прототипами, появившийся в ES6 чтобы не писатьObject.create()иObject.defineProperty()руками.Go в этом смысле честнее: нет притворяющегося классом синтаксиса. Структура это данные. Методы отдельно. Композиция через встраивание явная. Никто не ожидает поведения "настоящего" ООП и не удивляется, когда его нет.
В JS классы создали иллюзию привычного ООП для людей из Java/C#. Иллюзия работает, пока не полезешь в
_proto_или не попробуешь сделать множественное наследование. Тогда вспоминаешь, что под капотом всё те же прототипы.Про криворуких кодеров согласен, от них не спасёт никакой язык. Можно и на Rust написать что-то, что будет падать, если очень постараться. Но речь не о защите от злого умысла, речь о том, какой код получается по умолчанию.
Про
?.(optional chaining) справедливое замечание. Действительно, с ES2020 ситуация стала лучше:Но тут два нюанса:
?.это костыль поверх проблемы, а не её решение. Вы всё равно должны помнить, где нужен?., а где нет. В Go нулевое значение это дефолт, а не исключение. Разница в когнитивной нагрузке.?.появился в 2020. Sentry-ошибки из статьи это реальный опыт 2017-2019 годов. Легаси-код без optional chaining живёт и здравствует.Но вы правы, в современном JS эта проблема смягчена. Можно было упомянуть
?.как контрпример. Статья фокусируется на различиях в философии языков, а не на современных workaround'ах, но замечание учту, спасибо.Спасибо за развёрнутый разбор.
Про
packageи организацию модулей. Да, я сознательно упростил. Статья для JS-разработчиков, которые только смотрят в сторону Go. Полноценное объяснениеgo.mod,go.work, рабочих пространств и случаев несовпадения имени пакета и директории это отдельная статья. Здесь ментальная модель "пакет = папка" работает в 95% случаев для входа в язык.Но согласен, что фраза "видят друг друга полностью" технически неаккуратна. Файлы видит go, а не друг друга. И ваш пример с
go run m_v3.go p1.go p2.govsgo run .отличная иллюстрация того, как упрощение может сбить с толку. Исправлю формулировку.Про
:=и "новую" согласен на 100%. Там действительно нужно слово "новую", иначе приx, err := …; y, err := …начинающий запутается. Спасибо, поправлю.Про
undefined/nullи "удвоение проблемы". Тут я остаюсь при своём. Три состояния "известно / неизвестно / не спрашивали" это нюанс, который появляется в конкретных доменных задачах. Для 80% кода это просто два способа получитьTypeError. Про "решил" - вопрос вкуса. Моё мнение: если типичный вопрос на собеседовании "в чём разница между null и undefined" это признак неудачного дизайна, а не решения проблемы.Про обработку ошибок согласен частично. Для сложных сценариев Go-подход действительно удобнее благодаря явности. Но
try/catchтоже не просто так существуют 30+ лет. Оба подхода имеют своё место. Статья намеренно показывает Go в положительном свете. Это материал для тех, кто рассматривает переход.