JS ++ | Тип Система

Опубликовано: 10 Апреля, 2022

RGBtoHex: использование JavaScript из JS ++

Мы собираемся создать два файла, файл JavaScript и файл JS ++, чтобы показать, как они взаимодействуют друг с другом. Мы собираемся использовать классический пример «rgbToHex», чтобы понять гарантии типа JS ++.

Сначала создайте файл с именем rgbtohex.js (JavaScript) и введите следующий код:

(Не беспокойтесь о попытках понять этот код JavaScript. Мы будем использовать его только в качестве примера.)

function rgbToHex (красный, зеленый, синий) {
    если (typeof красный! == "число")   
      throw new TypeError («Ожидаемое числовое« красное »значение»);
    if (typeof зеленый! == "число") 
      throw new TypeError («Ожидаемое числовое« зеленое »значение»);
    if (typeof blue! == "число")  
      throw new TypeError («Ожидаемое числовое« синее »значение»);

    если (красный <0 || красный> 255)     
      throw new RangeError ("Ожидаемое красное значение от 0 до 255 (включительно)");
    если (зеленый <0 || зеленый> 255)   
      throw new RangeError («Ожидаемое« зеленое »значение от 0 до 255 (включительно)»);
    если (синий <0 || синий> 255)    
      throw new RangeError («Ожидаемое« синее »значение от 0 до 255 (включительно)»);

    var r = red.toString (16);
    var g = green.toString (16);
    var b = blue.toString (16);

    в то время как (r.length <2) r = "0" + r;
    в то время как (g.length <2) g = "0" + g;
    в то время как (b.length <2) b = "0" + b;

    вернуть "#" + r + g + b;
}

Сохраните приведенный выше код JavaScript в rgbtohex.js и создайте новый файл main.jspp:

внешнее оповещение;
внешний rgbToHex;

предупреждение (rgbToHex (255, 255, 255));

Начнем с объявления «оповещения» как «внешнего». «alert» на самом деле является встроенной функцией веб-браузеров (через «DOM API»), которая позволяет нам отображать окна сообщений. Затем мы объявляем нашу пользовательскую функцию JavaScript, которую мы только что написали («rgbToHex»), как «внешнюю». Это позволяет нам использовать функцию из JS ++.

Скомпилируйте main.jspp. Теперь создайте файл index.html:

<! DOCTYPE html>
<head>
    <title> Преобразование RGB в шестнадцатеричное </title>
</head>
<body>
<script src = "rgbtohex.js"> </script>
<script src = "main.jspp.js"> </script>
</body>
</html>

Убедитесь, что тег <script> для зависимости JavaScript (rgbtohex.js) написан до тега <script> скомпилированного JS ++ файла main.jspp.js.

Откройте index.html в своем браузере. Вы должны увидеть такое окно сообщения:

В результате получается значение «#ffffff», которое является эквивалентным шестнадцатеричным цветовым кодом для значения RGB (255, 255, 255), значений, которые мы ввели в main.jspp.

Мы только что успешно использовали специальную функцию JavaScript, которую написали на JS ++.

Тип Гарантии

«Гарантии типов» - это уникальная особенность JS ++, которая означает, что ваши типы гарантированно будут правильными во время анализа во время компиляции и выполнения кода времени выполнения, даже если вы загрязняете свой код JS ++ нетипизированным кодом JavaScript. Это самое близкое к типовой безопасности более безопасных языков, которым не приходится иметь дело с большими коллекциями нетипизированного кода.

Когда вы используете такие ключевые слова, как 'external', 'var' или 'function', вы соответственно получаете импорт, переменные и функции, которые являются «внешними типами», не типизированы и не отмечены. Другими словами, вы просто пишете JavaScript внутри JS ++. Однако, когда вы объявляете переменные и функции с типом JS ++, таким как 'int', 'string', 'bool', 'short' или 'unsigned int', они называются «внутренними типами» и гарантированно являются правильными. .

Когда «внешние типы» переходят территорию «внутренних типов», генерируется преобразование среды выполнения:

var x = 123;
int y = x; // 'x' преобразуется в 'int', поэтому 'y' гарантированно будет 'int'

Благодаря преобразованию мы гарантированно всегда будем правильно работать с типами. Мы продолжим исследовать, как эта концепция работает на практике, в этой и следующей главе, но сначала давайте посмотрим, как это применимо к нашему конвертеру RGB в Hex.

Ключевое понятие

В JS ++ ключевая концепция, которую необходимо понять, состоит в том, что JS ++ разделяет типы данных на «внутренние» типы и «внешние» типы. Внутренние типы данных - это типы данных JS ++: int, string, bool, unsigned int, типы массивов, словари и определяемые пользователем типы (которые мы рассмотрим в главе 11). Внешние типы - это типы данных JavaScript.

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

Значения RGB

Цветовая модель RGB определяет три цветовых значения: красный, синий и зеленый. Эти значения цвета являются числовыми и должны соответствовать диапазону 0–255. JS ++ на самом деле имеет тип данных, который точно соответствует спецификации числового и гарантирует, что числа находятся в диапазоне 0–255: тип данных «байт».

Благодаря гарантиям типов, когда мы объявляем тип данных в JS ++, он может изменить поведение нашей программы во время выполнения - почти так же, как это было бы в C, C ++, Java, C # и многих других языках программирования со статической типизацией. Следовательно, если мы определяем RGB как ожидаемые байтовые значения в диапазоне от 0 до 255, мы гарантируем, что эти значения будут числовыми и будут находиться в диапазоне от 0 до 255 во время анализа во время компиляции и выполнения приложения во время выполнения.

Например, во время анализа во время компиляции и проверки ошибок компилятор выдаст вам ошибку, если вы случайно попытаетесь передать 'int', где ожидался 'byte', поскольку 'int' допускает числа вне диапазона от 0 до 255.

Точно так же во время выполнения, когда ваше приложение работает, переменные, которые вы объявили как «байтовые», гарантированно никогда не будут равны 256. Это означает, что мы никогда не сможем получить недопустимые значения RGB. (Для разработчиков, работающих с такими фонами, как C или C ++, вам также гарантировано, что 'unsigned int' никогда не будет -1 во время выполнения, потому что беззнаковое и подписанное переполнение приводит к целочисленному переносу.)

Изучение нетипизированного JavaScript

Значения RGB должны находиться в диапазоне от 0 до 255. Поскольку в JavaScript отсутствуют типы данных, мы должны выполнять эти проверки вручную. Давайте посмотрим, как мы справляемся с этим в нашей функции JavaScript rgbToHex.

Первые три строки нашей функции JavaScript 'rgbToHex' проверяют числа:

    если (typeof красный! == "число")   
       throw new TypeError («Ожидаемое числовое« красное »значение»);
    if (typeof зеленый! == "число") 
       throw new TypeError («Ожидаемое числовое« зеленое »значение»);
    if (typeof blue! == "число")  
       throw new TypeError («Ожидаемое числовое« синее »значение»);

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

Следующие три строки проверяют, соответствуют ли эти числа диапазону от 0 до 255:

    если (красный <0 || красный> 255)     
      throw new RangeError ("Ожидаемое красное значение от 0 до 255 (включительно)");
    если (зеленый <0 || зеленый> 255)   
      throw new RangeError («Ожидаемое« зеленое »значение от 0 до 255 (включительно)»);
    если (синий <0 || синий> 255)    
      throw new RangeError («Ожидаемое« синее »значение от 0 до 255 (включительно)»);

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

Однако зачем допускать ошибки времени выполнения во время выполнения приложения? В JS ++ эти ошибки можно проверить без запуска программы - во время компиляции.

Более безопасное использование JavaScript

Вы можете более безопасно использовать JavaScript из JS ++, чем из самого JavaScript.

Начнем с изменения нашего кода main.jspp, чтобы явно использовать тип данных byte:

внешнее оповещение;
внешний rgbToHex;

байт красный = 255;
байт зеленый = 255;
байт синий = 255;
предупреждение (rgbToHex (красный, зеленый, синий));

Скомпилируйте main.jspp и откройте index.html. Результат должен быть точно таким же: появится окно сообщения, содержащее «#ffffff». Однако на этот раз есть разница: вы гарантированно сможете отправлять только целые числа в диапазоне от 0 до 255.

Помните все эти проверки в функции JavaScript, чтобы убедиться, что мы получили приемлемые входные значения RGB? Если были указаны неверные значения, сценарий остановит выполнение приложения, выдав исключения. Все эти потенциальные ошибки были устранены с помощью JS ++ и объявления типов. Эти ошибки были устранены, несмотря на то, что мы не изменили ни один исходный код JavaScript. Ошибки времени выполнения все еще присутствуют в коде JavaScript, но они никогда не будут выполнены, потому что введенные нами входные значения всегда будут правильными.

Попробуйте изменить одну из «красных», «зеленых» или «синих» переменных на число вне диапазона от 0 до 255:

внешнее оповещение;
внешний rgbToHex;

байт красный = -1;
байт зеленый = 255;
байт синий = 255;
предупреждение (rgbToHex (красный, зеленый, синий));

Теперь попробуйте скомпилировать измененный файл main.jspp. Вы получите сообщение об ошибке:

 [ОШИБКА] JSPPE5013: вычисленное значение «-1» вне диапазона для типа «byte» в строке 4 char 11 в main.jspp

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

Переместить rgbToHex в JS ++

Во-первых, давайте прекратим импорт функции JavaScript «rgbToHex», удалив «внешний» оператор, который ее импортирует. Теперь наш файл main.jspp должен выглядеть так:

внешнее оповещение;

предупреждение (rgbToHex (255, 255, 255));

Не пытайтесь компилировать прямо сейчас. Мы скомпилируем, как только переместим весь код JavaScript.

Функция JavaScript «rgbToHex» зависит от «TypeError» (встроенного в JavaScript) и «RangeError» (также встроенного в JavaScript). Давайте импортируем это:

внешнее оповещение;
внешний TypeError, RangeError;

предупреждение (rgbToHex (255, 255, 255));

Наконец, мы можем просто скопировать и вставить код из rgbToHex.js (файл JavaScript) в main.jspp (файл JS ++):

внешнее оповещение;
внешний TypeError, RangeError;

function rgbToHex (красный, зеленый, синий) {
    если (typeof красный! == "число")   
        throw new TypeError («Ожидаемое числовое« красное »значение»);
    if (typeof зеленый! == "число") 
        throw new TypeError («Ожидаемое числовое« зеленое »значение»);
    if (typeof blue! == "число")  
        throw new TypeError («Ожидаемое числовое« синее »значение»);
 
    если (красный <0 || красный> 255)     
        throw new RangeError ("Ожидаемое красное значение от 0 до 255 (включительно)");
    если (зеленый <0 || зеленый> 255)   
        throw new RangeError («Ожидаемое« зеленое »значение от 0 до 255 (включительно)»);
    если (синий <0 || синий> 255)    
        throw new RangeError («Ожидаемое« синее »значение от 0 до 255 (включительно)»);
 
    var r = red.toString (16);
    var g = green.toString (16);
    var b = blue.toString (16);
 
    в то время как (r.length <2) r = "0" + r;
    в то время как (g.length <2) g = "0" + g;
    в то время как (b.length <2) b = "0" + b;
 
    вернуть "#" + r + g + b;
}

предупреждение (rgbToHex (255, 255, 255));

Теперь мы можем скомпилировать код. Он должен успешно скомпилироваться. Откройте index.html в своем веб-браузере, и вы должны заметить, что в результате по-прежнему отображается окно сообщения с надписью «#ffffff».

Мы просто скопировали большой кусок кода JavaScript прямо в JS ++, и это сработало. Это потому, что JS ++ - это надмножество JavaScript; другими словами, это просто JavaScript с большим количеством функций.

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

Преобразование «нетипизированного» JavaScript в «типизированный» JS ++

Мы начнем преобразовывать нашу функцию JavaScript 'rgbToHex' в JS ++, удалив все проверки и ошибки во время выполнения. Они вам больше не понадобятся.

Ваш файл main.jspp теперь должен выглядеть так:

внешнее оповещение;

function rgbToHex (красный, зеленый, синий) {
    var r = red.toString (16);
    var g = green.toString (16);
    var b = blue.toString (16);
 
    в то время как (r.length <2) r = "0" + r;
    в то время как (g.length <2) g = "0" + g;
    в то время как (b.length <2) b = "0" + b;
 
    вернуть "#" + r + g + b;
}

предупреждение (rgbToHex (255, 255, 255));

Удалив проверки и ошибки во время выполнения, мы действительно можем улучшить потенциальную производительность. Очевидное наблюдение состоит в том, что в целом требуется обрабатывать меньше инструкций. Однако, удаляя все операторы if, мы улучшаем параллелизм на уровне инструкций на аппаратном уровне (ЦП) и уменьшаем вероятность неправильного предсказания переходов. (Эти оптимизации могут применяться или не применяться из-за наличия всех дополнительных уровней абстракции в сценариях браузера. На данный момент достаточно знать, что мы уменьшили общее количество операций.)

Поскольку мы удалили проверки и ошибки во время выполнения, наш код теперь полностью отключен! Попробуйте вызвать 'rgbToHex' с недопустимым значением, например 256. Вы увидите, что это разрешено. Давай исправим это.

Добавьте «байт» перед каждым параметром, чтобы ограничить их типы данных:

внешнее оповещение;

function rgbToHex ( байт красный, байт зеленый, байт синий) {
    var r = red.toString (16);
    var g = green.toString (16);
    var b = blue.toString (16);
 
    в то время как (r.length <2) r = "0" + r;
    в то время как (g.length <2) g = "0" + g;
    в то время как (b.length <2) b = "0" + b;
 
    вернуть "#" + r + g + b;
}

предупреждение (rgbToHex (255, 255, 255));

Скомпилируйте main.jspp и откройте index.html. Как обычно, вы увидите окно сообщения с надписью «#ffffff».

Теперь попробуйте снова вызвать функцию rgbToHex с недопустимым значением, например -1 или 256. Вы больше не сможете компилировать код, потому что ошибки будут обнаружены во время компиляции.

Добавить больше типов

Наша функция rgbToHex по-прежнему объявлена с ключевым словом function. Это способ объявления функции в JavaScript, и он по-прежнему оставляет нашу функцию небезопасной.

В JS ++ рекомендуется всегда объявлять типы данных, когда это возможно. Поскольку мы всегда возвращаем строковое значение для нашей функции «rgbToHex», мы должны ограничить возвращаемый тип «строкой».

внешнее оповещение;

string rgbToHex (байт красный, байт зеленый, байт синий) {
    var r = red.toString (16);
    var g = green.toString (16);
    var b = blue.toString (16);
 
    в то время как (r.length <2) r = "0" + r;
    в то время как (g.length <2) g = "0" + g;
    в то время как (b.length <2) b = "0" + b;
 
    вернуть "#" + r + g + b;
}

предупреждение (rgbToHex (255, 255, 255));

Теперь все операторы return внутри функции должны возвращать выражение, которое оценивается как строковые данные.

И последнее, но не менее важное: взгляните на эти утверждения:

var r = red.toString (16);
var g = green.toString (16);
var b = blue.toString (16);

Какие методы вызываются?

Помните, что во многих случаях программирование типов в JavaScript основано на интуиции. (Система типов JS ++ строится на основе этой интуиции, поэтому программирование на JS ++ должно казаться естественным продолжением для разработчиков JavaScript.) В каждом из приведенных выше операторов вызывается toString (16). Другими словами, мы знаем, что нам следует ожидать строковых данных. Тогда давайте изменим нашу 'var' на 'string':

внешнее оповещение;

string rgbToHex (байт красный, байт зеленый, байт синий) {
    строка r = red.toString (16);
    строка g = green.toString (16);
    строка b = blue.toString (16);
 
    в то время как (r.length <2) r = "0" + r;
    в то время как (g.length <2) g = "0" + g;
    в то время как (b.length <2) b = "0" + b;
 
    вернуть "#" + r + g + b;
}

предупреждение (rgbToHex (255, 255, 255));

Скомпилируйте main.jspp. Удалите файл JavaScript rgbtohex.js. Отредактируйте index.html, чтобы полностью удалить ссылку на файл JavaScript rgbtohex.js. Теперь ваш код index.html должен выглядеть так:

<! DOCTYPE html>
<head>
    <title> Преобразование RGB в шестнадцатеричное </title>
</head>
<body>
<script src = "main.jspp.js"> </script>
</body>
</html>

Откройте index.html в своем браузере. Вы должны увидеть окно сообщения с «#ffffff». Поздравляю! Вы только что изменили функцию JavaScript на JS ++.

Прочие соображения

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

Однако не всегда существует совместимый тип JS ++ для всех значений JavaScript. Это можно проиллюстрировать с помощью jQuery. Например, давайте еще раз обратимся к примеру с циклами из главы 5:

внешний $;

for (int i = 0; i <2; i ++) {
    $ ("# content"). append ("я сейчас", я, ";");
}

Это интересный пример, потому что он охватывает многое. Прежде всего, что, если бы мы хотели разбить вызов метода jQuery, чтобы выбор #content (элемент страницы с идентификатором «content») сохранялся в переменной? Здесь нет совместимого типа JS ++, поэтому мы можем просто использовать var:

внешний $;

for (int i = 0; i <2; i ++) {
    var content = $ ("# содержание");
    content.append («я сейчас», я, «;»);
}

Теоретически лучше не иметь небезопасного кода. Однако на практике для совместимости с JavaScript необходимы «external», «var» и «function». Другими словами, нужны внешние типы. В идеале мы бы никогда не использовали внешние элементы в «идеальном коде JS ++», но реальное программирование почти никогда не бывает идеальным.

Проницательный наблюдатель мог также заметить обратное преобразование: из внутреннего во внешнее. Мы объявили переменную счетчика цикла for i как int, внутренний тип JS ++. Однако, когда мы передаем его в качестве аргумента jQuery, он преобразуется во «внешний»:

 content.append («я сейчас», я, «;»);

По умолчанию «примитивные типы» (такие как int, string, bool, unsigned int и т. Д.) Имеют неявные преобразования по умолчанию, определенные во внешнее и обратно. Это связано с тем, что JavaScript имеет естественные совместимые типы данных для внутренних примитивных типов JS ++. Таким образом, конверсия тоже естественна. С пользовательскими типами и пользовательскими преобразованиями все становится сложнее, но мы рассмотрим их в следующих главах.

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

внешнее оповещение;

void messageBox (строковое сообщение) {
    оповещение (сообщение);
}

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

Заключительное примечание

Зачем нужны гарантии типа JS ++? Потому что с небезопасным JavaScript даже на крупных веб-сайтах с ресурсами, таких как GoDaddy, могут возникнуть проблемы с оформлением заказа, что приведет к потере продаж из-за единственной ошибки TypeError:

В приведенном выше примере кнопка «Продолжить» никогда не работает, поэтому оформление покупки в тележке не может быть завершено.

Любопытно, что сбой при проверке происходит из-за того же метода toLowerCase, который мы исследовали в главе 9. Поскольку JS ++ - единственный надежный, постепенно типизируемый язык программирования для JavaScript, гарантии типа означают больше, чем просто добавление «типов» в JavaScript. Это означает, что типы гарантированно будут правильными при их объявлении, и нет крайних случаев, которые могут привести к сбоям во время выполнения (в отличие от попыток добавить типы данных со стороны Microsoft и Facebook).

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