Pull to refresh

Comments 58

Если вы знаете ответ, пишите в комментариях.

В первую очередь потому, что JS был слеплен на коленке в кратчайшие сроки. А потом, естественно, стала мешать обратная совместимость.

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

Вас как явиста не смущает, что ваш прекрасный ява-код со строгой типизацией сначала станет байт-кодом, где типизация всё еще останется, но уже без особого контроля, а затем и вообще будет в рантайме машинным кодом? Нет? Ну а откуда тогда к TS претензии?
Претензий-то в общем к TS нет. Наоборот, это ведь пусть с усилению типизации, и что-то даже типа компилятора. От TS к JS, что дает возможность делать проверки во время этой компиляции-транспиляции.
Здесь скорее попытка разобраться
Общего у JavaScript и Java как у морской свинки и обычных свиней. JavaScript создавался под впечатлением от языков функционального программирования, таких как scheme. Ключевое в нем first-order functions и замыкания. А слово Java и С-подобный синтаксис появились по соображениям маркетинга.
В первую очередь потому, что JS был слеплен на коленке в кратчайшие сроки. А потом, естественно, стала мешать обратная совместимость.

Напомнило ситуацию с Basic. Там тоже было много нелогичного, из-за расширений стандарта, прикрученых изолентой. В детстве мечтал изменить язык, но не было знаний и инструментов. Позже увидел в Python реализоваными те свои представления о «правильном бейсике».
А вообще, мне кажется, если знаешь хотя бы поверхностно несколько языков, все эти странности не удивляют.
Только вот в Java всё же есть рантаймовые проверки типов, а в TS их нет вообще и это может приводить к весёлым багам. Я бы даже сказал не «может», а приводит. TS не кинет исключение, ничего не сообщит, если в рантайме прилетят данные совершенно другого типа, а это случиьтся может вообще без проблем.
Только вот в Java всё же есть рантаймовые проверки типов

Какие? Бросить исключение при касте? Очень полезно.

а в TS их нет вообще

Ознакомьтесь с Typescript type guards. Есть. Только разве что чуть более многословны, так как естественно информации о типе в рантайме нет, и приведение нужно делать по принципу «крякает как утка — значит утка».
Есть генераторы рантайм проверок на основе дефиниций (https://github.com/fabiandev/ts-runtime). swagger/raml/graphql тоже транслируются как в дефиниции так и в рантайм проверки. Большинство более менее зрелых технологий такой инструментарий предоставляют. Не хватает — компилятор typescript доступен, API открыто, можно сваять свой трансформер, это не сложно (https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API). Да, не из коробки. Но имхо, ожидать из коробки рантайм проверки от статичного анализатора — так себе хотелка.
TS не кинет исключение, ничего не сообщит, если в рантайме прилетят данные совершенно другого типа, а это случиьтся может вообще без проблем.
Если грамотно использовать TS и соблюдать согласованной контракта общения с источниками внешних данных, то рантайме проверки не нужны. Более того рантайм проверки вреды и противореччат концепции TypeScript, который не существуют в рантайме by design и это неплохо. Если и делать где-то рантайм проверки, то при поступлении внешних данных источник которых не поддается контролю (JSON.parse).
«В массив можно складывать что угодно, элементы любых типов, все они будут преобразованы в string»

Это не так, с чего бы преобразовывать к string, внезапно?

document.write(typeof numbers[0]);


Выведет number
Это потому что автор подумал, что for… in у него такой же как и в яве. А меж тем «такой же как и в яве» будет только лишь for… of.
Код автора на тему «в массивах одни лишь стринги !!!1!!» надо, разумеется, писать так:
document.write("Type elements in mix: ");
for (key in mix) {
    document.write(typeof mix[key] + " ");
}

И сразу наступят чудеса.

Добро пожаловать в клуб)

Спасибо) Зато еще одно отличие в копилку: for in))
Тогда вопрос. Если вывести сумму таким образом:
var numbers = [1,2,3,4,5];
var sum = numbers[0] + numbers[1];
document.write("<br /> sum numbers = " + sum);

то получим 3.
А если так
var numbers = [1,2,3,4,5];
document.write("<br /> sum numbers = " + numbers[0] + numbers[1]);

то будет 12. Это связано с тем, что операция "+" сначала преобразует numbers[0] в string? И если написать так:
document.write("<br /> sum numbers = " + (numbers[0] + numbers[1]));

тогда будет 3
Читайте выражение так, как его разбирает парсер:
1) Делаем string + number. Итог — string.
2) Делаем string (c №1) + number. Итог — string.
Итого две операции конкатенации со строкой.
sum numbers = " + numbers[0] + numbers[1]
Оператор + работает как конкатенация, если хотя бы один операнд строковый, и как числовое сложение в обратном случае. Ну и вычисляется слева направо
Но ведь в Java сложение работает так же… а вы говорили, что знаете Java…
«В JS, если из функция foo() необходимо вызвать функцию bar(), вы должны определить bar() до foo(). Если сделать наоборот, как в Java — приложениях, то вызов может закончится неудачно в некоторых старых браузерах.»
Нет :) JS сначала проходит по коду и собирает в память все переменные и функции, а потом уже начинает наполнять переменные и вызывать ф-и. Порядок написания не важен. А IE3-5 и прочих динозавров сейчас мало кто поддерживает.

Кстати, почему решили взять ES5, а не последние версии, где и классы и BigInt есть?
по-моему даже в IE5 такого нет. у автора минимум знания JS и максимум фантазии.
Все «недостатки» (а для кого-то фичи — как к этому подходить) удобно и понятно решены в TypeScript. Да, он компилируется в JS, но проверка типов довольно строгая. И засунуть что-то произвольное в массив, объявленный как items!: Array<{ [key: string]: string }> TS не даст.

А про зону видимости переменных/ функций/ методов — это фича. Это может появиться ниже, или при следующем тике, но сейчас этого нет. TS предварительно смотрит весь код, и подхватывает объявления, которые могут быть и несколькими строками ниже, и сверит типы.

В этом плане Java более похожа на C/C++, но это просто правила игры в каждом из ЯП.
Только там 2 аргумента.
Да. И тем не менее, это то же самое, что и Record<string>.
Вот жеж (к вопросу о «программировании на бумажке» из соседней статьи). Я почему-то до последнего был уверен, что один из параметров Record имеет какой-то дефолт.
Ну, как бы хорош не был TS, про «все недостатки» это всё же преувеличение.

Проблемы слабой (я бы сказал даже broken by design) типизации TS не решает и никак решить не может (т. к. является надмножеством JS).
То есть проблемы (или фичи, если угодно) того, что [1] + 2 === «12» или ToBoolean([]) === true никуда не денутся (как и многие другие).
Аналогично со сравнением на равенство. Разделение === на отдельные equality и identity TS не даст, как и возможности нормально сравнивать объекты (массивы).

Точно так же, с отсутствием целочисленных/decimal чисел, перегрузки операторов и многое, многое другое, увы.
Да, согласен. Но любой JS программист знает, что массив тут пройдёт через .toString(). Да и все прочие '==='. Это всё понятно.Но тоже имеет право на жизнь.

Я на Java никогда не писал, но знаю C++. По строгости типизации его сложно переплюнуть, по-моему. И говорить, что нет глубокого сравнения двух объектов «из коробки» — ну, в C++ его нет, и в JS тоже. Для первого — перезагружай оператор сравнения, для второго — подключай lodash.

Nobody's perfect.
По строгости типизации его сложно переплюнуть, по-моему.
Вообще C++ справедливо считается «ярким примером» языка со слабой типизацией. :)

нет глубокого сравнения двух объектов «из коробки» — ну, в C++ его нет, и в JS тоже
Не очень корректное сравнение — C++ низкоуровневый язык с zero-cost abstractions как ключевая концепция.
Сравните лучше с языками примерно того же класса — тем же Python (да и в Java, если я ничего не путаю, это тоже успешно реализовано).
UFO just landed and posted this here
>То есть проблемы (или фичи, если угодно) того, что [1] + 2 === «12» или ToBoolean([]) === true никуда не денутся (как и многие другие).

    let n: number;                                                                                                                                                      
    n = [1] + 1;                                                                                                                                                        
    console.log(n); 


TS2365: Operator '+' cannot be applied to types 'number[]' and '1'.

ЧЯДНТ?

А вообще это проблема не typescript-a (да, я согласен что есть проблемные места подобные указанным), это проблемы тайпингов, так вот — их можно подправить, сделать строже, это не сильно сложно.
ЧЯДНТ?
Всё так, это мой косяк.
TypeScript пропускает сложение чисел и строк, разрешая неявное приведение типов между ними (и это меня слегка раздражает).
Во всех остальных случаях TS ругается, да. Честно говоря, логику такого решения я совсем не понимаю — это и не строгая типизация, и не надмножество JS.

это проблемы тайпингов, так вот — их можно подправить
Я либо не согласен, либо не понял. :) Можете развернуть мысль?
>TypeScript пропускает сложение чисел и строк
Похоже у Вас либо версия несвежая либо в настройках послабления, я на прошлой неделе в своем коде втыкал parseInt что бы обойти ругательства typescript. UPD прочитал пост serf и вспомнил что у меня еще линтер подключен, вполне возможно что он ругался, да.

>Я либо не согласен, либо не понял. :) Можете развернуть мысль?

Все поведение js для typescript компайлера описано в тайпингах функций js, сам typescript чекер достаточно тупенький. За операторы не уверен (точнее почти уверен что нет), а вот вывод типов функций и методов встроенных объектов точно можно править. Я правил для reduce — он на какой то версии криво выводил типы (в моем кейсе по моему вообще не учитывался тип функции-аргумента). Загляните в node_modules/typescript/lib, там сразу видны тайпинги с которыми ts работает.
либо версия несвежая либо в настройках послабления
Нет, это именно штатное поведение. Проверял на tsc версии 3.3.3333 с флагом --strict. (Хотя смутно припоминаю, что оно так работает очень давно.)

Опять же, линтеры это здорово, но слегка отдельная история.

Все поведение js для typescript компайлера описано в тайпингах функций js, сам typescript чекер достаточно тупенький. За операторы не уверен (точнее почти уверен что нет), а вот вывод типов функций и методов встроенных объектов точно можно править.
А, ну это-то я знаю, да. Даже заглядывать никуда особо не надо, IDE (да и тот же VS Code) сами умеют перекидывать на нужный тайпинг.
parseInt нужен для преобразования string -> number
А сложение строки с числом — это преобразование number -> string
То есть проблемы (или фичи, если угодно) того, что [1] + 2 === «12
Подобные случаи думаю могут обработать статические анализаторы кода. Вероятно даже готовое решение как например lgtm.com.
Да это вполне понятно. Речь же не об этом, о а том, что система типов TS покрывает отнюдь не все проблемы (или особенности, которые многие считаются таковыми) типизации JS.
Позволю себе слегка поправить (за что глаз зацепился).

JavaScript — это интерпретируемый, скриптовый язык для написания сценариев.
Современные JS-движки, как правило, используют JIT-компиляцию (т. е. JS-код на лету компилируется сразу в машинные инструкции).
Редкое исключение — V8, он использует компиляцию в байт-код с последующей интерпретацией; но и он использует компилятор для оптимизирующей компиляции горячих участков (это тоже общая практика в JS-движках).

В JS есть тип Object. Если в Java это суперкласс всех классов, то в JS это просто один из типов.
В JS это тоже суперкласс всех классов. Все встроенные и пользовательские классы автоматически наследуются от Object.
Хотя для пользовательских классов это при желании можно обойти.

Когда же дело касается JS и его слабой типизации, то в дело вступает настоящая анархия. В массив можно складывать что угодно, элементы любых типов,
А ещё в массиве могут быть «пропасти»:
let a = new Array(5); // 5 указывает длину; не делайте так!

a.length;  // => 5
a[0];  // undefined 
'1' in a;  // false
a.forEach(value => console.log(value));  // ничего не выведет
Советую подробнее почитать про устройство массивов в JS, там много интересного и неожиданного (спойлер: они просто объекты со свойствами, которые являются валидным строковым представлением целых чисел, и пачкой методов в классе Array).
1. Мне кажется есть смысл сравнивать js с java в области nodejs.
2. Для java программиста может показаться глотком свежего воздуха разработка на js хотя бы из-за наличия шикарных инструментов разработчика и самого процесса разработки. Сравнить хотя бы старт и перестарт проекта на spring и koa например. Я уж молчу про меньшую академичность кода и практически отсутствующий бойлерплейт код.
3. js отнимает у java всё больше пространства, развивается быстрее и занимает всё больше ниш. Вот и в десктор ворвался, размахивая хромиумом.
Автор, почитайте bonsaiden.github.io/JavaScript-Garden
Это очень неплохой гайд про особенности JS, там перечисленны спорные и неочевидные моменты, которые часто вызывают трудности и непонимание.
В целом сравнение интересное, но подошли к нему недостаточно профессионально и местами слишком поверхностно. Кое-где даже с фантазией. Но все равно спасибо.
Интересно было бы послушать мнение минусующих вместо безликих минусов.
Если не понятна разница между const/let и var (а еще есть hoisting) то может лучше не писать про JS а читать про JS?
Странная статья с полезностью, стремящейся к нулю.
Просто автор совершил открытие что в мире существует не только java и делится с нами своими уникальными и незабываемыми впечатлениями. Я его понимаю, совершив открытие обычно хочется поделиться им с другими.
Мб и заминусуют, но, ИМХО, не вижу ничего хорошего ни в Java, ни в Java-программистах.

Если первый в 2019 году выглядит как нереально гипертрофированный… мамонт, который даже начинать изучать просто страшно, да и, по сути своей, бессмысленно.

То вторые, приходя в JS, последний откровенно загаживают.
В JS есть много прикольного и интересного, но бывшие жаба/си-шарп-проггеры ничего этого не хотят — они ведь круутыыые, они ведь не какие-то там js-разрабы, а потому, они хотят кодить на JS аки на своих языках… со всеми типо_типизациями_которые_разумеется_решают_все_проблемы итд.
Это приводит к порождению гор едва читаемого кода, который тупит почти на всех устройствах.

Статическая типизация в принципе не спасает от ошибок.
Горы лабораторных работ студентов на Си и «плюсах» тому яркое подтверждение.

Если жаба такая крутая, то почему джава-программист «смотрит» на JS?
Ведь, «в теории» должно быть ровно наоборот…
можете привести примеры прикольного и интересного?
И как, по вашему — эти приколы облегчают или затрудняют сопровождение программ, написанных другими программистами?

В Си — одна из наиболее слабых систем типов. Rust или Haskell в этом плане более выразительны. (Например, их системы типов позволяют избежать null pointer error).

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

С технологической точки зрения «лучше» конечно же формально верифицированная зависимыми типами программа с понятной человеку спецификацией. Но в реальном мире на получение доказательства корректности «правильного квиксорта» у меня уйдёт пара дней.


Каждая из статической/динамической сильной/слабой типизаций даёт свои профиты и даёт языкам свои ниши.


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


Типы в головах

image

Но чем больше разбираешься с системами типов, тем больше хочется описать, что не всегда возможно.

Когда нужно написать какой-нибудь write once код, делающий что-то мелкое, но интересное со сложными структурами данных — статическая типизация требует то, что можно с полным правом назвать «бойлерплейтом»: да, всё опишешь, но это особо никому не пригодится. Идея, например, написать писать на тайпскрипте скрипт настройки dev-сервера у меня восторга не вызывает даже в теории — доказывать тайпскрипту, что у меня тут типы все как надо сходятся — будет на редкость бессмысленным занятием.

А вот когда пишешь что-то сложное, большое, и поддерживаемое разными людьми — статическая типизация спасает от огромного количества головной боли буквально во всём.
UFO just landed and posted this here

Вот знаете, вроде и обидеть не хочется, но и приятного после прочтения тоже мало чего рождается. Зачем нам эти мысли вслух? Зачем вы начинаете копаться в языке не прочитав ничего по нему? Ведь вы даже азов не выучили. Просто представьте если бы кто-то сравнивал Норвежский язык и Русский — но без словарей, без этимологии итд, просто так. Смотрите — здесь слово похоже, но значит оно совсем другое — как так? Есть спецификация, либо читаете ее и вопросов больше не рождается, либо хотя бы каких-нибудь Илью Кантора, Акселя Раушмайера, Дмитрия Сошникова, Кайла Симпсона, Дугласа Крокфорда… Материалов в нашу JS-эру пруд пруди. Нет, надо взяться, наковырять на авось какой-то несуразицы. Так ладно бы вы это в файлик на рабочем столе сохранили и вернулись к нему со здравыми мыслями когда лень уйдет и появится желание читать мануалы/спеку. Так нет, надо накатать на Хабр, ведь это же бложек куда грех не написать. :(


Вот не хочется бомбить, но прямо читать такое больно.

UFO just landed and posted this here
Такой задачи не было. Была задача поделиться своими самыми первыми впечатлениями от использования JS и рассказать о вещах, которые вызвали у меня как разработчика на Java некоторое неудобство. Возможно, на эти же моменты обратят внимания другие джависты, решившие попробовать JS. Я не сталкиваю лбами JS и Java, даже не было задачи сравнивать. Поэтому реакция сообщества для меня стала неожиданной. Так или иначе имеется гора обратной связи. Спасибо интернету, что дает возможность получать ее в самом честном виде, без купюр, хоть и местами токсичненько
даже не было задачи сравнивать

И всё-таки вы именно сравнивали.
Получается, что вы имеете возможность узнать об ошибке еще до запуска приложения. В JS, в силу отсутствия компилятора, такой проверки нет. И ошибки, допущенные вами в момент написания кода будут обнаружены только после запуска скрипта.

IDE со встроенными инструментами анализа синтаксиса, линтеры… Не — не слышали.
Писать JS-код в блокноте (без всех плюшек IDE) — ну такое…
Возможно, это дело вкуса. А как считаете вы, что лучше слабая или сильная типизация?
Что лучше — шурупы или гвозди? Это дело не вкуса, а задачи.
Java и JavaScript — это не одно и тоже!
Многие работники сферы HR с вами не согласились бы.
Возможно, это дело вкуса. А как считаете вы, что лучше слабая или сильная типизация?
Зависит от проекта. Если проект не одноразовый и сложнее todo app, то TypeScript конечно стоит выбирать изначально и сразу в strict режиме. С ростом проекта и команды преимущества будут ощущаться все сильнее в отличии от JS когда с ростом будут увеличиваться только проблемы.
Но, в JS это нормально, потому что понятия класса, функции, методов класса размыты. Слабая типизация во всем.

до "ECMAScript 2015" в нем нет классов, там наследование основано на прототипах.


функция "Person" является объектом-конструктором, а


new Person("Igor", 26);

создаст объект-экземпляр.
Динамическая природа JS проявится в том, что можно на-ходу добавлять поля/методы к прототипу объекта-конструкора и они становтся доступы у всех объектов-экземпляров.


К "классовом" языке свойства и методы класса динамически менять не получится.

Sign up to leave a comment.

Articles