Как стать автором
Обновить

Обработка неопределённых глобальных переменных располагается далёко от здравого смысла! Но её можно превозмочь…

Время на прочтение3 мин
Количество просмотров2.5K
Здравый смысл веборазработчика подсказывает, что во браузерном джаваскрипте глобальные переменные являются свойствами объекта window так что window.чегоНибудь и просто чегоНибудь должны быть синонимами и вести себя одинаково (если, конечно, мы не находимся в какой-нибудь такой функции, где переменную чегоНибудь переопределили локально).

Здравый смысл веборазработчика также ещё подсказывает, что неопределённая переменная должна иметь значение undefined так что чегоНибудь и undefined должны быть синонимами и вести себя одинаково, когда переменную чегоНибудь не определяли в джаваскрипте (и если, конечно, никакой чудила не дерзнул переопределить undefined).

Но если вы собираетесь программировать для Opera 11 (будь то начальная версия Opera 11.01 или новёхонькая Opera 11.61), то будьте готовы отречься от здравого смысла в обоих сих случаях! (Не только в Opera, но и в других браузерах и средах — но об этом чуть позже.)

Чтобы нагляднейше убедиться в этом, воспользуемся библиотекою Underscore.js, в которой как раз имеется удобная функция тестирования неопределённых переменных — это функция _.isUndefined(), в исходном коде определённая самоочевидным способом:

// Is a given variable undefined?
_.isUndefined = function(obj) {
   return obj === void 0;
};

И так как библиотека Underscore.js подключена к собственной странице http://documentcloud.github.com/underscore/, то предлагаю попросту зайти на эту страницу да запустить Opera Dragonfly общеизвестным сочетанием клавиш Ctrl+Shift+I.

Вполне достаточно произвести три теста в консоли Dragonfly, чтобы тотчас коснуться хтонических глубин живейшего ужаса:

[итоги тестирования]

Что же видите вы на этом скриншоте?

Сперва я проверил _.isUndefined(undefined) и получил true разумеется, так тому и следует быть.

Затем я проверил _.isUndefined(чтоНибудь) и это вызвало состояние ошибки в Опере! Мы видим поэтому, что undefined ведёт себя вовсе не так, как обыкновенная неопределённая переменная. Мы также видим нечто более мрачное: Opera не умеет безошибочно передавать неопределённые глобальные переменные (кроме специальной неопределённой переменной undefined) внутрь функций!

И наконец я проверил _.isUndefined(window.чтоНибудь) и вдругорядь получил true! С одной стороны, так тому и следует быть. С другой же стороны, сравнивая с предыдущей проверкою, тотчас видим, что глобальная переменная и одноимённое ей свойство объекта window ведут себя совершенно по-разному, когда не определены: выходит, что свойство можно передать в функцию безошибочно, а с глобальною переменною этого не получится сделать невозбранно.

Для консоли Dragonfly такая строгость и такая готовность искать ошибки — это ещё нормально. Вся проблема в том, что Opera совершенно с той же меркою подходит и к джаваскриптам на вебостраницах, так что функция _.isUndefined() библиотеки Underscore.js становится, в общем-то, бесполезною: к простой глобальной переменной её применить без ошибки не удастся, а если всякий раз пользоваться префиксом «window.», то чего же было огород-то городить? — проще проверять на неопределённость традиционным способом:

typeof чтоНибудь == 'undefined' // традиционный способ
_.isUndefined(window.чтоНибудь) // едва ли короче и проще!

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

_.isUndef = function(name){
   return _.isUndefined(window[name]);
};

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

_.isUndefined(чтоНибудь)  // вызывает ошибку в Opera!
_.isUndef('чтоНибудь')    // записывается короче и работает без ошибки
};

До сих пор я говорил об Opera, но проблема, насколько я её понимаю, значительно шире браузера Opera. Например, нетрудно показать, что всё то же самое свойственно движку Node.JS:

[скриншот NodeJS]

Понятно, что аналог вышеприведённого костыля сможет подпереть проверку неопределённых глобальных переменных и в этом случае — только глобальным объектом в нём потребуется записать не window, а global, как принято в Node.

Здраво подозреваю, что подобный эффект при работе с неопределёнными глобальными переменными вы можете ожидать и в некоторых других приложениях, использующих движок V8 для интерпретации джаваскриптов. В комментариях мне TheShock подсказывает, что браузер Google Chrome относится к числу таких приложений.

Нетрудно убедиться и в том, что в Web Console в Файерфоксе вам также не удастся вызвать код «_.isUndefined(чтоНибудь)» безошибочно. К ошибке джаваскрипта («whatever is not defined») приведёт попытка загрузить в Firefox 11 нижеследующий HTML-код:

<!doctype html>
<script>
isUndefined = function(i){
   return i === void 0;
}
main = function(){
   document.getElementById('b').innerHTML = isUndefined(whatever);
}
</script>
<body id="b" onload="main();">
</body>
</html>

Всюду, всюду неопределённые глобальные переменные придётся проверять перед употреблением их в качестве параметров функций.
Теги:
Хабы:
Всего голосов 33: ↑15 и ↓18-3
Комментарии30

Публикации

Истории

Работа

Ближайшие события