Область Var и Let [duplicate]

Я тоже столкнулся с этой ошибкой.

Моя проблема заключалась в том, что я изменил подпись метода, например

void invest(Currency money){...}

в

void invest(Euro money){...}

Этот метод был вызван из контекста, подобного

public static void main(String args[]) {
    Bank myBank = new Bank();

    Euro capital = new Euro();
    myBank.invest(capital);
}

. Компилятор молчал в отношении предупреждений / ошибок, поскольку капитал - это как валюта, так и евро.

Проблема возникла из-за того, что я только скомпилировал класс, в котором был определен метод - Bank, но не класс, из которого вызывается метод, который содержит метод main ().

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

Мое заявление состояло в том, что я создал .jar, который должен был использоваться как исправление, которое не содержало App.class, поскольку это не было изменено. Мне было разумно не включать его, поскольку я сохранил наследование базового класса исходного аргумента.

Дело в том, что при компиляции класса полученный байт-код является видом static , другими словами, это hard-reference .

Оригинальный дизассемблированный байт-код (сгенерированный с помощью инструмента javap) выглядит следующим образом:

 #7 = Methodref          #2.#22         // Bank.invest:(LCurrency;)V

После того, как ClassLoader загружает новый скомпилированный Bank.class, он не найдет такого метода, он выглядит так, как будто он был удален и не изменен, поэтому именованная ошибка.

Надеюсь, это поможет.

93
задан Michał Perłakowski 19 November 2016 в 13:58
поделиться

1 ответ

let и const имеют две большие отличия от var:

  1. Они являются блочным областью .
  2. Доступ к var до его объявления имеет результат undefined; доступ к let или const, прежде чем он будет объявлен бросками ReferenceError:

console.log(aVar); // undefined
console.log(aLet); // causes ReferenceError: aLet is not defined
var aVar = 1;
let aLet = 2;

примеры, что let объявления (и const, которые работают одинаково) могут не быть подняты , так как aLet не существует, пока ему не присвоено значение.

Это не так, однако let и const подняты (например, var, class и function), но есть период между вводом области и объявлением там, где они не могут быть доступны. Этот период является временной мертвой зоной (TDZ).

TDZ заканчивается, когда aLet объявлен объявлен , а не назначен :

//console.log(aLet)  // would throw ReferenceError

let aLet;
console.log(aLet); // undefined
aLet = 10;
console.log(aLet); // 10

Этот пример показывает, что let поднят:

let x = 'outer value';
(function() {
  // start TDZ for x
  console.log(x);
  let x = 'inner value'; // declaration ends TDZ for x
}());

Кредит: временная мертвая зона (TDZ) demystified

Доступ к x во внутренней области все еще вызывает ReferenceError. Если let не были подняты, он будет записывать outer value.

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

TDZ также применяется к аргументам функции по умолчанию. Аргументы оцениваются слева направо, и каждый аргумент находится в TDZ до тех пор, пока он не назначен:

// b is in TDZ until its value is assigned
function testDefaults(a=b, b) { }
testDefaults(undefined, 1); // throws ReferenceError because the evaluation of a reads b before it has been evaluated.

TDZ не включен по умолчанию в трансляторе babel.js . Включите режим «высокого соответствия», чтобы использовать его в REPL . Поставьте флаг es6.spec.blockScoping, чтобы использовать его с CLI или в качестве библиотеки.

Рекомендуемое дополнительное чтение: TDZ demystified и ES6 Let, Const и «Temporal Dead» Зона "(TDZ) в глубину .

130
ответ дан vigzmv 17 August 2018 в 09:02
поделиться
  • 1
    b is not defined (как комментарий первого фрагмента кода), но я думаю, что вы изменили имена переменных тем временем (и позже вы напишете об этом) – oliverpool 18 October 2015 в 14:12
  • 2
  • 3
    @zeroflagL хорошая ссылка, спасибо. Также он говорит: «foo не является необъявленным, он неинициализирован», этот язык был бы полезен для уточнения / исправления в вышеприведенном ответе. let foo в блоке вызывает его подъем и объявление в верхней части этого блока. Строка let foo заставляет ее инициализироваться. И foo = xyz заставляет его присваивать значение. – AJP 4 June 2017 в 01:04
  • 4
    Я думаю, что это отличный пост! Однако у меня создалось впечатление, что «пусть» не подлежит подъему? Я нашел это в документах Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Я не пытаюсь быть кумиром, мне было просто любопытно, я открыт для разъяснения. – dmarges 3 October 2017 в 21:39
  • 5
    @jeows Страница MDN все еще говорит, что они не подняты. Вы должны попытаться изменить это, если вы действительно уверены в том, что вы говорите. Думаю, мне стоит задать вопрос. – doubleOrt 5 December 2017 в 23:01
Другие вопросы по тегам:

Похожие вопросы: