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

Как и многие новые разработчики, JavaScript был первым языком, который я выучил. Это интерфейсный язык программирования в Интернете и, благодаря Node.js, он также является популярным внутренним инструментом.

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

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

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

Итак, чтобы стать более продвинутым разработчиком JavaScript, полезно попытаться лучше понять, что происходит под капотом. В конечном счете, лучше всего искать V8 JavaScript Engine: это наиболее широко используемый компилятор JavaScript (лежащий в основе Google Chrome, Node.js и др.) И с открытым исходным кодом, поэтому вы можете точно увидеть, как функции JavaScript выполняются в C ++. - основной язык.

Но эта статья не является руководством по V8. Скорее, это взгляд на то, как языки нижнего уровня, такие как C ++, могут помочь нам улучшить наше понимание языков высокого уровня, таких как JavaScript. C ++ может не только помочь нам понять базовый код компилятора, но и - изучив то, что разработчики C ++ должны делать, чего разработчикам JavaScript следует избегать, - мы можем гораздо лучше понять, где JavaScript экономит нам время и почему иногда это может вызвать проблемы.

В частности, мы рассмотрим типы данных и управление памятью в C ++ и то, как их знание может помочь нам избежать ошибок типов и предотвратить утечки памяти в JavaScript. Мы также рассмотрим, какое отношение управление памятью имеет к концу времени.

Приведение типов в JavaScript

Прежде чем переходить к C ++, давайте посмотрим, как JavaScript обрабатывает типы данных и некоторые подводные камни его системы «приведения типов».

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

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

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

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

Помня о преимуществах и недостатках системы приведения типов в JavaScript, давайте теперь посмотрим, как C ++ обрабатывает типы данных.

Типы и управление памятью в C ++

Языки более низкого уровня, такие как C ++, не имеют таких потенциальных ловушек, потому что типы данных должны быть указаны в точке определения. В то время как в JavaScript есть три ключевых слова - var, let и const - для объявления новых переменных, в C ++ каждый тип данных имеет собственное ключевое слово.

Так, например, 7 основных типов данных в C ++ - это целые числа, числа с плавающей запятой, двойные числа с плавающей запятой, символьные, широкие символы, логические и бесполезные. Ключевые слова, используемые для их определения: int, float, double, bool, _10 _, _ 11_ и void соответственно.

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

В отличие от JavaScript, C ++ предоставляет разработчикам большую часть контроля над управлением памятью. В C ++ каждый раз, когда мы объявляем переменную, мы также принимаем решение о том, сколько памяти следует зарезервировать. Например, обычный char обычно содержит всего 8 бит (1 байт), что ограничивает его использование 255 символами таблиц ISO Latin. Напротив, wchar_t содержит 16 или 32 бита, занимая больше памяти, но позволяя нам получить доступ к гораздо большему разнообразию символов Unicode.

Наибольшее разнообразие вариантов можно найти в целочисленном типе, где основное ключевое слово int можно комбинировать с ключевыми словами размера short, long и long long и ключевыми словами «подписи» signed и unsigned.

Базовый int тип содержит естественный размер, предложенный системной архитектурой. В 64-битной операционной системе это обычно 32 бита. На практике это означает, что такая знаковая переменная может содержать значения от -2 147 483 648 до 2 147 483 647, а беззнаковая переменная может содержать значения от 0 до 4 294 967 295.

Если вы знаете, что диапазон возможных целых чисел меньше этого, вы можете использовать short int для экономии памяти. Или, если вы имеете дело с очень большими целыми числами, вы можете использовать unsigned long long int для записи 64-битных чисел размером до 2^64-1 (9 квинтиллионов).

Почему память так важна: пример использования о конце времен

Использование 64-битного объявления переменной, такого как long long int, позволяет компьютерам измерять даты на 292 миллиона лет в будущем. Это может показаться излишне большим количеством времени, но на самом деле это решает очень практическую проблему.

По соглашению, большинство дат в вычислениях измеряются с использованием времени Unix, которое отсчитывается от полуночи 1 января 1970 года по всемирному координированному времени и имеет точность до ближайшей секунды. В системах, где время Unix хранится как 32-битное число со знаком, наибольшее значение, которое может быть записано, составляет 2 147 483 647. Это может показаться большим, но, учитывая, что мы записываем каждую секунду, два миллиарда на самом деле не очень далеко.

Фактически, даты, записанные в 32-битных системах, достигнут своего максимального значения 19 января 2038 года по всемирному координированному времени (точно в 03:14:07). Когда это произойдет, дата перейдет в минус 2147483647, появится 13 декабря 1901 года. Это известно как проблема 2038 года, и это привело к появлению многих гиперболических заголовков, таких как «Все компьютеры будут уничтожены в 2038 году». - любезно предоставлено британской таблоидом Metro.

Этот сенсационный заголовок может быть далек от истины, но - когда наступит 2038 год - проблема может вызвать проблемы для 32-битных операционных систем и даже более старых версий целых языков программирования. Впервые я столкнулся с проблемой, используя PHP, который - до версии 5.2 - не имел встроенного способа записи дат после 2038 года. (Для записи, JavaScript использует 64-битную систему для измерения даты, поэтому нам, разработчикам JavaScript, не нужно беспокоиться об этом)!

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

Управление памятью в JavaScript

«JavaScript автоматически выделяет память при создании объектов и освобождает ее, когда они больше не используются (сборка мусора). Эта автоматичность является потенциальным источником путаницы: она может создать у разработчиков ложное впечатление, что им не нужно беспокоиться об управлении памятью ». - MDN

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

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

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

Одной из частых причин утечки памяти является случайное использование глобальных переменных. Каждый раз, когда мы определяем переменную в JavaScript без ключевого слова var, let или const, это автоматически считается глобальной переменной. Если foo уже не определен, выражение foo = "bar" эквивалентно window.foo = "bar".

Инструмент линтинга, такой как ESLint, поможет вам обнаружить подобные ошибки, но встроенный строгий режим JavaScript также предотвращает случайное использование глобальных переменных, помечая их как ошибки. Чтобы активировать строгий режим, просто введите "use strict"; в начале любого скрипта или функции, где вы хотите ее использовать. Чтобы узнать о других способах устранения утечек памяти из кода, ознакомьтесь с этой статьей.

Типы в JavaScript

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

По TypeScript есть множество замечательных ресурсов, достаточно сказать, что это отличный способ обеспечить масштабируемость и отсутствие ошибок в вашем коде, и он поможет нам избежать неинтуитивных результатов, которые мы видели выше в разделе о принуждении типов. Расширение файла TypeScript - .ts, также есть эквивалент для .jsx: .tsx. Одна из лучших отправных точек для начинающих - TypeScript за 5 минут.

Также стоит отметить, что существуют решения для аннотаций типов, специфичные для различных технологий JavaScript. Например, вы можете добавить официальный модуль узла PropTypes в свои проекты React. Это позволяет документировать предполагаемые типы данных для свойств, передаваемых компоненту, а также устанавливать значения по умолчанию. PropTypes, особенно в сочетании с линтером вроде ESLint, является мощным дополнением к любой настройке на основе React.

Заключение

В целом, я надеюсь, что эта статья помогла прояснить некоторые различия между языками более низкого уровня, такими как C ++, и языками более высокого уровня JavaScript.

Я также надеюсь, что он снабдил вас инструментами, которые позволят привнести некоторые преимущества C ++ в JavaScript в форме TypeScript или PropTypes и продемонстрировать, что в JavaScript можно влиять на управление памятью и улучшать его.

Если вы хотите узнать больше, я привел несколько ссылок ниже на статьи и ресурсы, которые я нашел наиболее полезными при написании этой статьи. И если вы хорошо разбираетесь в C ++ и хотите узнать больше о том, как реализован JavaScript, лучше всего пойти на официальный сайт V8 или официальный репозиторий Git. Удачного кодирования!

использованная литература

Типы в JavaScript



Типы в C ++



Память в JavaScript







Машинопись



PropTypes