четвер, 28 березня 2013 р.

Сложение, конкатенация и динамическая типизация


Дама сдавала в багаж:
Диван, Чемодан, Саквояж,
Картину, Корзину, Картонку
И маленькую собачонку.



Лирика

Динамическая типизация мне нравится. Хоть иногда это и приводит к ошибкам, которые выявляются только на этапе выполения и сверки результатов, а не на этапе компиляции, как в языках со строгой типизацией, но удобство трудно переоценить.
Ещё со времён строготипизированного Pascal я помню этот кошмар с кучей определённых переменных в самом начале программы... Больше всего я не любил выдумывать имена переменных. И сейчас не люблю, это для меня самое сложное :) То ли дело PHP, придумал один раз $result и потом использовал десять раз, однажды для результата типа array, а другой раз — Object, и ни кто не в обиде.


Практика

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

result1 = 'string' + key + 2
result2 = key + 2 + 'string'
result3 = key + 'string' + 2
result4 = key + 2
result5 = key + '2' + 3 + 4

Создатели JavaScript сэкономили оператор и решили объединить конкатенацию и сложение одним оператором, дескать, для строк это будет конкатенация, а для числовых данных — сложением. Видимо тоже, как и я, не любили придумывать названия или обозначения. Или решили не плодить сущностей сверх необходимого. «Ну а поскольку строгой типизации нет, то ещё и всякие там строки с цифрами будем приравнивать к числовым» подумали они, а может не думали даже, а сразу сделали, как это иногда бывает. А в результате получилось следующее:
доставай, читатель, свой листочек с результатами вычислений, будем проверять.

result1 = 'string' + key + 2 // "string12"
result2 = key + 2 + 'string' // "3string"
result3 = key + 'string' + 2 // "1string2"
result4 = key + 2 // 3
result5 = key + '2' + 3 + 4 // "1234"

0_о, подумал я тогда.
И ещё пример того, как работает приведение типов:

isempty = []
isempty == false // true
!isempty // false


Всему этому есть объяснение и это не баг, а работает «как планировалось», но «даже объяснять лень» ©, цель данного повествования призвать обратить пристальное внимание на автоманическое приведение типов в JavaScript.

А для примера приведу аналогичные примеры на php. Однако в PHP на операторе конкатенации не сэкономили, поэтому «+» остался чистым сложением, однако не без интересных моментов:



$key = 1;
$result1 = 'string' + $key + 2; // 3
$result2 = $key + 2 + 'string'; // 3
$result3 = $key + 'string' + 2; // 3
$result4 = $key + 2; // 3
$result5 = $key + '2' + 3 + 4; // 10
$result6 = '10 meters' + '5 hours' + 'not 3 volts'; // 15
$isempty = array();
$result7 = $isempty == false; // true
$result8 = !$isempty; // true



И почему мне кажется, что именно это более логично? Поскольку «+» остался чистым сложением, то в первых трёх случаях строка приводится к 0, в пятом случае строка '2' приводится к 2, и далее по плану. Примечателен случай 6: в строках отбрасываюся символы, идущие после цифр, но если строка не начинается с цифры, то дальше она не обрабатывается, а приводится к 0.

Конкретика

Не доверяйте JavaScript приводить типы на своё усмотрение или знайте досконально как там что будет приводиться. Но для понятности я бы рекомендовал использовать принудительное приведение типов. В руководствах для приведения к числу ркомеднуют (!) использовать вычитание нуля из строки (Важно: не сложение с нулём по причине конкатенации) или умножение на один, или деление на один. Однако есть более наглядный способ (и самый медленный):
Number(stringvar)
Аналогично для Boolean и String
Так же можно воспользоваться функциями parseInt() и parseFloat()
В PHP принудительное приведение типа выполняется следующим образом:
$intvar = (int) '9000 over'; // или (integer)
аналогично (bool), (boolean); (float), (double), (real); (string); (array); (object); (unset);
Подробнее: Type Juggling
Или же использовать функцию settype

Немає коментарів:

Дописати коментар

Не обязательно регистрироваться, вы наверняка уже зарегистрированы в одном из сервисов, который предоставляет OpenId, предлагаю воспользоваться им. Подробнее: http://openid.net/what/