Язык программирования JavaScript: информация для начинающих. Зачем использовать статические типы в JavaScript? (Преимущества и недостатки)

Язык PHP применяется для разработки веб-приложений очень активно, и сегодня на нем работают три из пяти сайтов. Однако обязательно стоит обратить внимание и на возможные альтернативы. Одной из них является Node.js.

Преимущества Node.js

Количество поклонников этой программной платформы стремительно увеличивается, ведь во многих ситуациях она имеет неоспоримые преимущества перед PHP. Javascript, на котором пишется серверный код на Node.js — это мощный и гибкий язык. Он имеет свои особенности и даже странности, однако после того, как вы поймете его концепцию, работа на нем наверняка вас затянет. Javascript допускает программирование в разных стилях и предоставляет разработчику большие возможности.

Node.js дополнительно расширяет его функционал. Если раньше Javascript использовался исключительно для разработки браузерных приложений, то теперь на нем можно писать также приложения мобильные и десктопные. PHP тоже можно применять для разработки десктопных приложений и консольных утилит, но делается это достаточно редко.

По умолчанию Node.js укомплектована удобным и функциональным менеджером пакетов — npm. Он делает управление модулями и зависимостями простым и комфортным. А благодаря встроенным библиотекам для обработки запросов и ответов с Нодой вы не будете зависеть от сторонних серверов. Также эта платформа в некоторых ситуациях обеспечивает лучшую производительность.

И, наконец, Node.js имеет большое количество положительных отзывов от разработчиков. Немногие из тех, кто пишут на PHP, увлечены этим языком, но с Javascript ситуация совсем иная.

Недостатки

Однако надо иметь в виду, что Node не лишена недостатков:

  • она сложнее в изучении, и начать работать с использованием этой технологии будет не так легко, особенно в том случае, если вы новичок в веб-программировании, в то время как создать сайт на PHP гораздо проще;
  • технология Node относительно молода, поэтому информации по ней гораздо меньше, чем по PHP;
  • для PHP подойдет любой хостинг, а вот подходящую площадку для Node придется еще поискать;

Таким образом, однозначного ответа на вопрос о том, что лучше — PHP или Node.js — нет. Однако нужно иметь в виду, что последняя стремительно набирает популярность. Сегодня ее используют Microsoft, PayPal, LinkedIn, Yahoo и множество других крупных компаний.

Многие еще с девяностых годов привыкли использовать PHP и не спешат его на что-то менять. Однако прогресс не стоит на месте, и технологии веб-разработки в последние годы развиваются стремительно. В том случае, если вы будете игнорировать новые веяния, рано или поздно вы заметите, что разрабатываемые вами продукты просто недостаточно актуальны и востребованы.

Теперь с синтаксисом покончено, давайте наконец перейдём к самому интересному: изучению преимуществ и недостатков использования статических типов.

Преимущество № 1: Вы можете заблаговременно находить баги и ошибки

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

Небольшой пример: предположим, что у нас небольшая функция, которая берёт радиус и вычисляет площадь:

Const calculateArea = (radius) => 3.14 * radius * radius; var area = calculateArea(3); // 28.26
Теперь если мы захотим передать функции радиус, который не является числом (типа «злоумышленник»)…

Var area = calculateArea("im evil"); // NaN
Нам вернётся NaN . Если какая-то функциональность основана на том, что функция calculateArea всегда возвращает число, то это приведёт к уязвимости или сбою. Не очень приятно, правда?

Если бы мы использовали статические типы, то определили бы конкретный тип передаваемых параметров и возвращаемых значений для этой функции:

Const calculateArea = (radius: number): number => 3.14 * radius * radius;
Попробуйте теперь передать что-нибудь кроме числа функции calculateArea - и Flow вернёт удобное и симпатичное сообщение:

CalculateArea("Im evil"); ^^^^^^^^^^^^^^^^^^^^^^^^^ function call calculateArea("Im evil"); ^^^^^^^^^ string. This type is incompatible with const calculateArea = (radius: number): number => 3.14 * radius * radius; ^^^^^^ number
Теперь у нас есть гарантия, что функция будет принимать только валидные числа на входе и возвращать результат только в виде валидных чисел.

Поскольку контролёр типов сообщает вам об ошибках прямо во время написания кода, это намного удобнее (и намного дешевле), чем поиск бага после того, как код отправлен заказчику.

Преимущество № 2: У вас появляется живая документация

Типы работают как живая, дышащая документация и для вас, и для других.

Чтобы понять каким образом, посмотрим на метод, который я однажды нашла в большой кодовой базе, с которой работала:

Function calculatePayoutDate(quote, amount, paymentMethod) { let payoutDate; /* business logic */ return payoutDate; }
На первый взгляд (и на второй, и на третий), совершенно непонятно, как использовать эту функцию.

Является ли quote числом? Или логическим значением? Платёжный метод - это объект? Или это может быть строка, которая представляет тип платёжного метода? Возвращает ли функция дату в строковом виде? Или это объект Date ?

Без понятия.

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

С другой стороны, если бы написали что-то вроде такого:

Function calculatePayoutDate(quote: boolean, amount: number, paymentMethod: string): Date { let payoutDate; /* business logic */ return payoutDate; }
то немедленно стало бы ясно, какой тип данных функция принимает, а какой тип возвращает. Это пример того, как можно использовать статические типы для сообщения того, что функция намерена делать. Мы можем сообщить другим разработчикам, чего ожидаем от них, и можем увидеть, чего они ожидают от нас. Следующий раз, если кто-то соберётся использовать эту функцию, вопросов не возникнет.

Можно поспорить, что эта проблема решается добавлением комментариев к коду или документации:

/* @function Determines the payout date for a purchase @param {boolean} quote - Is this for a price quote? @param {boolean} amount - Purchase amount @param {string} paymentMethod - Type of payment method used for this purchase */ function calculatePayoutDate(quote, amount, paymentMethod) { let payoutDate; /* .... Business logic .... */ return payoutDate; };
Это работает. Но здесь гораздо больше слов. Кроме многословности, такие комментарии в коде трудно поддерживать, потому что они ненадёжные и не имеют структуры - некоторые разработчики пишут хорошие комментарии, а другие могут написать что-то непонятное, а некоторые вообще могут забыть оставить комментарий.

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

Преимущество № 3: Устраняется обработка запутанных ошибок

Типы помогают устранить обработку в коде запутанных ошибок. Давайте вернёмся к нашей функции calculateArea и посмотрим, каким образом это происходит.

На этот раз я передам ей массив радиусов для вычисления площадей для каждого радиуса:

Const calculateAreas = (radii) => { var areas = ; for (let i = 0; i < radii.length; i++) { areas[i] = PI * (radii[i] * radii[i]); } return areas; };
Эта функция работает, но неправильно обрабатывает некорректные входные аргументы. Если мы захотим убедиться, что функция правильно обрабатывает ситуации, когда входные аргументы не являются валидными массивами чисел, то придём к функции примерно такого вида:

Const calculateAreas = (radii) => < radii.length; i++) { if (typeof radii[i] !== "number") { throw new Error("Array must contain valid numbers only"); } else { areas[i] = 3.14 * (radii[i] * radii[i]); } } return areas; };
Ого. Тут много кода для такого маленького кусочка функциональности.

А со статическими типами мы просто напишем:

): Array => < radii.length; i++) { areas[i] = 3.14 * (radii[i] * radii[i]); } return areas; };
Теперь функция действительно выглядит так, как она выглядела перед добавлением всего визуального мусора из-за обработки ошибок.

Легко понять преимущества статических типов, правда?

Преимущество № 4: Вы можете увереннее осуществлять рефакторинг

Объясню это историей из жизни. Однажды я работала с очень большой кодовой базой, и нужно было обновить метод, установленный в классе User . В частности, изменить один из параметров функции со string на object .

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

Единственный способ проверить - это отправить код и молиться, что он не взорвётся кучей ошибок.

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

Преимущество № 5: Разделение данных и поведения

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

Ещё раз посмотрим на нашу функцию calculateArea со статическими типами:

Const calculateAreas = (radii: Array): Array => { var areas = ; for (var i = 0; i < radii.length; i++) { areas[i] = 3.14 * (radii[i] * radii[i]); } return areas; };
Подумайте, как бы мы подошли к составлению этой функции. Поскольку мы указываем типы данных, то вынуждены в первую очередь думать о типах данных, которые собираемся использовать, чтобы можно было соответствующим образом установить типы для передаваемых параметров и возвращаемых значений.

Только после этого мы реализуем логику:

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

Преимущество № 6: Устранение целой категории багов

Ошибки типов во время выполнения программы - одна из самых распространённых ошибок или багов, с которыми сталкиваются JavaScript-разработчики.

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

Var appState = { isFetching: false, messages: , };
И предположим, что затем мы делаем вызов API, чтобы забрать сообщения и заполнить наш appState . Далее, у нашего приложения есть чрезмерно упрощённый компонент для просмотра, который забирает messages (указанные в состоянии выше) и отображает количество непрочитанных сообщений и каждое сообщение как элемент списка:

Import Message from "./Message"; const MyComponent = ({ messages }) => { return (

{ messages.map(message => )}
); };
Если вызов API для забора сообщений не сработал или вернул undefined , то вы столкнётесь с ошибкой типа в продакшне:

TypeError: Cannot read property ‘length’ of undefined
…и ваша программа завершится со сбоем. Вы потеряете клиента. Занавес.

Посмотрим, как могут помочь статические типы. Начнём с добавления типов Flow к состоянию приложения. Я использую псевдоним типа AppState для определения состояния:

Type AppState = { isFetching: boolean, messages: ?Array }; var appState: AppState = { isFetching: false, messages: null, };
Поскольку известно, что API для забора сообщений работают ненадёжно, то укажем для значения messages тип maybe для массива строк.

Так же как в прошлый раз, мы забираем сообщения через ненадёжный API и используем их в компоненте просмотра:

Import Message from "./Message"; const MyComponent = ({ messages }) => { return (

You have { messages.length } unread messages

{ messages.map(message => )}
); };
Но в этот момент Flow обнаружит ошибку и пожалуется:

^^^^^^ property `length`. Property cannot be accessed on possibly null value

You have {messages.length} unread messages

^^^^^^^^ null

You have {messages.length} unread messages

^^^^^^ property `length`. Property cannot be accessed on possibly undefined value

You have {messages.length} unread messages

^^^^^^^^ undefined { messages.map(message => )} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call of method `map`. Method cannot be called on possibly null value { messages.map(message => )} ^^^^^^^^ null { messages.map(message => )} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call of method `map`. Method cannot be called on possibly undefined value { messages.map(message => )} ^^^^^^^^ undefined
Погоди, приятель!

Поскольку мы определили messages как тип maybe , мы разрешаем ему быть null или undefined . Но это не даёт нам права проводить операции с ним (вроде.length или.map) без осуществления проверки на null , потому что если значение messages на самом деле null или undefined , то выскочит ошибка типа при попытке проведения операции с ним.

Так что вернёмся и обновим нашу функцию для просмотра примерно таким образом:

Const MyComponent = ({ messages, isFetching }: AppState) => { if (isFetching) { return } else if (messages === null || messages === undefined) { return

Failed to load messages. Try again.
} else { return (

You have { messages.length } unread messages

{ messages.map(message => )}
); } };
Теперь Flow знает, что мы учли все ситуации, где messages равно null или undefined , так что проверка типов кода завершается с 0 ошибок. Прощайте, ошибки во время выполнения программы!

Преимущество № 7: Уменьшение количества юнит-тестов

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

Например, вернёмся к нашей функции calculateAreas с динамическими типами и обработкой ошибок.

Const calculateAreas = (radii) => { // Handle undefined or null input if (!radii) { throw new Error("Argument is missing"); } // Handle non-array inputs if (!Array.isArray(radii)) { throw new Error("Argument must be an array"); } var areas = ; for (var i = 0; i < radii.length; i++) { if (typeof radii[i] !== "number") { throw new Error("Array must contain valid numbers only"); } else { areas[i] = 3.14 * (radii[i] * radii[i]); } } return areas; };
Если бы мы были прилежными программистами, то могли бы подумать о тестировании недействительных передаваемых параметров для проверки, что они корректно обрабатываются нашей программой:

It("should not work - case 1", () => { expect(() => calculateAreas()).to.throw(Error); }); it("should not work - case 2", () => { expect(() => calculateAreas(undefined).to.throw(Error); }); it("should not work - case 2", () => { expect(() => calculateAreas("hello")).to.throw(Error); });
… и так далее. Но очень вероятно, что мы забудем протестировать какие-то граничные случаи, - и наш заказчик будет тем, кто обнаружит проблему. :(

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

С другой стороны, когда нам требуется установить типы:

Const calculateAreas = (radii: Array): Array => { var areas = ; for (var i = 0; i < radii.length; i++) { areas[i] = 3.14 * (radii[i] * radii[i]); } return areas; };
… мы не только получаем гарантию, что наша цель соответствует реальности, но такие тесты попросту надёжнее. В отличие от тестов на эмпирической основе, типы универсальны и их труднее обойти.

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

Преимущество № 8: Инструмент моделирования предметной области

Один из моих любимых примеров использования статичных типов - моделирование предметной области (domain modeling). В этом случае создаётся модель, которая включает в себя и данные, и поведение программы на этих данных. В данном случае лучше всего понять на примере, как использовать типы.

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

Итак, сначала применим псевдонимы типов для трёх платёжных методов:

Type Paypal = { id: number, type: "Paypal" }; type CreditCard = { id: number, type: "CreditCard" }; type Bank = { id: number, type: "Bank" };
Теперь можно установить тип PaymentMethod как непересекающееся множество с тремя случаями:

Type PaymentMethod = Paypal | CreditCard | Bank;
Теперь составим модель состояния нашего приложения. Чтобы не усложнять, предположим, что данные приложения состоят только из платёжных методов, доступных пользователю.

Type Model = { paymentMethods: Array };
Это приемлемо? Ну, мы знаем, что для получения платёжных методов пользователя нужно сделать запрос к API и, в зависимости от результата и этапа процесса, приложение может принимать разные состояния. В реальности, возможно четыре состояния:

1) Мы не получили платёжные методы.
2) Мы в процессе получения платёжных методов.
3) Мы успешно получили платёжные методы.
4) Мы попытались получить платёжные методы, но возникла ошибка.

Но наш простой тип Model с paymentMethods не покрывает все эти случаи. Вместо этого он предполагает, что paymentMethods всегда существует.

Хм-м-м. Существует ли способ составить модель, чтобы состояние приложения принимало одно из этих четырёх значений, и только их? Давайте посмотрим:

Type AppState = { type: "NotFetched" } | { type: "Fetching" } | { type: "Failure", error: E } | { type: "Success", paymentMethods: Array };
Мы использовали тип непересекающегося множества для установки AppState в одно из четырёх состояний, описанных выше. Заметьте, как я использую свойство type для определения, в каком из четырёх состояний находится приложение. Именно это свойство type и является тем, что создаёт непересекающееся множество. Используя его мы можем осуществить анализ и определить, когда у нас есть платёжные методы, а когда нет.

Вы также заметите, что я передаю параметризованный тип E и D в состояние приложения. Тип D будет представлять собой платёжный метод пользователя (PaymentMethod , определённый выше). Мы не установили тип E , который будет нашим типом для ошибки, так что сделаем это сейчас:

Type HttpError = { id: string, message: string };
Теперь можно смоделировать предметную область приложения:

Type Model = AppState;
В целом, подпись для состояния приложения теперь AppState , где E имеет форму HttpError , а D - это PaymentMethod . И у AppState есть четыре (и только эти четыре) возможных состояния: NotFetched , Fetching , Failure и Success .

Такие модели предметной области мне кажутся полезными для размышлений и разработки пользовательских интерфейсов в соответствии с определёнными бизнес-правилами. Бизнес-правила говорят нам, что приложение может быть только в одном из этих состояний, и это позволяет нам явно представить AppState и гарантировать, что оно будет только в одном из этих заранее установленных состояний. И когда мы разрабатываем по этой модели (например, создаём компонент для просмотра), становится абсолютно очевидно, что нужно обработать все четыре возможных состояния.

Более того, код документирует сам себя - достаточно посмотреть на непересекающиеся множества, и немедленно становится понятно, как структурирован AppState.

Недостатки использования статических типов

Как и всё остальное в жизни и программировании, проверка статических типов требует некоторых компромиссов.

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

Вот некоторые из этих соображений:

Недостаток № 1: Статические типы требуют предварительного изучения

Одна причина, почему JavaScript - такой фантастический язык для начинающих, состоит в том, что новичкам не требуется изучать полную систему типов перед началом продуктивной работы.

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

Изучение эффективного использования типов - это была половина успеха в изучении самого языка. В итоге, из-за статических типов кривая обучения Elm круче, чем у JavaScript.

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

Недостаток № 2: Можно увязнуть в многословии

Из-за статических типов программы часто выглядят более многословными и загромождёнными.

Например, вместо этого:

Async function amountExceedsPurchaseLimit(amount, getPurchaseLimit){ var limit = await getPurchaseLimit(); return limit > amount; }
Нам приходится писать:

Async function amountExceedsPurchaseLimit(amount: number, getPurchaseLimit: () => Promise): Promise { var limit = await getPurchaseLimit(); return limit > amount; }
А вместо этого:

Var user = { id: 123456, name: "Preethi", city: "San Francisco", };
Приходится писать такое:

Type User = { id: number, name: string, city: string, }; var user: User = { id: 123456, name: "Preethi", city: "San Francisco", };
Очевидно, что добавляются лишние строки кода. Но есть парочка аргументов против того, чтобы считать это недостатком.

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

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

Сложно сказать, является ли многословность реальным аргументом против типов, но стóит держать его в уме.

Недостаток № 3: Требуется время для достижения мастерства в использовании типов

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

Например, один из подходов такой: закодировать критическиую бизнес-логику статическими типами, но оставить краткосрочные или неважные фрагменты логики динамическими, чтобы избежать излишней сложности.

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

Недостаток № 4: Статические типы могут задержать быструю разработку

Как я упоминала ранее, я слегка споткнулась о типы, когда изучала Elm - особенно когда добавляла код или делала изменения в нём. Постоянно отвлекаясь на ошибки компилятора, трудно делать работу и чувствовать прогресс.

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

Дело не только в этом. Контролёры статических типов тоже не всегда идеальны. Иногда возникает ситуация, когда вы знаете что делать, а проверка типов вмешивается и мешает.

Уверена, что я упустила какие-то ещё недостатки, но это самые важные для меня.

Нужно использовать статические типы в JavaScript или нет?


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

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

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

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

В конечном счёте, здесь нет универсального решения. Лично я предпочитают использовать статические типы при следующих условиях:

  1. Программа критически важна для вашего бизнеса.
  2. Программа, вероятно, подвергнется рефакторингу, в соответствии с новыми потребностями.
  3. Программа сложна и имеет много подвижных частей.
  4. Программу поддерживает большая группа разработчиков, которым нужно быстро и точно понять код.
С другой стороны, я бы отказалась от статических типов в следующих условиях:
  1. Код недолговечный и не является критически важным.
  2. Вы делаете прототип и стараетесь продвигаться как можно быстрее.
  3. Программа маленькая и/или простая.
  4. Вы единственный разработчик.
Преимущество разработки на JavaScript в наши дни состоит в том, что благодаря инструментам вроде Flow и TypeScript у нас наконец-то появился выбор - использовать статические типы или старый добрый JavaScript.

Заключение

Надеюсь, эти статьи помогли вам понять важность типов, как их использовать и, самое главное, *когда* их использовать.

Возможность переключаться между динамическими и статическими типами - это мощный инструмент для JavaScript-сообщества, и захватывающий:)

Javascript очень мощный язык, в нем заложен большой потенциал. При бурно растущих веб-технологиях он может стать одним из лидеров среди языков программирования. Среда исполнения javascript кода присутствует в любом компьютере, в большинстве телефонов, да и серверное ПО можно разработать на этом замечательном языке.

Но язык не лишен недостатков. Наиболее значимые из них:

  1. Язык компилируется в момент исполнения кода. Каждый раз, когда вы открываете сайт, javascript код начинает компилироваться. Как минимум увеличивается время выполнения программы.
  2. Отсутствует типизация данных. Проблема всех скриптовых языков. Пока выполнение кода не дойдет до нужной строчки, не узнаешь работает ли она. А ведь значительную часть по поиску ошибок мог бы взять на себя компилятор, если бы знал типы данных, с которыми он работает. Да и по скорости выполнения, типизированный код быстрее.
  3. Не привычная для многих программистов объектная модель. Классы и наследование классов присутствует, но оно сильно отличается от привычной многим реализаций в языках программирования C++/C#/Java.

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

Какие есть пути решения? Отказаться от использолвания javascript? Google, например, уже придумала замену - язык google dart. А как быть с уже написанным кодом? Годы полезной работы наших замечательных программистов?

Не все так печально.

  1. Проблему с типизаций позволяет решить удивительное ПО от google - closure compiler. Необходимо в коде рядом с переменными, функциями и параметрами функций добавлять специальным образом оформленные комментарии - аннотации, в которых указаны типы данных. И умное ПО от google подскажет вам, где вы совершили ошибку.
  2. Компилировать код на данный момент нельзя. Но можно уменьшить объем кода, сжав его как логически (переименовав переменные, убрав лишние пробелы, преобразовав код и т.д.), так и при помощи алгоритмов сжатия (например, gzip). Здесь же есть простор для браузеров. Браузеры могут компилировать код только при первой загрузку с сайта, и уже откомпилированный код запоминать. И при следующем запуске использовать уже откомпилированный код. Производительность железа тоже не отстает, сейчас уже даже телефон может не уступать по производительности простенькому настольным компьютеру.
  3. Избавиться от «корявой» объектной модели позволяет сам язык javascript. Имеются замечательные инструменты:

    Описание классов внешне приближается к описанию классов на языке C++/C#/Java. Это действительно удобно как для понимания, так и для сопровождения кода. Второй инструмент привносит полноценные public, protected и private методы, добавляет полноценные свойства классов. Все просто и изящно.

Все недостатки языка javascript устранимы. Его смело можно использовать в масштабных проектах. Замена языку пока не нужна.

Теги: javascript, javascript framework

24.11.14 15.6K

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

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

Интернет представляет собой массу возможностей, за которые ухватываются светлые и предприимчивые умы. Конечно, веб-разработка тоже имеет свои инструменты для воплощения идей в жизнь. Один из них – язык программирования JavaScript , о котором и пойдёт речь в данной статье:

Общая информация

Многие люди, даже не имеющие никакого отношения к IT-сфере, слышали слово Java . Революционный независимый от платформ язык, на котором активно пишут приложения для мобильных систем. Он был разработан перспективной компанией Sun , которая затем перешла «под крыло » Oracle . Но ни та, ни другая компании не имеют никакого отношения к JavaScript :

От Sun потребовалось лишь разрешение на использование части названия. Удивительно, но JavaScript вообще не принадлежит ни одной фирме.

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

  • Объектно-ориентированность. Выполнение программы представляет собой взаимодействие объектов;
  • Приведение типов данных проводится автоматически;
  • Функции выступают объектами базового класса. Эта особенность делает JavaScript похожим на многие функциональные языки программирования, такие как Lisp и Haskell ;
  • Автоматическая очистка памяти. Так называемая, сборка мусора делает JavaScript похожим на C# или Java .

Если говорить о сути применения JavaScript , то этот язык позволяет «оживлять » неподвижные страницы сайтов с помощью кода, который можно запустить на исполнение (так называемые, скрипты ). То есть, можно провести аналогию с мультфильмами, где html и css – это прорисованные герои, а JavaScript – это то, что заставляет их двигаться.

Если говорить о синтаксисе JavaScript , то ему присущи следующие особенности:

  • Регистр важен. Функции с названиями func() и Func() – совершенно разные;
  • После операторов необходимо ставить точку с запятой;
  • Встроенные объекты и операции;
  • Пробелы не учитываются. Можно использовать сколько угодно отступов, а также переводов строки, чтобы оформить свой код.

Простейший код на JavaScript выглядит следующим образом:

Сфера применения

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

  • Разработка веб-приложений. Хотите установить простой счетчик, организовать передачу данных между формами или поместить на своем сайте игру? Тогда JavaScript выступит верным помощником в этом деле;
  • «Активное участие» в AJAX . Эта технология позволила значительно ускорить работу приложений, осуществляя обмен данными с сервером в «фоновом » режиме:

  • Операционные системы. Возможно, кто-то не знал, но Windows , Linux и Mac имеют своих браузерных конкурентов, львиная доля кода которых написана на JavaScript ;
  • Мобильные приложения;
  • Сфера обучения. Любая программистская специальность в университете включает в себя изучение JavaScript в том или ином объеме. Это обусловлено тем, что язык изначально разрабатывался для не очень сильных программистов. Уроки JavaScript логически вплетаются в базовый курс HTML , поэтому освоение проходит достаточно просто.

Преимущества и недостатки

Не стоит думать, что JavaScript – это какая-то панацея от всех проблем, и каждый программист с улыбкой на лице пользуется этим языком. Всё на свете имеет свои положительные и отрицательные стороны. Для начала, отметим недостатки.

  • Необходимость обеспечивать кроссбраузерность. Раз уж JavaScript выступает как интернет-технология, то приходится мириться с правилами, которые устанавливает всемирная паутина. Код должен корректно выполняться во всех, или хотя бы самых популярных, браузерах;
  • Система наследования в языке вызывает трудности в понимании происходящего. В JavaScript реализовано наследование, основанное на прототипах. Люди, изучавшие другие объектно-ориентированные языки программирования, привыкли к привычному «класс потомок наследует родительский класс ». Но в JavaScript такими вещами занимаются непосредственно объекты, а это не укладывается в голове;
  • Отсутствует стандартная библиотека. JavaScript не предоставляет никаких возможностей для работы с файлами, потоками ввода-вывода и прочими полезными вещами;
  • Синтаксис в целом затрудняет понимание. Красота кода – явно не конёк JavaScript , но главное правило программистов соблюдено: «Работает? Не трожь! ».

Теперь стоит отметить некоторые преимущества

  • JavaScript предоставляет большое количество возможностей для решения самых разнообразных задач. Гибкость языка позволяет использовать множество шаблонов программирования применительно к конкретным условиям. Изобретательный ум получит настоящее удовольствие;
  • Популярность JavaScript открывает перед программистом немалое количество готовых библиотек, которые позволяют значительно упростить написание кода и нивелировать несовершенства синтаксиса;
  • Применение во многих областях. Широкие возможности JavaScript дают программистам шанс попробовать себя в качестве разработчика самых разнообразных приложений, а это, безусловно, подогревает интерес к профессиональной деятельности.

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

Для тех, кто хочет изучать

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

  • Прежде всего, HTML . Нельзя начинать делать что-либо для интернета без основы основ. Каскадные таблицы стилей (CSS ) также очень сильно пригодятся;
  • Использовать новую литературу. Программирование – это не физика, законы которой нерушимы, а новые учебные пособия – это урезанные старые. IT-технологии постоянно развиваются, и не стоит пренебрегать полезными обновлениями;
  • Стараться самостоятельно писать все участки программы. Если что-то ну совсем не получается – можно позаимствовать чужой код, но лишь предварительно уяснив для себя каждую строчку;
  • Отладка – ваш верный друг. Быстро находить ошибки – один из важнейших моментов в программировании;
  • Не игнорируйте нормы форматирования. Конечно, код не станет лучше или хуже от разного количества отступов и пробелов, но легкость чтения и понимания программистом – тоже немаловажный момент. Код, приведенный ниже? очень трудно воспринимается, особенно если вы не его

  • Имена переменных должны иметь лексическое значение. В процессе написания простых программ это кажется вовсе не важным, но когда количество строк кода переваливает за тысячу – все черти ломают ноги;


Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: