Как мне избежать «переменная, возможно, не была инициализирована» при ссылке на родительский объект JavaScript?

#javascript #eclipse #warnings

#javascript #eclipse #предупреждения

Вопрос:

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

 var foo = new Foo({
  bar: new Bar({
    x: function(){
      doStuff(foo);
    }
  });
});
 

(Если это выглядит знакомо, возможно, вы раньше использовали ExtJS — именно так создается большая часть их материалов.)

Когда я вызываю foo.bar.x() , я хочу указать обратно на Foo ( foo ) , которому принадлежит Bar ( bar ), вызывающий функцию ( x ) . Это работает, но мое Eclipse предупреждает меня, что «foo, возможно, не был инициализирован», ссылаясь на вызов doStuff(); — потому что, когда движок впервые видит строку, мы еще не закончили определение foo . Конечно, x() не может быть вызван, если foo не создан успешно, но моя проверка стиля, по-видимому, этого не поняла.

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

Комментарии:

1. Это опечатка? Должно ли это быть doStuff(foo) вместо doStuff(f)

2. Не используйте eclipse. Есть лучшие IDE (WebStorm 3)

Ответ №1:

 var Foo = function() { }

var Bar = function (obj) {
  // foo is not initialized
  obj.x();
  // called doStuff with undefined
}

var foo = new Foo({
  bar: new Bar({
    x: function(){
      doStuff(foo);
    }
  });
});
 

Eclipse прав. Опять же, если вам нужна лучшая система анализа, рассмотрите возможность использования WebStorm 3.0 или Visual Studio 11 в качестве среды разработки JS.

Комментарии:

1. Я понимаю, почему он жалуется. Я просто на 99% уверен, что нет фактического контекста выполнения, в котором x() можно было бы вызвать , пока foo он остается неопределенным. Да, Bar конструктор завершится до завершения Foo конструктора, но это не значит, что что-либо может воздействовать на Bar созданный (и назначенный foo.bar ) объект до тех пор, пока Foo объект не будет полностью сконструирован, и в этот момент foo переменная инициализируется. Если это имеет какой-то смысл…

2. в стороне: VS — это не вариант (хотя я вообще фанат …), Поскольку я разрабатываю в Linux. Я серьезно рассмотрю WebStorm — спасибо за указатель!

3. @Coderer Я только что показал вам контекст, в котором x вызывается, когда foo не определено

4. Хорошо, я все еще достаточно новичок в JavaScript, чтобы мне пришлось перечитывать это около дюжины раз, прежде чем он щелкнул. Вы говорите, что если конструктор Bar вызывает свой собственный x метод во время построения (!!!), этот метод попытается использовать foo , который не определен. Теперь это имеет смысл. Существует ли шаблон, предотвращающий это? Я не могу придумать ни одного.

5. @Coderer это называется «не ссылайтесь на себя в своем объявлении». Это плохая практика (если только это не простое объявление, подобное функции)

Ответ №2:

Это не имеет ничего общего с javascript, но, вероятно, как-то связано с Eclipse. Переменная foo может быть объявлена где угодно, поскольку объявления переменных обрабатываются до выполнения любого кода. Он также может быть инициализирован в любое время перед вызовом doStuff (хотя инициализация переменных без их объявления считается дурным тоном).

Ответ №3:

Сначала создается Foo . Его конструктору передается новый Bar, который передается функции с использованием переменной foo .

Но foo присваивается значение только после завершения работы конструктора Foo. На этом этапе функция уже объявлена с использованием необъявленной переменной foo . Если функция используется в конструкторе Bar или Foo, она завершится ошибкой.

Комментарии:

1. Во-первых, foo создается как свойство объекта локальной переменной. Код, похоже, находится в глобальной области видимости, поэтому он является свойством глобального объекта (глобальной переменной) перед выполнением любого кода. При вызове doStuff foo существует, но, возможно, ему не было присвоено значение (т. Е. Оно может быть неопределенным).

2. Вы предполагаете, что код OP выдаст ошибку? Потому что этого не произойдет.

3. Я не предлагаю этого, я объясняю, как возможно, что переменная не назначается в момент вызова doStuff . Я не говорю, что это так, но это возможно, поэтому выдается предупреждение. foo В этой ситуации не имеет значения, объявлено ли оно как свойство или как глобальное. Самый простой способ предотвратить предупреждение — присвоить значение (может быть нулевым) foo перед вызовом этого присваивания.

Ответ №4:

Я думаю, что @RobG прав, что это проблема Eclipse, и, вероятно, лучше просто разобраться с ней. Но если вы хотите избежать этого, вы можете объявить foo перед его инициализацией, и я уверен, что это удержит Eclipse от жалоб:

 var foo;
foo = new Foo({
  bar: new Bar({
    x: function(){
      doStuff(foo);
    }
  });
});
 

Комментарии:

1. Просто объявить его недостаточно (он объявлен, но все еще технически не «инициализирован»), и мне трудно заставить себя сделать что-то вроде var foo = "some garbage"; foo = new Foo(....);

2. Да, вы могли бы инициализировать его null , но в этот момент вы искажаете свой стиль кодирования, чтобы соответствовать вашей IDE, что никуда не годится.

3. Javascript не требует, чтобы переменным присваивалось значение (инициализированное), поэтому Eclipse просто придирчив. Запустите свой код через jslint и посмотрите, что вы получите!!

4. Я намерен попробовать JSLint, но он настолько требователен, что мне потребуется несколько часов, чтобы исправить все его предупреждения, поэтому я хотел сначала попробовать поработать с «мягкими» предупреждениями в Eclipse. Я знаю, что значения не обязательно инициализировать, но есть смысл заставить вас задуматься о том, что может пойти не так (например, если инициализирующий код находится внутри условного)