JavaScript: Слабая типизация
Нам известно про два разных типа данных: числа и строки. Мы, например, можем складывать числа, потому что операция сложения — это операция для типа «числа».
А что, если применить эту операцию не к двум числам, а к числу и строке?
console.log(1 + '7'); // => 17Несмотря на то что '7' — это строка, а не число, интерпретатор JavaScript выдал ответ '17', как если бы мы складывали две строки. Когда JavaScript видит несоответствие типов, он сам пытается преобразовать информацию. В данном случае он преобразовал число 1 в строку '1', а потом спокойно сделал конкатенацию '1' и '7'.
Слабая типизация
Не все языки так делают. JavaScript — это язык со слабой типизацией. Он знает о существовании разных типов (числа, строки и другие), но относится к их использованию не очень строго и пытается преобразовывать данные, когда это кажется ему разумным.
Иногда JavaScript доходит до крайностей. Большинство выражений, которые не работают в других языках, в JavaScript отрабатывают. Попробуйте выполнить любую арифметическую операцию, кроме сложения, подставив туда строки — вы увидите, что код выполнится и вернёт NaN (Not a Number):
console.log('one' * 'two'); // => NaN1 + '7' → '17' (число превратилось в строку, конкатенация)
'7' - 1 → 6 (строка превратилась в число, вычитание)
'one' * 2 → NaN (строку нельзя превратить в число)А как в строгих языках?
В языках со строгой (сильной) типизацией сложить число со строкой не получится — программа остановится с ошибкой. Например, в Python или Ruby выражение 1 + '7' приведёт к ошибке типов: язык требует, чтобы вы явно указали, как преобразовать данные.
При этом языки не делятся ровно на два лагеря — «строгие» и «слабые». Корректнее говорить, что у разных языков разная степень строгости: где-то неявных преобразований почти нет, а где-то их много. JavaScript находится у «слабого» края этой шкалы.
Статическая и динамическая типизация
Есть и другое, отдельное понятие — статическая и динамическая типизация. Оно описывает, когда проверяются типы. JavaScript относится к динамически типизированным языкам: типы проверяются во время работы программы. В статически типизированных языках проверка обычно происходит раньше, ещё до запуска кода.
Важно не путать две вещи:
- статическая/динамическая типизация отвечает на вопрос «когда проверяются типы»;
- сильная/слабая типизация отвечает на вопрос «что произойдёт, если смешать разные типы без явного преобразования».
Это независимые свойства. JavaScript — язык динамический и слабо типизированный.
Почему JavaScript такой
JavaScript был создан для интернета, а в интернете вся информация — это строки. Даже когда вы вводите на сайте номер телефона или год рождения, на сервер эти данные приходят не как числа, а как строки. Поэтому авторы языка решили, что автоматически преобразовывать типы — удобно.
Удобство есть, но у него высокая цена. На практике неявные преобразования создают множество ошибок, которые трудно найти: код может иногда работать, а иногда нет — в зависимости от того, «повезло» ли в конкретном случае с автоматическим преобразованием. Программист замечает это не сразу.
В дальнейших заданиях вы будете встречаться с таким поведением не раз. Часто будет возникать вопрос: «почему мой код работает не так, как я ожидаю?». Слабая типизация красной нитью проходит сквозь всю разработку на JavaScript.
Задание
Выведите на экран результат выражения: 7 - (-8 - -2). Попробуйте сделать число 7 не числом, а строкой. Поэкспериментируйте с другими числами тоже.
Полезное
JavaScript: Слабая типизация
Нам известно про два разных типа данных: числа и строки. Мы, например, можем складывать числа, потому что операция сложения — это операция для типа «числа».
А что, если применить эту операцию не к двум числам, а к числу и строке?
console.log(1 + '7'); // => 17Несмотря на то что '7' — это строка, а не число, интерпретатор JavaScript выдал ответ '17', как если бы мы складывали две строки. Когда JavaScript видит несоответствие типов, он сам пытается преобразовать информацию. В данном случае он преобразовал число 1 в строку '1', а потом спокойно сделал конкатенацию '1' и '7'.
Слабая типизация
Не все языки так делают. JavaScript — это язык со слабой типизацией. Он знает о существовании разных типов (числа, строки и другие), но относится к их использованию не очень строго и пытается преобразовывать данные, когда это кажется ему разумным.
Иногда JavaScript доходит до крайностей. Большинство выражений, которые не работают в других языках, в JavaScript отрабатывают. Попробуйте выполнить любую арифметическую операцию, кроме сложения, подставив туда строки — вы увидите, что код выполнится и вернёт NaN (Not a Number):
console.log('one' * 'two'); // => NaN1 + '7' → '17' (число превратилось в строку, конкатенация)
'7' - 1 → 6 (строка превратилась в число, вычитание)
'one' * 2 → NaN (строку нельзя превратить в число)А как в строгих языках?
В языках со строгой (сильной) типизацией сложить число со строкой не получится — программа остановится с ошибкой. Например, в Python или Ruby выражение 1 + '7' приведёт к ошибке типов: язык требует, чтобы вы явно указали, как преобразовать данные.
При этом языки не делятся ровно на два лагеря — «строгие» и «слабые». Корректнее говорить, что у разных языков разная степень строгости: где-то неявных преобразований почти нет, а где-то их много. JavaScript находится у «слабого» края этой шкалы.
Статическая и динамическая типизация
Есть и другое, отдельное понятие — статическая и динамическая типизация. Оно описывает, когда проверяются типы. JavaScript относится к динамически типизированным языкам: типы проверяются во время работы программы. В статически типизированных языках проверка обычно происходит раньше, ещё до запуска кода.
Важно не путать две вещи:
- статическая/динамическая типизация отвечает на вопрос «когда проверяются типы»;
- сильная/слабая типизация отвечает на вопрос «что произойдёт, если смешать разные типы без явного преобразования».
Это независимые свойства. JavaScript — язык динамический и слабо типизированный.
Почему JavaScript такой
JavaScript был создан для интернета, а в интернете вся информация — это строки. Даже когда вы вводите на сайте номер телефона или год рождения, на сервер эти данные приходят не как числа, а как строки. Поэтому авторы языка решили, что автоматически преобразовывать типы — удобно.
Удобство есть, но у него высокая цена. На практике неявные преобразования создают множество ошибок, которые трудно найти: код может иногда работать, а иногда нет — в зависимости от того, «повезло» ли в конкретном случае с автоматическим преобразованием. Программист замечает это не сразу.
В дальнейших заданиях вы будете встречаться с таким поведением не раз. Часто будет возникать вопрос: «почему мой код работает не так, как я ожидаю?». Слабая типизация красной нитью проходит сквозь всю разработку на JavaScript.
Задание
Выведите на экран результат выражения: 7 - (-8 - -2). Попробуйте сделать число 7 не числом, а строкой. Поэкспериментируйте с другими числами тоже.
Полезное
Ваше упражнение проверяется по этим тестам
// @ts-check
import { expect, test, vi } from 'vitest';
test('data types weak typing', async () => {
const consoleLogSpy = vi.spyOn(console, 'log');
await import('./index.js');
const firstArg = consoleLogSpy.mock.calls.join('\n');
expect(firstArg).toBe('13');
});Решение учителя откроется через:
20:00
