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

в 11:40, , рубрики: javascript, node.js, nodejs, underscore, Underscore.js, Веб-разработка, здравый смысл, метки: , , , , ,

Здравый смысл веборазработчика подсказывает, что во браузерном джаваскрипте глобальные переменные являются свойствами объекта 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 такая строгость и такая готовность искать ошибки — это ещё нормально (ведь, как нетрудно убедиться, и из Web Console в Файерфоксе вам также не удастся вызвать код «_.isUndefined(чтоНибудь)» безошибочно!…). Вся проблема в том, что 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 для интерпретации джаваскриптов.

Автор: Mithgol


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js