Pull to refresh

Comments 30

По-моему, использование неопределённых глобальных переменных должно бросать ReferenceError, а «здравый смысл веборазработчика» должен обязывать его писать 'use strict', чтобы избежать их непреднамеренного использования.
Есть случаи, когда уместно проверить некоторую глобальную переменную на определённость.

Хорошим примером этого являются гаджеты MediaWiki.

Предположим, что в MediaWiki некоторая функциональность оформлена джаваскриптом (например, именно джаваскриптом подключаются обеспечиваемые службою AddThis кнопки для добавления статьи вики в закладки, в Твиттер, во ВКонтакте, и так далее) — а ещё предположим, что по умолчанию (в частности, для незарегистрированных читателей вики) эта функциональность включена и действует, так что код её уместно располагать в основном скриптовом файле вики.

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

Тогда им проще всего будет также придать этому гаджету форму джаваскрипта, задающего какое угодно (это неважно) значение некоторой глобальной переменной — право же, ничего проще и вообразить нельзя. А в основном коде (который запускает функциональность, доступную по умолчанию) после поступления всего документа тогда будет достаточно сперва проверить, не была ли эта глобальная переменная задана, существует ли она вообще. И если она не существует, то только тогда действовать, в противном же случае бездействовать.
А не кажется ли вам что для описанной вами ситуации отлично подходят куки?
Да нет, не кажется. Куки по определению более сложный и проблемный объект, чем глобальная переменная. Не только как структура данных куки сложнее, но и потому, что даже при включённом джаваскрипте браузер может отказаться принимать куки, тогда как не бывало примера, чтобы при включённом джаваскрипте браузер отказался принимать значение глобальной переменной. Проблема глобальных переменных, как видно, только в том, что чрезмерно строгая обработка ошибок фактически принуждает разработчика иметь с ними дело прежде, чем он передаст глобальную переменную вглубь какой-нибудь функции как параметр.
как структура данных куки сложнее

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

Снова не вижу проблемы, раз браузер отказывается принимать куки, то куки не будет, следовательно код будет вести себя согласно варианту по умолчанию. Вроде бы всё достаточно логично и прозрачно.

Проблема же глобальных переменных в джаваскрипте, на мой взгляд, не в том что вы написали, а в том что это является плохой практикой при работе с ним. Поведение стрикт мода это только подтверждает
Активировать какую-то функциональность, только если не объявлена некая «глобальная переменная»? Почему нельзя просто всегда явно проверять наличие свойства у объекта window? В JS вообще не должно быть никаких «глобальных переменных», переменная либо объявлена через var в каком-то контексте и порождает замыкание (включая window и console, объявленные браузером на самом верху), либо является свойством какого-то определённого объекта, доступного в текущей области видимости.
Нельзя просто всегда явно проверять наличие свойства у объекта window, потому что всегда явно записывать семь символов «window.» — это задалбывает.

Полагаю, Вам хорошо известно также, что переменная далеко не всегда объявлена через var в каком-то контексте: вместо того я могу в любой момент (даже внутри внутренней функции) начертать «globalName = 'someValue'» и это будет работать невозбранно. Вам, как видно, думается, что этого «не должно быть», а я вот, напротив, считаю это удобным в ряде случаев инструментом веборазработки.
Использование такого способа доступа к свойствам обекта window вполне «возбранно» и выпилено в strict mode не без оснований, так как является частым источником ошибок и портит лаконичность ECMAScript.
Assignment to an undeclared identifier or otherwise unresolvable reference does not create a property in the global object. When a simple assignment occurs within strict mode code, its LeftHandSide must not evaluate to an unresolvable Reference. If it does a ReferenceError exception is thrown
(документация)
Насколько я знаю, за такое
globalName = 'someValue'

принято бить по рукам линейкой. Конечно, если относиться к javascript, как к простеньким скриптикам, добавляющим на страницу анимацию, то это ещё, возможно, сгодится. Но в хоть сколько-либо сложных проектах это приводит к страшному хаосу (особенно если не слишком осознанно подходить к именованию переменных).

А если использовать 'use strict'; то вы получите ошибку (и поделом :) ). Да, запись
window.globalName = 'someValue'
несколько длиннее, зато с первого взгляда ясно, что переменная глобальная.

P.S. Netbeans в базовой цветовой схеме отображает «глобалки» зелёным. Как правило код, в котором их много сразу уходит в утиль.
Вы ужé второй комментатор, помянувший 'use strict'. Мне, кажется, есть смысл подчеркнуть в явном виде, что я-то никакого 'use strict' не использовал — и даже, более того, с превеликим удовольствием пробормотал бы какое-нибудь альтернативное заклинание 'use loose', кабы это дало мне возможность в дальнейшем передавать неопределённые глобальные переменные внутрь функций в качестве параметров.
Лучше бы «они» сделали рабочей запись
if( var some = blabla() ){ ... }

Это сэкономило бы уйму строк кода :)
А зачем вам объявлять переменную, область видимости которой только в круглых скобках у if?
Про область видимости я ни слова не написал, подразумевая, что она стандартна для всего javascript-а (var в for работает из за пределами for(… ){} ). Речь идёт о вездесущих:
var some = someFn();
if( some )
{
    ...
    some.blabla
}
Sory. Действительно, для JavaScript этот вопрос не принципиален (могли бы и сделать), т.к. в отличии от например, C++ "{" и "}" не ограничивают область видимости.

Спасибо за ликбез. У меня ни когда даже сомнений не возникало. Да и не возникло бы.
Во всех браузерах ровно такое же поведение, которое соответсвует стандарту. Пример в хроме:
console.log( something == null )
// ReferenceError: something is not defined


Кстати, зачем строго проверять на undefined? Разве не всё-равно, null в переменной или undefined?

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


А на практике доступ к глобальным переменным практически не нужен. А в таком описании, как у автора — не нужен однозначно.

Решить проще всего через конфигурационный объект, который передаётся всем модулям при инициализации
0 == undefined. Если выполняются математические вычисления, то это любит порождать баги, который всплывают не сразу.
Популярное заблуждение людей, перешедших с php. Я знаю, что советую. Проверьте сами:
console.log( undefined == null); // true
console.log( ''        == 0   ); // true
console.log( null      == 0   ); // false
console.log( undefined == 0   ); // false
console.log( null      == ''  ); // false
console.log( undefined == ''  ); // false
Тогда случай, когда не всё равно null там или undefined — не покроет. Undefined — чёткое не определено, как оно есть. Null — обычно какое-то ручное «не установленное значение», но существующее. Но иногда полезно и то, и то, спасибо.
Странные какие-то случаи) Не могу ни одного придумать)
Во всех браузерах ровно такое же поведение, которое соответствует стандарту.
Можете ли Вы указать соответствующее место стандарта ECMA-262? Что поведение такое стало весьма распространённым — это я осознал сегодня.
ECMA-262, edition 5.1
8.7.1 GetValue (V):
  1. If Type(V) is not Reference, return V.
  2. Let base be the result of calling GetBase(V).
  3. If IsUnresolvableReference(V), throw a ReferenceError exception.

IsUnresolvableReference(V). Returns true if the base value is undefined and false otherwise.

Также советую взглянуть на 11.1.2, 10.3.1 и 10.2.2.1

В 3-й редакции всё обстоит похожим делом, только в базе null вместо undefined'а.
(правильная проверка глобальных переменных на неопределённость — typeof a =='undefined'. К глобальным относится тоже. Любая другая проверка не работает, за исключением глобальных переменных и прочих ключей хеша: window['a'] )
правильная проверка глобальных переменных

(хотел сказать, любых переменных. TheShock одновременно сказал то же самое).
Не понимаю негодования автора. Все ситуации, описанные в топике, совершенно логичны и разумны. Более того, использование глобальных переменных должно подразумевать под собой какую-либо серьёзную причину. Просто так сорить ими направо-налево нельзя, т.к. это приводит к страшной каше. Я не против использования глобальных переменных, но делать это необходимо разумно. Проверок вроде if( window.bla_bla_bla ) мне делать почти не приходится, а уж проверять if( typeof window.blabla !== 'undefined' ) мне не приходилось ни разу вовсе (зачем создавать такие странные ситуации? уж не хаоса ли в коде это признак?).

И кстати, по поводу приведённого вами примера с mediawiki. Что мешает сделать так?
window.__config = {};
...
if( __config.use_super_duper_plugin ){ ... }

Вам не кажется что это будет несколько более гибко, нежели:
if( use_super_duper_plugin ) { ... }

Лично я стараюсь каждую новую ситуацию обработать так, чтобы все похожие случаи, которые могут встретиться в будущем, уже легли в готовую колею.
Проверок вроде if( window.bla_bla_bla ) мне делать почти не приходится, а уж проверять if( typeof window.blabla !== 'undefined' ) мне не приходилось ни разу вовсе (зачем создавать такие странные ситуации? уж не хаоса ли в коде это признак?).

Обычно такие ситуации встречаются, когда пишутся плагины. Например, для tinyMCE
С tinyMCE не сталкивался, использую CKeditor, но всё же не понимаю, зачем там использовать window. Неужели нет никакого объекта аля TinyMCE.plugin.somPlugin? Конструкцию typeof some !== 'undefined' я использую нередко, но ведь window то использовать совсем не обязательно )
Ничего себе. В 2012 мы ВНЕЗАПНО узнаем что JS-движки кидают эксепшен при обращении к неопределенной переменной!

Какой плохой браузер опера, делает все как надо по стандартам.

Кроме того, myVar и window.myVar никогда не были синонимами. Как минимум потому, что первое — обращение к переменной, которое может сломаться, если переменная неопределена, а второе — обращение к свойству объекта, которое мирно выдаст undefined и поедет дальше. Разные подходы, разные результаты.

Это свойство часто используется при написании мульти-плагинов. Например, для работы с jQuery, zepto и ender можно написать так:

!function($){
  $.fn.myPlugin = something;
}(window.jQuery || window.zepto || window.ender);


Так делал Twitter Bootstrap до версии 1.4
Какая-то очень странная статья. Все браузеры кидают эксепшен при обращении к несуществующим переменным, а не только Опера.

Чтобы не было ошибок надо обращаться через window потому что это будет lookup свойств объекта а не резолв переменной. А если обращений к глобальным переменным много из какой-то функции, то для лучшей производительности лучше сделать локальную переменную для window.

Да и вообще как бы ни были быстры вызовы функций делать функцию для проверки на undefined это плохо…
Sign up to leave a comment.

Articles