Pull to refresh

Comments 241

С# приложение разрабатывала команда из 12 программистов в течении двух лет, JavaScript — команда из 3 программистов в течение года

Странно, мы например пытаемся перенести максимум логики на сервер приложений (.net / c#) и минимум делать в браузере (js).
Т.к. был прямо противоположный опыт.
(C# отлавливает ошибки на этапе компиляции, есть продвинутые анализаторы кода, проще с тестированием/покрытием и т.д.)
Покрытие кода тестами для js так и не нашли адекватного.
В том проекте логика тоже была на сервере и писалась на Java, но пользовательский интерфейс был довольно сложным, поэтому на клиенте тоже было чем заняться.
Для тестирования JavaScript могу посоветовать jsTestDriver, Selenium, Mocha или Jasmine, в зависимости от задач. Первый, например, имеет хорошую интеграцию с WebStorm и браузерами, позволяет запусткать юнит-тесты для компонентов интерфейса в один клик. Selenium позволяет писать поведенческие тесты практически любой сложности.
Да, мы знаем про многие способы тестирования, у нас настроен CI в TeamCity для регулярного прогона Selenium тестов, но вот получить покрытие кода, которое тестируется этими Selenium тестами — пока не получилось.
А что писалось раньше, код на C# или Javascript?
Запросто может быть так, что команда C# сталкивалась с тем, что требований толком нет, или они по сто раз меняются, а потом когда все устаканилось и было ясно что нужно, а что можно выкинуть, пришли все такие в белом на коне Javascript разработчики и сделали в 8 раз быстрее, уже имея точное задание и готовый вариант реализации на другом языке?
В javascript можно не только писать unit-тесты (для которых существует куча библиотек), но и покрыть буквально каждую операцию так называемым code coverage (одна из самых популярных библиотек для этого istanbul).
Для отлавливания ошибок на этапе компиляции (для js это этап сборки проекта) используются статические анализаторы кода (типа JSLint, eslint и других) или препроцессоры типа TypeScript (в котором есть типизация).

Но конечно, нужно рассматривать конкретный проект, может быть в вашем случае вы и поступили правильнее перенеся логику на C#.
Как обычно разговор о плюсах javascript плавно перетёк в тему «как бы так спрятать сам javascript, что бы его было не сильно видно программисту».

Ну вот вы говорите, замечательный язык JS, давайте писать на TS. Мы убили потенциальные плюсы нетипизированости, пишем на сильно кастрированом недо-С# да еще иногда ловим ошибки, связаные с особенностями генерации.

Стоп, а где, собсвенно, тут JS? Снова затолкали подальше.

В очередной раз оставлю это здесь:
github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS
В TS замечательно то, что никто тебя не принуждает использовать типы. В принципе, мне они нужны только для перегрузки функций и более внятного описания классов.
Но сам я сейчас пишу на ES6 (вот пример) и не могу нарадоваться, хотя типов данных и enum(особенно) и не хватает.
Просто речь о 2 разных языках JS:
1. Исполняемый язык для браузеров (и др. клиентов).
2. Язык разработки (описание алгоритма программистами).

JS отлично выполняет первую роль — кроссплатформенный, достаточно быстрый для множества задач, открытый стандарт. Конечно на его месте мог быть любой язык, но исторически выжил именно он и пока он справляется. Не будем забывать, что в основном — это скриптовый язык. Т.е. язык, который и должен быть максимально гибким в пределах своих разрешений (которые задаются платформой).
Таким же языком является ассемблер для процессоров.
Однако, как с повышением сложности задач — всегда требуется новый уровень абстракции, автоматизирующий часть задач (проверка типов, защита памяти, классы). Над ассемблером появился C и др., над JavaScript — Coffee и др. Даже над C# есть множество уровней — это визуальное редактирование форм, связей, свойств и т.д.
Нет никаких «двух языков», это именно язык разработки. Впрочем, если вы — не разработчик а броузер, то готов принести вам свои извинения. :))

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

>>Т.е. язык, который и должен быть максимально гибким в пределах своих разрешений (которые задаются платформой).

Ух красиво загнули, прямо как на конференции маркетологов…

>>Таким же языком является ассемблер для процессоров.

Так на ассемблере почти никто не пишет кроме полутора мамонтов. И уж точно я не вспомню статей «ассемблер — это суперязык будущего», «как, вы не любите asm?». Что-то всё больше наоборот.
Так на ассемблере почти никто не пишет кроме полутора мамонтов. И уж точно я не вспомню статей «ассемблер — это суперязык будущего», «как, вы не любите asm?». Что-то всё больше наоборот.


Люди, у которых хватает образования (и/или навыков) пользоваться asm'ом, уже не будут писать такие желтые и холиварные заголовки. Они просто работают. Так что не показатель.

А то периодически видишь на хабре то Excel на JS (о 30-ти строках), то итерацию по live-коллекции в JS кто-то осилил и накатал об этом статью. Смешно ведь.
Показатель. Я не знаю, застали ли вы холивары asm VS C/C++, но поверьте, они были и были страшными. Но там хоть аргумент был «в пиковых случаях компилятор не соптимизирует так, как человет»(оказалось — соптимизирует, но это совсем другая история).

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

>>Смешно ведь.

Это да.
Человек выше пишет о том же самом что и вы, только другими словами. JS — аналог ассемблера, только для браузера. А для разработки он не пригоден, так же само как и ассемблер не пригоден. Только вот на ассемблере *сейчас* никто не пишет, потому что есть инструменты получше, а раньше писали. Сейчас, в 2017 (извините за некропостинг) уже есть неплохие языки, которые транслируются в JS.
Перенесённая на сервер логика ведь тоже может быть написана на js. Одно из преимуществ языка — его распространённость и универсальность — ведь сейчас для написания веб-преложений (сервер + клиент) достаточно знать только js. Считаю это плюсом.
Мне кажется что тут больше влияет разница между динамической и статической типизацией. То что по английски называют «hacking», позволяет получить продукт гораздо быстрее. Ну и квалификация программистов играет огромную роль, опытные .net разработчики, не измученные поддержкой динозавров, будут работать быстрее и т д.
Я вот тоже не понимаю какое это должно быть приложение, чтобы на winforms с каким-нибудь devexpress было бы медленнее нашлепать формочек, чем сделать то же на вебе. Там ведь куча проблем — кросс-браузероность и вообще приколы DOM-а, недостаточно API, недостаточно средств что-нибудь нарисовать/разместить, как следствие — отсутствуют UI библиотеки хоть как-то сопоставимые с winforms.

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

Это все безотносительно совершенно JS и C# — я вот тоже думаю что JS как бы не лучше для UI чем C#. Дело именно в веб vs десктоп.
А сколько у вас опыта работы фронт-энд разработчиком? Просто все вот эти домыслы, вроде «физически нереализуемая» — подразумевают отсутствие опыта вообще.

Поверьте на слово, в плане UI — html\css\js даст фору любому. Если знать что делать =)
Лет 5 из 8 в профессии занимаюсь в основном веб-фронтэндом.

Например, делал грид. Надо было там сделать «фиксированные/frozen» колонки — которые не скроллятся, когда остальные — скроллятся. Эта фича, замечу, из коробки в любом декстопном гриде имеется. В вебе — это большая проблема. Можно сходить сюда: trirand.com/blog/jqgrid/jqgrid.html, выбрать демку «Frozen col...\ Frozen Column», вписать дебаггером в фиксированную первую колонку две строчки текста, и посмотреть как оно разъедется. Это можно победить, и я даже знаю как, но в вебе вот такие проблемы — от входа.

Я вижу какого объема, в какие сроки и с каким качеством делают приложения люди примерно одного уровня на вебе и на десктопе. Веб в разы менее продуктивен для большинства типов приложений: всякие бекенды с табличками и формами, редакторы текстов и картинок, игрушки, IDE, CAD-ы, и т.п., и т.д. — все это в разы проще делается на десктопе. У веба есть ниша, в которой он хорош — собственно различные сайты, с несложными формочками. Все остальное на нем делается с гемором и требует редкие и дорогие кадры.

Это не говорит о том, что плох JS. Плохи html/css/dom, точнее они плохи как основа для более-менее сложных UI.
overflow: auto для скроллящихся, overflow: hidden для не скроллящихся. Вот и всё в основном =)
Ага, пущай обрезается, типа у нас веб — чего вы хотели?

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

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

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

Прошу прощения что глаза в одном месте и ссылку не сразу тыкнул.
Я решал и сильно геммороился, правда нам надо было IE6 поддерживать.
Мы любим. Спасибо.

Когда программирую на js испытываю особенное удовольствие. Вся эта асинхронность.
Ня!
Одни обожают JS за ассихнонность, а другие ненавидят JS за ассинхронность.
есть гораздо более удачные решения, нежели макароны колбэков и различные костыли, призывающих это обойти
Можно пример? Хочется узнать, чем люди пользуются
Люди пользуются promises, features and generators.
бинго!
правда все же futures
а некоторые извращенцы(я в хорошем смысле) — еще и icedCoffeeScript.
Ради пары псевдомонад нет смысла мучать себя кофескриптом, если он не по душе. :) Есть, например, фейсбуковский Регенератор.
Async на сервере и на клиенте.
асинхронность JS зависит от того как движок используется в приложении.
В Node.JS и браузерах движок любят использовать как асинхронный, но ничто не мешает ему работать как полностью синхронный язык.
У меня есть мнение, что JS всё-таки не язык общего назначения. Круг задач на нём можно решать достаточно широкий, но не все решения будут выглядеть хорошо.
Я где-то в середине пути от вторых к первым. Достаточно лишь начать уметь эту асинхронность «готовить».
Я не то чтобы супер профессионал в JS. Тем не менее несколько лет писал и пишу на нем достаточно сложные системы. Паралельно с этим очень много пишу на Python и балуюсь Go.
На мой взгляд, для действительно больших систем со сложно бизнес-логикой JavaScript отвратительный язык.
Сложные системы на js легче писать, чем генерить html (пусть и через всякие библиотеки) на сервере и всю логику хранить там.
Если б можно было я вообще ты только СУБД и браузер оставил, без веб-сервера.
Сложные системы на js легче писать, чем генерить html

Не то чтобы совсем не согласен с этим утверждением, однако не вижу большой разницы где «генерить html» на сервере или на клиенте, равзе что на клиенте можно чуть по гибче, но на сервере безопаснее.

Если б можно было я вообще ты только СУБД и браузер оставил

Если бы можно было, я бы был миллардером и жил на острове.
А что вам мешает оставить браузер и REST-сервисы? Ну и пишите себе на JS после этого что угодно.
Можно. Вот этим написать сервер. Плюс научить postgres общаться через http.
А, кто, простите, будет http-запросы обрабатывать? Только не говорите, что web-сервер. И еще, какие запросы сможет слать браузер к СУБД в вашей схеме? DELETE FROM very_important_data, к примеру, можно? Очевидно, что нет. Значит есть «разрешенные» запросы. И кто же будет это проверять? Ведь логики-то вы на сервере не оставили.
СУБД вполне может поддерживать логику типа управления правами доступа.
Втакой схеме, так скажем, нетривиальная логика будет. Да и авторизоваться надо как-то из полностью открытого кода через прозрачный канал.
А как сейчас авторизуются?
Соглашусь. Похожий опыт. Причём, на мой взгляд, JS был бы как минимум раза в полтора удобнее, если бы у него была «утиная» типизация, как в Python'е и разного рода лиспах.
Готово! В JavaScript есть duck typing.
Ну, я немного не так выразился. Помимо утиности, хотелось бы на 3+"3" получать TypeError, а не "33".
Минусующие, наверное, никогда не передавали по ошибке вместро строки в какую-нибудь функцию объект, который превращался затем в "[object Object]" и совершал долгий путь по коду, прежде чем привести к отложенным, но неприятным последствиям, таким, что даже с неплохим набором тестов далеко не сразу можно понять, в чём дело. А, или вот — случайно загнать строку вместо массива, а потом биться головой о стену, что где-то дальше по коду somevar[0] = ...; не даёт никакого эффекта.
Это сильная типизация, а не утиная.
Да, верно. Я же говорю, я не так выразился. «Утиность» является стандартной характеристикой Python'кой системы типов, но не определяет строгость проверки типов. С другой стороны, если вы скажете, что в Python'е сильная типизация, вас очень многие поймут неправильно, т.к. многие путают сильную типизацию со статической.
То, о чем вы говорите называется type coercion.
Если быть конкретнее, то, что мне мешает жить в JS, называется implicit type conversion (coercion, typecasting, как угодно). А так выражение int(x) в py — тоже coercion, только explicit.
Я согласен, что это плохое решение. Но то же неявное конвертирование используется, например, в условии if.
С другой стороны, если вы скажете, что в Python'е сильная типизация, вас очень многие поймут неправильно, т.к. многие путают сильную типизацию со статической.

Так надо развеивать эти заблуждения, нет?
По моему чаще используют термин «строгая»
Строгая вообще не допускает неявного приведения типов, сильная допускает некоторые типа int к long int.
Хотите вредный совет?

delete Object.prototype.toString;
delete Object.prototype.valueOf;
delete Array.prototype.toString;
...

И будет вам счастье с TypeError.
Само собой, надеюсь, что никто это вместе с чужим кодом использовать не будет.
UFO just landed and posted this here
Что доказывают ваши ссылки? Никто не говорит что на JS нельзя написать больших и сложных приложений. Моё утверждение что делать это на них сложнее чем на многих других языках.
UFO just landed and posted this here
>Скажем, вы поделили на нуль, большинство языков выбросит ошибку и завершит работу, а JavaScript покажет знакомый нам Not a Number
Это в какой реализации JavaScript? Всегда было Infinity.
По спецификации Infinity имеет тип Number.
Поправил. Спасибо за внимательность.
UFO just landed and posted this here
Может автор делил нуль на нуль? Тогда получится действительно NaN.
Ну, или Inf на нуль. Или NaN ) В любом случае, к JS это имеет довольно опосредованное отношение.
О, я бы просто обожал JS, если бы не «коллбеки, коллбеки, коллбеки, коллбеки, коллбеки, коллбеки». На первых порах прикольно, а дальше становится всё более и более неприятно работать с этим языком.
В ES6 добавили генераторы, которые решают вашу проблема, и еще дозволяют централизированно обрабатывать ошибки. Правда, если вы пишете для браузеров, ждать придется еще долго.
откройте для себя async, коллбеки нынче меньшая из проблем js.
Q уже не модно, сейчас в тренде Bluebird. Но AmdY скорее всего имел ввиду что async решает проблему каши из коллбеков
С async перестаёшь ненавидеть коллбеки и начинаешь их любить.
github.com/caolan/async
или deferred / github.com/kriskowal/q

Только немного настораживает, что async не обновляется уже несколько месяцев.

Для меня проблемой было то, что с первого взгляда неясно, является ли функция асинхронной или нет. Возвращает ли она значение в коллбеке? Или в return? Или она в return возвращает deferred-объект?
А что по-вашему там надо менять, учитывая что async просто работает? Изменения ради изменений никому не нужны…
А программы на C# и JavaScript параллельно разрабатывались? Какая из групп разработки выясняла неточности в требованиях и т.п.?
Команда C# начала на год раньше. В этом плане им, конечно, было сложнее, но конце мы их немного перегоняли.
Тогда совсем не удивительно. что результаты такие.
В группе из 12 программистов половина времени уйдёт только на совещания, пока все между собой договорятся :)
Все эти слова применимы, например, к Perl.

Но вообще, JS крайне любопытен.
Это какая-то слишком холиварная статья. Ничего нового про JavaScript я не узнал, доводы меня не убедили. Думаю для бэкендщиков это не доводы.
Вот я сейчас рискую получить звание «Капитан Очевидность», но все-таки скажу, что для каждой задачи есть свой инструмент (в данном случае язык программирования).
Мне кажется что автор действительно достиг больших высот в JavaScript и познал дао его инфраструктуры (я без сарказма). За 10 лет это вполне достижимо. Поэтому и любит его.

Но у большинства разработчиков к этому языку все таки больше претензий.
Раз уж затронул специфику JS, то где хоть слово про область видимости переменных, про то что null в JS это объект? Ничего про эти и другие специфичные для JavaScript вещи, которые стоит узнать прежде чем начать на нем писать.
Написано же — «мы считаем, что все, кто работают над кодом — профессионалы и доверяем им».
null не объект.
А про typeof null == 'object' можно почитать в стандарте, если на пальцах то тут habrahabr.ru/post/159313/
Я знаком со статьей, как раз про эту «специфику» языка и говорил
Хочу заметить, что в тексте ни слова про замыкания. Не уж то это случайность?
Считал замыкания интуитивно понятным принципом. К тому же они есть во многих популярных языках (PHP, C#).
Субъективно, они там ещё не начали массово использоваться, а для JS — єто норма давно.
Оооочень субъективно. В C# замыкания мейнстрим с 3-ей версии, т.е. с 2007-го года, а появились они там во второй версии, т.е. с 2005-го.
А в джаваскрипте с какого?
А это не важно, важно что они сейчас уже массово используются.
Это как это не начали? Где лямбды — там и замыкания. Лямбды в C# используются в хвост и в гриву. Далеко не все на нем пишут как на джаве.
Сложно представить язык, где функции — обьекты первого класса, и нет поддержки замыканий. Как правило, если есть поддержка первых, вторые идут «из коробки».
Скажем, вы поделили на нуль, большинство языков выбросит ошибку и завершит работу

Нет если это деление чисел с плавающей точкой. На этот счёт есть IEEE 754.
Выход из строя одного элемента не выводит из строя всю систему. Конечно, плохо показывать пользователю NaN или undefined, но это гораздо лучше, чем аварийно завершиться, как все мы много раз видели у многих нативных прогамм под Windows (и не только).

Вывод из строя одного элемента обязан обрушить всю систему, если явно не указано иначе (т.е. если исключение не поймано). Иначе мы получаем неопределённое поведение во всей программе и потенциально портим пользовательские данные. Выпасть с ошибкой — лучше. Поэтому нужно явно проверить результат на NaN. Если вся программа — 3 строчки, то это не так страшно, но сейчас javascript используется далеко не только для «динамического HTML».

JS — не такой плохой язык, но именно этот момент — скорее слабая сторона.

Если говорить об Объектно Ориентированном Программировании

то у нас как минимум есть замыкания, которые, как известно, poor man's объекты. А объекты — poor man's замыкания. Если ещё к ним прилагаются прототипы — тем лучше.

P.S.: Javascript — не единственный язык с динамическими типами и на Javascript/Java/C# выбор языков не заканчивается. И чаще строгая типизация (в том числе строгая динамическая, пример — тот же Python) лучше, чем слабая как в Javascript: явное приведение типов намного проще отлаживать. Поэтому в реальности программы на javascript нечасто бывают длинными.

Есть возможность включить статическую типизацию (тот же asm.js), но строгую — нет. Иногда проще было бы с ней.
Вывод из строя одного элемента обязан обрушить всю систему

Даже если это сервер?
Необработанное исключение? Обязан особенно если это сервер. Он же перезапустится (и его работу на время перезапуска возьмут на себя другие узлы если нужна безотказность). Это намного лучше, чем написать чушь в базу. Тем более учитывая, что ошибка может быть спровоцированна неожиданными вещами на входе (в результате целенаправленной атаки).
UFO just landed and posted this here
Почти так, но бектрейсом не стоит плевать в пользователя. Это слегка небезопасно. В лог — пожалуйста.
UFO just landed and posted this here
UFO just landed and posted this here
Скажем, вы поделили на нуль, большинство языков выбросит ошибку и завершит работу, а JavaScript покажет знакомый нам Not a Number и, возможно, даже выведет его в интерфейс пользователю в виде строки, если так задумана логика программы. Хорошо это или плохо? Я бы сказал, это позволяет создавать программы с высочайшим уровнем стабильности.

В корне неверное утверждение. Если произошла ошибка, рантайм должен как можно раньше сообщить об этом. Если же ошибки тихо игнорируются, значения конвертирутся и передаются дальше, то проблема может быть не видна ещё час, день, месяц. А потом вдруг вылезити в совершенно неожиданном месте и поломать гораздо больше. Или даже хуже — продолжать работать, но выдавать неверные данные, подрывая работу всей организации.
Я согласен что ратайм ошибки можно игнорировать. Но! Только осмысленно, и на уровне определенного блока кода. Блок может быть и маленьким и большим, не важно. И этот блок должен быть завернут в try catch, чтобы искверканные рантайм ошибкой данные никтогда не покинули этот блок.
Да, это популярное мнение. Не хочу вступать в холивар, просто небольшой контраргумент: то что вы написали хорошо в релизе для разработчиков и тестировшиков, в продакшн-коде часто лучше всё-таки умолчать об ошибке. Пусть вы её быстро увидите, а так же её увидит приличная доля ваших пользователей, это ударит по репутации сервиса и менеджменту будет не важно какими благими намерениями вы руководствовались. При графике релизов раз в неделю или две, что сейчас всё более популярно, сложно гарантировать абсолютно стабильный код. Однако лучше если в службу поддержки придёт 2 обращения, чем 200. В любом случае ошибка будет исправлена, если нет — значит она не так критична. Этот подход хорошо подходит к разработке интерфейсов, если вы работаете с финансами или сложной математикой — возможно ваш подход более оправдан, хотя в JavaScript для таких случаев тоже можно вставить дополнительные проверки.
в продакшн-коде часто лучше всё-таки умолчать об ошибке.

После чего пользователь будет задавать вопросы «где мои данные» (реальный пример из опыта, когда js-ошибка проглатывалась, и табличка в браузере оставалась пустой)
Если есть ошибка — пользователь будет недоволен в любом случае. И, как я понимаю, обращение пользователя с вопросом про данные помогло вам найти и устранить ошибку не хуже, тем если бы ему выводилось что-то вроде «General failure».
Вы поняли неправильно. Отсутствие данных в гриде — возможное поведение системы, поэтому один пользователь, который данных не видит, считает, что система работает, и звонит другому пользователю, который должен данные вводить, с вопросом «какого хрена ничего не сделано». Тот в холодном поту бросается к экрану и — поскольку он считает, что система работает нормально — в панике звонит начальству со словами «все данные пропали». Дальше это эскалируется и долетает до разработчиков как критический баг «все пропало».

А если бы там было сообщение об ошибке, (а) не было бы паники и (б) разработчики бы сразу знали, где искать ошибку, а не разбирались бы в состоянии БД и логике выборки данных.
При подходе который я предлагаю программа в случае ошибки выдаст что то типа «Ошибка при расчете стоимости заказа», но не упадет целиком. Так как вы предлагаете, программа выдаст какую нибудь жуть типа «На вашем счету NaN рублей, вы сделали undefined заказов, ваш долг составляет -1.51e-28 рублей». И еще и сохранит это на сервере.
Если есть время — конечно лучше создать отдельные сообщения для ошибок, я с этим не спорю, и в JavaScript это нисколько не сложнее. Скажем в C++ вы будете использовать try catch, а в JavaScript проверете все выводимые значения на NaN и Infinity при рендеринге.
UFO just landed and posted this here
JavaScript хороший язык, в основном благодаря HOF и замыканиям, но в вашей статье слишком много слов в превосходной степени.

Свойства делают публичными потому, что сделать их приватными не так уж и просто. Нужно объявлять все методы на инстансе, а не на прототипе, что влияет на прозводительность и потребление памяти. Кроме того, нету промежуточного уровня — protected, который много используют в других языках, и поэтому если вы хотите, чтобы ваш «класс» наследовался, приходится использовать properties.

Благодаря системе типов можно избежать целого класса runtime ошибок, правда, за счет более сложного процесса разработки. Например, если ваша программа на Haskell, который известен своей системой типов, скомпилировалась, с большой вероятностью она будет работать как ожидается.

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

К синтаксису у меня вообще большие претензии, но coffeescript решает почти все.

Вот еще парочка вещей, которые мешают мне любить JavaScript: почему тип null'а это object; почему arguments это как массив, но не массив; почему так сложна логика использования this?
Обилие array-like штук (arguments, NodeList) объясняется очень просто: в первой версии языка не было массивов. Из первой же версии тянется баг с typeof null.
А вас не пугает что одинаковые буквы произносятся по разному в различных языках?
Вы о слове коллбек? Да, вы правы, извините.
Что вы, нет, я про:
Синтаксис языка во многом похож на C, что вводит многох людей в заблуждение. JavaScript сильно отличается от того, к чему вы привыкли, если писать на нем как на C, будете наступать на разнообразные грабли типа variables hoisting или обработки ошибок в асинхронных коллбеках.
UFO just landed and posted this here
Очень красивое решение с WeakMap, я в восторге. У вашего же метода будут проблемы с памятью — данные не удалятся с массивов при сборке мусора.
Кстати, Nicholas описал практически такое же решение, но с одним массивом в разделе «Towards truly private members».
UFO just landed and posted this here
В ES6 для создания приватных свойств есть символы. В свежем хроме они уже доступны. Они не полностью приватны (есть Object.getOwnPropertySymbols), но, пожалуй, это идеологически более правильное решение. Касательно вашего комментария — вместо использования массивов проще эмулировать WeakMap'ы храня данные на ключе — нет необходимости чистить и не течет (пока существует коллекция).
UFO just landed and posted this here
Именно эмуляцию WeakMap с хранение данных на ключе. В примитивном виде будет что-то в стиле

if(!window.WeakMap){
  var id  = 0
    , has = ({}).hasOwnProperty
    , WEAKDATA = Math.random().toString(36).slice(2);
  window.WeakMap = function(){
    if(!(this instanceof WeakMap))throw TypeError();
    this.clear();
  }
  WeakMap.prototype.clear = function(){
    this._id = id++;
  }
  WeakMap.prototype['delete'] = function(key){
    return this.has(key) && delete key[WEAKDATA][this._id];
  }
  WeakMap.prototype.has = function(key){
    return (key === Object(key)) && has.call(key, WEAKDATA) && has.call(key[WEAKDATA], this._id);
  }
  WeakMap.prototype.get = function(key){
    return (key === Object(key)) && has.call(key, WEAKDATA) ? key[WEAKDATA][this._id] : undefined;
  }
  WeakMap.prototype.set = function(key, value){
    if((key !== Object(key)))throw TypeError();
    (has.call(key, WEAKDATA) ? key : Object.defineProperty(key, WEAKDATA, {value: {}}))[WEAKDATA][this._id] = value;
    return this;
  }
}

Честную и полностью не текущую эмуляцию WeakMap на ES5 создать нельзя. Минус данной — после удаления коллекции или её очистки через .clear, ключ и значение останутся связанными. Но для данного случая — хранения приватных полей — никаких минусов, утечек и необходимости чистить.
Символы эмулировать еще проще, но из-за того, как и за счет чего это делается, я бы их эмуляцией пользоваться не стал.
Порой вы не можете быть уверены даже в том, какие методы имеет тот или иной объект.

Вы можете вывести полное содержание практически любого объекта в консоль, со всеми его методами, значениями полей, цепочкой прототипов и т.д. Хотя это, конечно, относится не к JS как таковому, а к инструментам разработчика, которые, однако, де-факто стандарт при разработке на этом языке.
в общем идеализированно, но идейно я с вами.
Подобные восхваления можно написать практически про любой язык. Вот, уже упомянутый C#: ООП вместе с лямбда-функциями, dynamic, async / await и т.д. и т.п. Тут уж кто к чему привык)
Статья похожа на рассказ какого-то сетевого маркетолога.

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

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

Ну и выражения в одном тексте вроде
JavaScript обладает очень низким порогом входа.
и
Это требует высокого уровня концентрации и хорошего понимания архитектуры.
убедительно показывают, что количество аргументов здесь решает больше, чем их сочетаемость и актуальность.
Скажем, вы поделили на нуль, большинство языков выбросит ошибку и завершит работу, а JavaScript покажет знакомый нам Not a Number

Скорее большинство компилируемых языков выкинет ошибку (и то, только в случае целочисленных типов), а интерпретируемые и выкидывают либо INF (если деление на ноль) или NaN (в случае того-же sqrt(-1)), что, так-же, выкинут компилируемые, в случае представлении числа по IEEE 754.
Кому-то нравится порядок в типах c#, кто-то обожает гибкость, присущую javascript. И у тех, и у других — получается хорошо решать стоящие перед ними задачи (при условии их профессионализма, виртуозного владения основами и тонкостями языка).

Но самое жуткое, что мне пришлось наблюдать в одном из прошлых проектов — это как заядлые (в хорошем смысле слова) шарписты воссоздавали типизацию, классы, публичные, приватные и защищенные методы в javascript, чтобы подчинить этот язык более привычной им логике. Они плодили оъекты «классов» через new ..() и, не зная, как их связывать, создавали древовидные структуры, чтобы содержать эти объекты. Поддержка такой системы оборачивалась совершенно непредсказуемыми косяками и была доступна не то, что «дот-нетчикам с элементарными знаниями javascript», и даже не сугубо джаваскриптерам, а преимущественно самим создателям. В общем, удручающее воспоминание.

По возможности удерживайтесь от такой крайности. Дружите с языками по отдельности.

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

В JavaScript нет защиты от дурака. Мы считаем, что все, кто работают над кодом — профессионалы и доверяем им.

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

Статья просто дышит юношеским максимализмом и духом rockstar programming. Я тоже думал нечто подобное на 2 курсе и хотел создать свой собственный язык с похожими возможностями. Ничего, после работы над более-менее серьезным проектом, желание «гибко патчить чужой код» сразу же отпадает, равно как и убежденность в профессионализме окружающих.
Если вы знакомы с C++ или Java, то можете начать вполне сносно программировать на нём уже через 15 минут после знакомства.
Ага. Только что то не хочется.
UFO just landed and posted this here
Да. Это же очевидно. Плюс в статье это оговаривается.
UFO just landed and posted this here
'3' + 2 === '32';

Я это имел ввиду.
UFO just landed and posted this here
Добавлю:
— почему в i попадает индекс, когда для такого написания во многих (как минимум) других языках характерна «for each» конструкция, при которой в i должно попадать значение массива
Да нет, тут проблема не в понимании матчасти, тут проблема в «схожести» с другими языками визуально с совершенно иным смыслом:
— там, где в других языках идёт foreach по элементам массива
— в JS идёт foreach по ключам ассоциативного массива свойств объекта.
Такое поведение рождает непонятки, вопросы и претензии к языку.

Так что, если при обычном программировании можно (пытаться) опираться на стек языков, при работе с JS придётся или тратить дополнительное время на внимательное и вдумчивое написание (чтобы не налететь на такие вещи), либо придётся отказаться от других языков… Иная альтернатива — писать говнокод.
UFO just landed and posted this here
Я может быть сейчас вам тайну открою, но цикл for-in в js не предназначен для обхода массива. Он не гарантирует вам очередность прохода. Он предназначен для обхода свойств объекта. В 6-ой версии для обхода массива предназначается for-of.
UFO just landed and posted this here
Где такие конструкции используются?
UFO just landed and posted this here
В лоб, конечно, не стоит, но и говнокодить тоже не надо. Потому что получается не хэш, а хрен знает что с линейным временем доступа и с повышенным расходом памяти. Лучше просто добавлять префикс какой-нибудь, чтобы исключить конфликт имен: {x_first: 'foo', x_second: 'bar'}. И всё будет хорошо. P.S. Это, конечно, не решает проблемы порядка обхода.
UFO just landed and posted this here
i — это ключ. И переменная имеет тип String.
В JS массив это объект. Поэтому его можно итерировать.
UFO just landed and posted this here
Да нет же. Здесь это индекс массива.

for(var i = 0; i < arr.length; i++){}

А здесь это ключ хеша.

for(var i in arr){}

Это же очевидно.
UFO just landed and posted this here
Даже если

var arr = [1,2,3];

В

for(var i in arr){}

Все равно строка будет. Проверьте.

var arr = [1,2,3];
for(var i in arr){
  console.log(typeof i);
}

Тут дело в капитальном непонимании матчасти.

for (var index in arr) {}
эквивалентно
for (var prop in obj) {}


А бегать по массиву таким образом не советуют, потому что можно зацепить length.
Для таких целей есть Array.prototype.forEach.
UFO just landed and posted this here
Ох… В своё время забил на этот брейнфак и начал писать my_array.map(...) или my_array.forEach(...)
…или my_array.every(), или my_array.filter(), или my_array.reduce(), или my_array.reduceRight(), или my_array.reduce(), или my_array.some()

И это правильно. Потому что библиотечные функции (вкомпилированные в движок) работают, естественно, быстрее, чем цикл, запрограммированный на джаваскрипте.
Если бы они были нативными.
На данный момент реализация подобных функций в V8 выглядят как «цикл, запрограммированный на джаваскрипте», при этом никак не оптимизированный. А это значит, что callback-и этих методов создаются и выполняются точно так же, как обычные функции, которых вообще нет в обычном цикле.

Так что я бы пока не стал отказываться от for и while в критичных местах.
гибкого и кроссплатформенного программного обеспечения с поразительной скоростью.

Да уж. Очень быстрый и очень кросплатформенный.

Я вообще не являюсь ярым ненавистником js. Когда начал разработку веб-приложений именно js мне понравился больше всего, но не замечать очевидных недостатков глупо. Они, конечно, как и преимущества, есть во всех языках, только статья написана в духе легкого фанатизма (я на этом акцентирую больше внимания, а не на том, плох или хорош js).
И да, как по мне, так вешать на него что-то кроме обработки событий элементов интерфейса не стоит.
Когда человек награждает JavaScript такими эпитетами как высочайщий, стабильный, идеальный и мультипарадигменный, хочется спросить пытался ли он в своей недолгой карьере решать задачи сложнее чем «в 30 строк» и знает ли он какой-нибудь другой язык, привести примеры своей работы.
Делаю проект на JavaScript-фреймворках на клиенте и сервере и удивляюсь тому как же он быстро и изящно получается. К тому же, в команде всего двое разработчиков на парт-тайме.
Ждём статью про примеры «быстроту и изящности» после того, как когда у вас на проекте будет хотя бы человек 50-100.
Хорошая идея, это будет честно.
> Часто, классы создавать совсем не обязательно, это излишний уровень абстракции, и прототипное наследование, или даже создание объектов на лету, прекрасно справляется с такими задачами.

И чем нам тут помогает прототипное наследование в реализации JS? Какая разница, объявлять класс или функцию-конструктор, которая делат всё то же самое, что класс, но при этом не класс?
Можно было бы про Бритву Оккама вспомнить, если бы в JS можно было использовать в качестве прототипа произвольный объект. Но это не так.
Почему же не так? Вы можете использовать любой объект как прототип.
Без функции-конструктора — нет. А она в данном случае и есть ненужная сущность. Я имел в виду это, может быть неудачно выразился.
Можно, например, так:

var daddy = {foo: 'bar'}
var son = Object.create(daddy)
console.log(son.foo)

С одной стороны вы правы, мы используем Object, но зато нам не приходится создавать конструкторов — лишних сущностей — самим.
Да, согласен, всё время забываю про фичи, которые не поддерживаются в IE8, т.к. пока всё равно не получается ими пользоваться.
Был бы javascript удобным языком, народ бы Typescript CoffieScript не городил.
Тут не в этом дело, все программисты начинают свое обучение с каких-то конкретных языков, привыкают к ним, любят их. Со временем, переходя на другие языки, они вздыхают и матерятся. Но не все. Некоторые решают перенести свои любимые фичи с собой в новый язык, таким образом и появляются всякие препроцессоры или фреймворки реализующие синтаксический сахар или эмулирующие наследование или типизацию. В конце концов, в других языках тоже полно таких надстроек.
ES6 будет прекрасным языком, это уже видно по спецификациям.
Чем больше вокруг статей, превозносящих до небес какие-то достоинства Javascript, тем больше я его ненавижу.
Хорошие языки в навязчивой рекламе банальных вещей (но и это еще не все! вы получаете коробочку) не нуждаются.
Писал тут недавно сложное приложение с html5 воркерами. Течет потихоньку :-( Хотел в хроме воспользоваться функцией Record Heap Allocations, но он показывает только 100500 анонимных функций и где, собственно, искать утечку нифига не понятно. Возможно я просто не умею его готовить. А так да, язык шикарный.
Ну дык не делайте эти функции анонимными.

Всюду, где можно создать+передать «function(…){…}» в качестве коллбэка (функции обратного вызова), можно и «function имяФункции(…){…}» создать+передать с не меньшим успехом.
Громоздко слишком. Плюс думать нужно, как красиво функцию назвать. Все изящество языка теряется. Какие-то ключевые функции, которые вызываются из многих мест, действительно именуются. Но большинство так и остаются безымянными. Кроме того, помимо моего кода есть код библиотек, в которых тоже далеко не все поименовано.
Чем победили callback hell?
Честно, не знаю что это такое.
Значит вы еще недостаточно любите js, или не так долго
Все дело в том что JS — это даже не гадкий утенок программирования, а настоящий Франкенштейн. Посудите сами:
  • Слепили за 10 дней.
  • Его имя — это кличка от временных хозяев, настоящее его имя ECMAScript — одно из самых уродливых имен для языка программирования в мире (я посмотрел список самых распространненных, рядом с этим названием стоят разве что языки для сред настолько специализированных, что им даже ласковое имя не дают), даже те, для кого js — родной язык, не используют это название.
  • Кочевал от одних неравдивых родителей к другим Netscape, MS, как-то попал под влияние Opera. Пока его не вытащил Firefox, который вроде бы начал приводить все в порядок, но тут v8, html5, WebAPI… как понеслось!
  • Долго не мог найти себе работу, некоторое время помогал CSS.
  • Как-то даже подрабатывал на новый год,… а потом вообще потерялся, искал себя, шлялся по Интернет-свалкам. Пока не появились ajax и jQ.
  • А тут началось! На JS свалилась популярность. Начались случайный связи...
  • Новыми фишками обрастал в случайном порядке, как навесным оборудованием, кто во что горазд: encodeURIСomponent, но JSON.parse().
  • Основной язык веб разработки, который до сих пор не обладает объектом для создания URL? А парсинг HTML — только через мои гнилой труп браузерный DOM!
  • Своей полноценной семьей (стандартной библиотекой) так и не обзавелся. Возьмите тот же ruby. Вместо коротких имен методов мы зачастую получаем кашу и полный бред: у массива отстутствует метод has, который бы возвращал булеву. Я очень редко ищу индексы, чаще ограничиваясь наличием элемента, но я как обезьяна переписываю "[1].indexOf(1)>0". Таких методов тьма.
  • Ключевое слово const ввести так и не смогли, но реализовали константы стандартными же средствами: Object.defineProperty(window,'CONST',{value:1,immutable:true}).
  • Всей инфраструктурой занимаются ТРИ лагеря: большая четверка (браузеров), nodejs и несколько различных сообществ (CommonJS, ECMAScrit, W3C) единого видения будущего JS — нет.
  • У языка отсутствуют классические циклы развития. Пример: isNaN сломан(попробуйте:isNaN('foo')) и никто этого не уже починит! Зато в шестой версии появится метод Object.is, который, внимание, проверяет является ли объект самим собой или полностью эквивалентен ему! Что? А как же '==='? Разработчики стандарта считают, что оператор работает не корректно (я хочу выделить это жирным красным капсом, чтобы у всех вытекли глаза — дали стечь мозгу). для некоторых значений выдавая true. Теперь 0 и -0 не одно и тоже. Но не потому что это отрицательный ноль: Object.is(1/0-0, 1/0+0) будет true, почему? Потому что это результат вычислений. НО!!! запомните раз и навсегда Object.is(-0-0,-0) снова true. Но ведь минус на минус дает плюс, нет просто -0 это -0!
  • Приведение типов, это адский ад, даже не хотел трогать, приведение используется для конвертации в строку или число, но и c этим js справляется не так как ожидается. Что получим в результате 'Infinity'-0! Правильно, угдали! Или не угадали? Или все-таки угадали? Почему не решить это средствами языка?
  • Язык объектно-ориентритованный, но встречаются вот такие функции-монстры encodeURIСomponent, почему нельзя перенести это в объект URI?
  • Еще раз ООП. У объектов есть свойство prototype — это скелет, а теперь есть еще и __proto__ это… соседний скелет, он появился для удобства.


Я люблю JS, но не за его божественную красоту, уж точно! И я боюсь того что в ECMAScript называют Harmony, потому что гармонией здесь еще не пахнет, а порядок за ними наводить ведь придется, рано или поздно.
но я как обезьяна переписываю "[1].indexOf(1)>0"

>= 0, если на то пошло.

Еще добавлю КУЧУ приятных «паттернов» вроде
for(k in a){ if (a.hasOwnProperty(k)){ // прелесть какая

}}

или
(function(){
}($)); // лисп отдыхает

, а также callback hell и отсутствие внятной библиотеки ДАЖЕ для работы со строками.

В языке есть много приятных начинаний, но он страшен, как вся моя жизнь.
.indexOf() это проход по массиву и сравнение с каждым элементом, то есть медленный поиск и использование его для проверки наличия элемента в большом массиве неправильно.
Есть хорошие библиотеки с открытым исходным кодом: для обработки массивов уместно использовать Underscore или Lo-Dash, для работы с датами — Moment.

Они не являются частью самогó языка? — ну и ладно; зато авторы библиотек этих более свободны от оков стандартизации и вечной поддержки обратной совместимости.
Библиотеки хорошие, но что касается .indexOf(), то Underscore нас не спасет. Нет адекватной проверки вхождения элемента в массив, нет и в библиотеках, ибо они пользуют нативные вызовы, а в браузерах тоже нет. Если возникла такая необходимость и массив большой, тут потребуется добротный костыль или переход на хэш-объект для проверки.
Если известно, что массив заблаговременно отсортирован, то тогда, разумеется, можно ускорить поиск (избавиться от последовательного перебора элементов).

Для этого достаточно в Underscore использовать _(array).indexOf(value, true), где true значение параметра isSorted.

Тогда работает двоичный поиск, и его реализация в Underscore вполне адекватна.
Так я именно об этом и пишу. Нужен дополнительный код (библиотека), что бы проверить вхождение элемента в массив. Underscore не решает все за нас, необходимо организовать сортировку, то есть еще плюс телодвижения.
Так давайте тогда просто решим, чем, все-таки, занимается ECMAScript как организация? Синтаксисом и идеологией языка — это один вопрос, тогда руки прочь от `String.prototype.startsWith` и т.п., если стандартной библиотекой, то где все остальное?
Строго говоря, объекти в js не имеют свойства prototype. Есть внутренне свойство [[Prototype]], недоступное в клиентском коде. Так как иногда все же надо иметь доступ к прототипу объекта, для удобства ввели свойство __proto__, которое как раз указывает на объект-прототип. Более того, в es5 есть стандартный метод Object.getPrototypeOf(obj) для этих целей. Собственно a.__proto__ === Object.getPrototypeOf(a).
Эк вас накрыло…
> Ключевое слово const ввести так и не смогли
Доступно уже почти везде.
> isNaN сломан(попробуйте:isNaN('foo')) и никто этого не уже починит
А что, +'foo' не NaN? На ваш конкретный случай — Number.isNaN.
> У объектов есть свойство prototype — это скелет, а теперь есть еще и __proto__ это… соседний скелет, он появился для удобства.
То, что prototype у конструкторов, а __proto__ у инстансов вас не смущает?
  1. Ок, посмотрел не там.
  2. А теперь сравните поведение is и isNaN, они должны работать по схожему алгоритму, но это не так.
  3. То что prototype у конструкторов, а __proto__ у инстансов меня как раз и смущает, они идеологически разные. Подмена __proto__ у инстанса дает изменение поведения, а подмена constructor — нет. При этом instanceof вернет true даже когда объект не тот за кого себя выдает. Таким образом объект навсегда останется объектом, даже, когда его поведение не является поведением объекта, но узнать об этом мы сможем только реализовав такую проверку самостоятельно, так мы возвращаемся к стандартной библиотеке и остальным вытекающим отсюда проблемам.
> А теперь сравните поведение is и isNaN, они должны работать по схожему алгоритму, но это не так.
По этой вашей логике Array.isArray(foo) должен работать как Object.is(foo, Array)? Как по мне — всё логично.

Как и поведение instanceof. Прототип инстанса равен prototype конструктора? Вернуть true. Рекурсивно повторить, вернуть false когда прототип равен null. Что может быть проще?
Не устраивает? Проверяйте через isPrototypeOf.
Свойство constructor? А зачем оно? Инстансы можно создавать и без конструкторов.

Лучше скажите, что под вы подразумевали под immutable:true в defineProperty :)
isArray — еще один пример навесного оборудования. Для чего нужен этот метод? Почему instanceof не может выполнить эту задачу? Но относительно is — появление любых методов, должно быть обусловлено отсутствием нужной возможности в самом языке, а теперь еще раз вернемся к тому о чем я говорил выше: почему нельзя средствами языка узнать, чем является объект и является ли он самим собой?

В том-то и дело, что нельзя создать полноценный инстанс без конструктора, вы не сможете воссоздать всего поведения. Описанный вами метод не даст вам понимания того будет ли инстанс работать как наследник прототипа, хотя и скажет вам, что прототип был наследован. Просто замените слово prototype на interface и вам все станет ясно что я имею в виду.

Это же очевидно, я подразумевал, что свойсто не mutable :)
Массив может не содержать под собой Array.prototype. Примеры — массив из другого фрейма, массив с измененным прототипом, типизированный массив. Array.isArray — проверка внутреннего класса, а не цепочки прототипов. Кстати да, отсутствие оператора или метода в стандартной библиотеке для получения внутреннего класса (а не изврат через Object.prototype.toString) — ИМХО серьезный минус js.

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

> В том-то и дело, что нельзя создать полноценный инстанс без конструктора, вы не сможете воссоздать всего поведения.
Почему это?
function Foo(bar){
  this.bar = bar;
}
Foo.prototype.getBar = function(){
  return this.bar;
}
var foo1 = new Foo(42);
console.log(foo1.getBar()); // -> 42
var foo2 = Object.create(Foo.prototype, {'bar': {value: 43}});
console.log(foo2.getBar()); // -> 43
var foo3 = {bar: 44};
foo3.__proto__ = Foo.prototype;
console.log(foo3.getBar()); // -> 44
Тогда метод должен называться isIteratable, но никак не isArray.

Это относится к Object.is. Вместо того чтобы расширить поведение оператора === до требуемого, добавляется новый метод, в следующей версии ждем глобального is или Object.isNotLike. Самое главное теперь понять почему этот метод добавлен в Object, а сравнивает примитивы.

Подмена __proto__ не воспроизведет всего поведения. Подмените __proto__ еще раз для foo1 и foo2 на что-то другое и у foo1 будет метод getBar, а у foo2 — нет. Не принимается.

Object.create — не вызовет конструктор. Соответственно придется делать, так:
var foo2=Object.create(Foo.prototype); Foo.call(foo2,43); 

Есть еще пара особенностей поведения, которые делают и этот способ не гарантированным, но вероятность их появления низка, поэтому принимается, но только в исправленном виде.
Подмените __proto__ еще раз для foo1 и foo2 на что-то другое и у foo1 будет метод getBar, а у foo2 — нет
Да шо ви такое говорите?

> foo1.__proto__ = null
null
> foo1.getBar
undefined

Конструктор в JavaScript — это всего-навсего функция, вызванная на «пустом» объекте, чтобы его «наполнить», а прототип — всего-навсего автоматически занесённое в поле __proto__ значение. Они ну ровным счётом ничем не отличаются от таких же объектов «созданных» руками.

В том-то и дело, что вы ищите в JavaScript'е какую-то логику, какой-то разумный замысел, а этот язык — как те «slightly used dutritium rods», которые не «cheap, cheap, cheap», а «even cheaper than that»: он слабан на коленке за 10 дней и его рядовые пятна с ним так навсегда и останутся даже когда он попадёт в тот же паноптикум, что и COBOL. Протипы не имеют ничего общего ни с интерфейсами, ни с классами, ни с чем-либо ещё — просто потому что в режиме «ещё дешевле чем дёшево, дёшево, ну просто очень дёшево» можно было сделать только тупое копирование из поля prototype в __proto__ — и всё. Ну то есть совсем всё. Нет там никакой магии.

А вот в объектах, созданных через new Array() — есть магия (опять-таки: потому что так было сделать «дешевле»). Но в остальном это — обычные объекты (и снова: не надо искать логику, она вся — в «дешевизне»):
> foo4 = new Array()
[]
> foo4.__proto__ = Foo.prototype
Foo {getBar: function, hohoho: 1}
> foo4.bar = "wow"
"wow"
> foo4.getBar()
"wow"
> Array.isArray(foo4)
true

Прелестно, не правда ли?

Относитесь к JavaScript'у проще: нет там никаких глубин науки, хитрых теорий, интерфейсов или чего-нибудь подобного. А есть куча дерьма которую только и можно было создать «ещё дешевле чем дёшево, дёшево, ну просто очень дёшево». Как только вы это поймёте — сразу поймёте почему в нём сделано всё так, а не иначе.

P.S. ECMAScript 6 — это попытка замазать эту кучу дерьма большим, толстым слоем помады. Какие-то косяки стали видны меньше, да, но запах… запах остался.
Есть случай с __proto__, который не позволяет говорить о 100% воспроизведении поведения. Но весь его я не стал расписывать.
А случай тяжелее, чем я думал.

> Тогда метод должен называться isIteratable, но никак не isArray.
Как же вы не поймете, что метод проверяет именно [[Class]], именно то, является ли объект массивом, а не array-like объектом.
В js есть итераторы, и это совершенно другое. Не знаете — учите.

> ждем глобального is
Вполне возможно, так и будет. Первоначально задумывались операторы is и isnt.

> Подмените __proto__ еще раз для foo1 и foo2 на что-то другое и у foo1 будет метод getBar, а у foo2 — нет.
Лолшто?

> Object.create — не вызовет конструктор. Соответственно придется делать, так
И не должен. Учите основы. Object.create принимает 2 аргумента.

И еще раз. Учите основы и не позорьтесь.
А с комментарием выше — про кучу дерьма — абсолютно согласен.
Для начала: ваш наркоманский сленг и стиль общения неуместны для этого ресурса, советую изменить — позорьтесь так только вы, показывая свой не высокий уровень и неумение вести интеллектуальную дисскуссию.

Теперь по существу.

Вы пытаетесть убедить меня приводя примеры очевидных костылей на уровне стандартной библиотеки создаваемых стандартизирующей организации. Вас не смущает ничего? Еще раз перечитайте с чего мы начали.

Есть ситуации, когда подмена __proto__ не даст вам 100% поведения. Пример оказался не удачным, нопример вы найдете.

Я знаю, что Object.create не вызовет конструктор, это вы видимо не знаете, раз предлагаете это как решение поставленной мной задачи. Конструктор — это неотъемлемый элемент при воспроизведении поведения.
Я вам указал на ваши, вполне очевидные, ошибки, при том даже не защищая js — а вы огрызаетесь.

> показывая свой не высокий уровень и неумение вести интеллектуальную дисскуссию

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

Так что GTFO, мне с вами больше не о чем разговаривать.
Не знаю, что означает GTFO. Я попросил сменить тон, так как он показался, мне оскорбительным. Имею на это право. Но к моему сожалению, вы не прислушались к моей просьбе, поэтому, советую вам обратить внимание на свое самообладание.

Подмена __proto__ у примитивов не даст желаемого результата, соответственно, данный способ не подходит, а вот Object.create ­— создаст полноценный инстанс (той же строки) с изменяемым __proto__.

Вот так просто. Это основы-основ. Советовать вам учить основы и не позориться я не буду, но несколько полезных ссылок все же оставлю:
www.ecma-international.org/ecma-262/5.1/
www.google.ru/search?q=речевой+этикет

Всего хорошего.
Есть ситуации, когда подмена __proto__ не даст вам 100% поведения.
Если исключить ошибки в реализации и встроенные типы, то таких вещей нет. И быть не может.

Я просто некоторое время «смотрел на молоток со стороны гвоздя» (когда разрабатывал нативные компоненты расширений для Firefox). В смысле работал с «кишками» той реализации JavaScript'а, которая тогда там была. И вот в этом случае вполне отчётливо видно, что вызов конструктора — это таки просто-напросто вызов обычной функции на пустом объекте с последующим копированием prototype в __proto__. И всё. Больше там ничего нету.

Конечно это было не очень эффективно, конечно сейчас всё несколько не совсем так просто, но из-за обратной совместимости для программиста всё должно продолжать выглядеть именно так. Если вы знаете случай когда на каком-то браузере «подмена __proto__ не даст вам 100% поведения», то вам нужно написать разработчикам этого браузера об этом как об ошибке, а не дуть щёки на Хабрахабре.

Я вам, кстати, даже дал подсказку: действительно иногда без вызова конструктора вы не сможете обойтись ибо конструкторы некоторых встроенных типов (таких как Array) — они «особенные». Но вот поле constructor в созданном таким образом объекте — оно особенным не является. Его можно подменить как и любое другое. Но создать таких «особенных» конструкторов на уровне JavaScript'а вы не сможете (в Firefox если выйти на уровень XPCOM'а — сможете, но это другая история), так что в результате вы таки можете эти случаи тоже обработать — используя как раз Array.isArray() и тому подобные вещи. Только нужно не забывать про «дешевизну» и помнить про заботливо разложенные по всему языку грабли. Например если вы сделаете переменную a содержащую, ну скажем, нуль (простой обычный нуль без выкрутасов), то у неё тоже будет поле __proto__ и в нём — функция isPrototypeOf, но вот a.__proto__.isPrototypeOf(a) будет равно false. А конструктор там такой особенный, что дальше некуда:
a = 0;
b = a.constructor = function () { return "hehe"; }
alert(b); // function () { return "hehe"; }
alert(a.constructor); // function Number() { [native code] }
То есть присваивание вроде как сработало… а вроде как и нет. Ну и где здесь логика? Нет её. За исключением одной: делаем так, как проще реализовать, а как с этим будут жить разработчики — это их проблемы.
А почему это мы исключили примитивы? Если разговор шел в контексте реализации ООП в js? Например в том же ruby, насколько мне известно, примитивы являются такими же инстансами, как и созданные, через конструктор.

Смотреть на молоток со стороны гвоздя, возможно, хорошо, но, как вы сами понимаете в корне не верно — не всегда гвозди забивают молотком. И js — именно тот случай — огромное разнообразие инструментов. Поэтому обратимся к соответсвующему разделу документации. Здесь мы увидим, что свойство __proto__ так же не доступно для тех объектов, которые имеют внутреннее свойство [[Extensible]] установленное в false и не смотря на то, что стандартная библиотека JS почти не имеет встроенных типов с [[Extensible]] равное false, все же считаю данный способ не гарантированным, хоть и 100%-работоспособным для остальных случаев.
Знаете, как в анекдоте. Иногда примитивы — это всего лишь примитивы.

Раз уж вы приводите пример ruby, где всё есть класс, приведу в пример java, где примитивы (int, long, boolean) не являются классами вовсе.
С чем именно вы не согласны в моем комментарии? С тем что нельзя говорить о 100% поддержке и работоспособности метода, если поддержка не полная? Не знаю как в Java, но, если вы не знаете, в js примитивы это и примитивы, и объекты одновременно, но с множеством тонкостей. Мы говорим про конкретную задачу – создание инстанса без вызова new Сonstructor(), когда сможете подменить __proto__ у примитива – приходите с решением!

P.S. Прежде чем встревать в обсуждение, прочтите ветку сначала.
Да, свойство «не mutable» это configurable:false и writable:false.
Красиво написано…

По существу:
Судя по всему, вы знаете про ECMAScript 6, поэтому не можете не знать, что большинство описанных вами проблем решено в следующей версии языка:
1. У массивов есть [].contains(item) — возвращающий булевое значение. У строк есть .contains, .startsWith, .endsWith
2. let/const появились
3. Number.isNaN работает иначе чем isNaN
4. Стандартный класс URI (уже работает в V8)
5. Классы class A extends B {}
6. __proto__ deprecated. Используйте Reflect.getPrototypeOf, Reflect.setPrototypeOf

Слепили за 10 дней.

Неправда и провокация. За 10 дней слепили версию, которую два года допиливали, до того состояния, чтобы отправить на стандартизацию в ISO. Текущая поддерживаемая браузерами — версия ECMA-262 редакция 5.1 2011 года — то есть почти 16 лет развития. 6 версия редакции (пресловутый Harmony) разрабатывалась последние 3 года — небольшой срок для такой сложной работы (все ведь помнят, сколько понадобилось времени для завершения работы над C++11 и принятии его в качестве стандарта?).

Вы можете возразить, что существуют браузеры, которые даже не в полной мере поддерживают ES 5.1, что уж говорить про ES6. Я на это обычно отвечаю, что самая популярная версия Python — 2.7 2010 года. Чтобы подтянуть старые браузеры до уровня ES 5.1 или даже ES 6, вы можете использовать полифилы. Вы даже можете уже писать на ES6 (т.к. стандарт уже не будет серьёзно меняться), просто используя прансляцию на этапе сборки проекта.
У массивов есть [].contains(item)


Или Array.prototype.has — ещё не решено.

Стандартный класс URI


А где спецификация?
Ссылка на http://wiki.ecmascript.org/doku.php?id=strawman:array.prototype.has находится на странице http://wiki.ecmascript.org/doku.php?id=strawman:oldes6 с подзаголовком «Most of this stuff didn’t make it into ES6», так что вообще нельзя быть уверенным в том, что в ES6 эти методы будут.

Я вот, например, вовсе не уверен в этом.
Признаться я спешил, поэтому в моём комментарии есть неточности:
1. К сожалению, ни [].has, ни [].contains в спецификации на данный момент нету — нужно уточнить почему.
2. Имел ввиду не класс URI, а класс URL (спецификация)
нужно уточнить почему


Ну так это же strawman, а не harmony.

Имел ввиду не класс URI, а класс URL


А, так Gecko тоже, и уже давно!
UFO just landed and posted this here
Записывать «маскировку» ошибок в преимущества языка это не то что бы неадекватно, но очень сильно на любителя, скажем так.


Да это не то что бы неадекватно, это бред чистой воды. Причем называть это высочайшим уровнем стабильности (именно так, выделяя буковки)… Это что же, эрланг с его моделью let it crash написан студентами-идиотами? Мда
UFO just landed and posted this here
  • Юнлинги увлеченно множат сущности безоглядно плодят прототипы, хвастаясь друг перед другом длиной светового меча
  • Падаван уже имеет несколько любимых приемов и думает что может практически для чего угодно использовать cut and paste
  • Суровый джедай, усмехаясь в усы, уже понимает что все не так однозначно
  • Мастер-джедай уверен, что чем меньше кода на яваскрипте в приложеньи тем лучше
  • Магистр же достичь результата сможет к источнику силы не прибегая почти
Беда JS в обратной совместимости, и от нее никуда не убежишь.
Доделать можно было бы много чего, изменить много что, но ведь половина интернетов при даже одном крупном изменении поломается. Или доломается.
Именно. Язык, в чем-то ущербный изначально, на уровне базовых вещей, будет ущербен до конца своих дней.
UFO just landed and posted this here
А вот это мне кажется уже не очень хорошо. JavaScript язык конечно будет иметь очень широкое применение, но есть ряд областей, в которых его применять неправильно и даже в чем-то преступно. Это финансовые расчеты, медицина, управление устройствами. Бездумных людей много, конечно будут пытаться это делать, но если применят яваскрипт где-нибудь к примеру в бортовой технике самолетов или в ракетах, это уже будет крайне не смешно. Да я бы даже бытовую технику ему не доверил, где-нибудь температура или время приведется к строке и будет сравниваться в таком виде и это конечно же не заметят.
Эксепшн, да будет вам известно, может быть обработан и в крайнем случае по необработанному эксепшену холодильник выключен. А что мы получим от холодильника на яваскрипт? Необработанные, замаскированные ошибки, риски поломки и даже возгорания, потому что если яваскрипт то и на физической защите и тестировании тоже сэкономят.
Эксепшн, да будет вам известно, может быть обработан


orly?

похоже, в иронию нынче без тега вообще никак.
У автора превратные представления об анархии. По его описанию языков анархичным следовало бы назвать C++, а в JS — обычный беспредел.
> Необходимо было создать настольное приложение на .Net C# и его точную копию в веб на JavaScript. С# приложение разрабатывала команда из 12 программистов в течении двух лет, JavaScript — команда из 3 программистов в течение года

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

Ну и уровень команд может влиять.

Зато, с другой стороны, веб-приложение работает по другому, чем декстопное, так что «точная копия» — может, она и функционально была попроще?
Особенно про производительность посмешило. Когда игры с восьмибитки при портировании тормозят на core i7.
Говоря об играх, так же не стоит забывать про тормоза самого API, с помощью которого они создаются (Canvas, WebGL). С этим мы ничего поделать не можем.
Да, конечно, я не совсем корректно выразился — тут виноват весь стек, слишком уж много оберток и виртуальных машин, чтобы все быстро работало. Но и напрямую пускать нельзя — и выходит тупик.
Здесь будет всего 4 строчки кода и много-много того, что не напишут в учебниках

Почти про все это пишут в учебниках, кроме субъективных «порогов вхождения», поправьте меня, если я что-то упустил.
Давайте будем честными. javascript это изначально очень неудачный язык с очень неудачной стандартной библиотекой, который по нелепому стечению обстоятельств прижился и стал данностью миллионов. Надо так же заметить, что это понимают и другие, поэтому пытаются привести javascript и его стандартную библиотеку (и другие веб-стандарты) в кондицию подобающую «главному языку».
UFO just landed and posted this here
JavaScript мультипарадигменный язык

Ну и что? Scala тоже мультипарадигменная. Java в 8-й версии подтягивается, а C++ с его бустом — вообще ого-го.

JavaScript не признаёт ограничений

… что позволяет выстрелить в ногу атомной ракетой

Последняя и самая важная вещь, которую нужно понимать о JavaScript, связана с его нетипизованностью

Чушь, ибо есть typeof, instanceof и .constructor. А это значит, что в рантайме информация о типа присутствует. Другое дело, что её нет на этапе компиляции.

Это может показаться странным, но я хочу задать такой вопрос: а для чего вообще существует система типов?

Цена ошибки возрастает со временем. Чем раньше обнаружена ошибка, тем менее разрушительные последствия от неё. Статически типизированные языки позволяют отлавливать многие ошибки на этапе компиляции. А ещё, навигация по коду гораздо удобнее, ведь если известен тип, то можно найти все подтипы, все вызовы метода, все переопределения метода и т.п. Поиск по регэкспам — геморрой после того, что даёт Eclipse для Java.

JavaScript обладает потрясающим уровнем интроспекции

Ну и что? java.lang.reflect? А ещё в Java есть байт-код, который можно заменить или проанализировать. Вот как мне построить data flow graph работающей программы на лету? Например, чтобы произвести liveness analysis или построить domination tree. За LLVM не скажу, так глубоко не копал, но есть подозрение, что и там подобные выкрутасы можно проводить в рантайме. Зато там сразу SSA! Где такой уровень интроспекции в JS?

И вот самое вкусное, наконец:

Необходимо было создать настольное приложение на .Net C# и его точную копию в веб на JavaScript. С# приложение разрабатывала команда из 12 программистов в течении двух лет, JavaScript — команда из 3 программистов в течение года. Можно говорить о разнице в квалификации, о том, что возможно влияли другие факторы, но так или иначе разница в 8 раз показательна.


А единственный одинэсер наваял за три месяца, ага? Есть такая палка о двух концах. На одной стороне — скорость разработки, на другой — сложность поддержки. Можно усилиями мозга пытаться уменьшить и то и другое, но только до определённого предела. Приходится выбирать. Можно и на JS писать так, чтобы было надёжно и понятно, но тогда разработка сильно замедлится, а можно и на Java быстро наваять, а потом долго мучиться.
А почему бы браузероделам не придумать альтернативу? Да и те же джава апплеты, но с решёнными проблемами безопасности и поддерживаемые всеми браузерами из коробки?
А зачем? Ну и с Джава могут быть неприятности с Оракл.
Затем чтоб не было так, что открываешь браузер с парой страничек и он ест 80% CPU выполняя скрипт какого-то криворучки. А от J2ME или JavaCard неприятностей вроде нет…
> программы с высочайшим уровнем стабильности.

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

Какой такой павлин-мавлин? Где там интроспекция? Чем она потрясает после, скажем, питоновой?
Sign up to leave a comment.

Articles