Как мне определить «пространство имен» JavaScript для удовлетворения JSLint? - PullRequest
20 голосов
/ 20 февраля 2010

Я хочу иметь возможность упаковать свой код JavaScript в «пространство имен», чтобы предотвратить конфликт имен с другими библиотеками. Поскольку объявление пространства имен должно быть простым фрагментом кода, я не хочу зависеть от каких-либо внешних библиотек, чтобы предоставить мне эту функциональность. Я нашел несколько советов о том, как сделать это просто, но ни один из них не свободен от ошибок при запуске через JSLint (с использованием параметров «Хорошие детали»).

В качестве примера я попробовал это из Advanced JavaScript (раздел Пространства имен без YUI):

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    MyNamespace = {};
}

Выполнение этого через JSLint дает следующие ошибки:

Problem at line 2 character 12: 'MyNamespace' is not defined.
Problem at line 3 character 5: 'MyNamespace' is not defined.
Implied global: MyNamespace 2,3

Ошибка «Предполагаемая глобальная» может быть исправлена ​​явным объявлением MyNamespace ...

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    var MyNamespace = {};
}

... и две другие ошибки можно исправить, объявив переменную вне блока if.

"use strict";
var MyNamespace;
if (typeof(MyNamespace) === 'undefined') {
    MyNamespace = {};
}

Так что это работает, но мне кажется, что (поскольку MyNamespace всегда будет неопределенным в момент проверки?), Это эквивалентно гораздо более простому:

"use strict";
var MyNamespace = {};

JSLint доволен этим, но я обеспокоен тем, что упростил код до такой степени, что он больше не будет корректно функционировать как пространство имен. Является ли эта окончательная формулировка разумной?

Ответы [ 6 ]

18 голосов
/ 20 февраля 2010

Не воспринимайте слово Дж.С.Линта как Евангелие. Многое из того, что он говорит, разумно, но оно также сопровождается личными догмами Крокфорда. В частности, я не всегда согласен с ним о лучшем месте для var.

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    MyNamespace = {};
}

Это не хорошо; JSLint правильно жаловаться на подразумеваемый глобальный. 'use strict' требует, чтобы вы не подразумевали глобалы.

"use strict";
if (typeof(MyNamespace) === 'undefined') {
    var MyNamespace = {};
}

Отлично. var поднят, поэтому MyNamespace присутствует и устанавливается на undefined при входе в блок кода. Таким образом, вы можете выполнить этот тест как (MyNamespace===undefined) даже без магической способности оператора typeof, позволяющей вам ссылаться на несуществующие переменные.

Другой способ заключается в использовании однозначного оператора in (который является единственным способом отличить отсутствующее свойство от того, которое присутствует, но установлено на undefined). В случае глобальных переменных в обычном скрипте браузера вы можете использовать его для глобального window объекта:

'use strict';
if (!('MyNamespace' in window)) {
    window.MyNamespace = {};
}

(JSLint это тоже не нравится, так как «предположим, что браузер», по-видимому, не определяет window по какой-то непостижимой причине.

7 голосов
/ 15 февраля 2011

Вы можете попробовать намного более короткую версию:

var MyNamespace = MyNamespace || {};

Это должно быть допустимо в JSLint, даже в строгом режиме, используя имя, если оно уже существует, и создавая его, если его нет, так как лучше всего ожидать, что пространство имен в JavaScript будет работать.

6 голосов
/ 03 ноября 2013

Это ДЕЙСТВИТЕЛЬНО старый вопрос, но я подумал, что все равно отвечу, поскольку ни один из вышеперечисленных вопросов не очистил все ошибки jslint для меня, потому что я подозреваю, что lint'r был обновлен :-)

Возможно, есть другие способы сделать это, но с 2013 года это лучшее, что я могу придумать

Если вам нужен безошибочный шаблон модуля jsLint с пространством имен и строгим режимом, см. Ниже

Предполагая, что это содержится в каком-то файле .js ...

this.ns = this.ns || {}; // Check for global namespace and if not found create 

(function(ns) {
  'use strict'   // restrict usage to this module 

  ns.myFunction = function() {
  } 

} (this.ns)); // Pass in the global namespace you 'might' have created above and 
              // drop 'this' reference

'this' необходимо, чтобы избежать ошибки, выходящей за рамки видимости (кажется, что это не должно иметь значения, но я предполагаю, что использование 'this' является явным по сравнению с простым использованием ns или var ns, оба из которых выдают ошибки.

Шаблон iffy необходим, чтобы избежать глобальной ошибки «использовать строгое»

Конечно, другим инструментам не нравится "this" как ненадежное предупреждение о том, что оно глобально (что, конечно, и есть цель), так что ... tomatoe tomato

3 голосов
/ 20 февраля 2010

Вы можете получить доступ к глобальным переменным через синтаксис window["NAMEOFGLOBAL"], поэтому вместо этого вы можете выполнить проверку следующим образом:

if(typeof(window['MyNamespace']) === 'undefined') {
1 голос
/ 20 февраля 2010

Я сталкивался с этой проблемой раньше. Вы определенно не хотите использовать свою окончательную форму, так как она полностью обходит проверку определенной переменной и всегда перезаписывает ее на пустой объект, даже если в нем уже что-то было.

Я думаю, что ваша вторая-последняя форма является наиболее подходящей для создания пространства имен, но на самом деле первая форма тоже неплоха. На мой взгляд, ошибки, о которых сообщает JSLint, являются своего рода ловушкой, и не о чем беспокоиться. Причина, по которой я думаю, что нет ничего страшного в том, чтобы оставить объявление, состоит в том, что в случае, когда пространство имен загружено в какой-то предыдущей точке, вы в конечном итоге использовали переменную JSLint, использовавшуюся до «ошибка», поэтому вы просто обмениваете одно предупреждение на другое.

1 голос
/ 20 февраля 2010

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

Как насчет:

var MyNs;
if(MyNs==null){
    //foo()
}
...