Проблема, с которой вы столкнулись, связана с областью видимости и подъемом переменных в JavaScript, особенно при использовании стрелочных функций и конструкций, связанных с `setTimeout`.
Давайте по порядку разберем код и ваши наблюдения:
1. **Ошибка "Uncaught ReferenceError: Cannot access 'testValue' before initialization"**:
Эта ошибка возникает, когда вы пытаетесь обратиться к переменной, определенной через `let` или `const`, до того, как она была инициализирована. Область видимости переменных, объявленных с использованием `let` или `const`, ограничена блоком, в котором они были определены.
В вашем случае это происходит потому, что при повторном вызове функции `testFn` переменная `testValue` инициализируется в каждой новой функции. Однако, если в `setTimeout` используется условие `if (condition === 0)`, это приводит к тому, что вызывается ошибка, если `condition` не соответствует этому значению, а доступ к `testValue` станет возможным только после того, как выполнение функции дойдет до области видимости, где `testValue` доступна. Таким образом, если `condition` равен 0, код никогда не дойдет до точки, где `testValue` будет инициализирован, и будет зафиксирована ошибка.
2. **Использование `true` или самовызывающейся функции**:
Когда вы заменяете условие `if (condition === 0)` на `if (true)`, вы позволяете коду всегда обращаться к `testValue`, и поэтому ошибка не возникает. В этом случае переменная доступна в пределах функции обратного вызова `setTimeout`.
В случае самовызывающейся функции код выполняется сразу же, и поэтому все переменные инициализируются до обращения к `testValue`. Таким образом, в момент вызова `console.log(testValue)` все необходимые переменные уже инициализированы и доступны.
3. **Общая рекомендация**:
Чтобы избежать подобных ошибок, всегда следите за областью видимости переменных и их инициализацией в асинхронных вызовах, таких как `setTimeout`, особенно если вы используете конструкции, которые могут привести к изменению контекста исполнения. Иногда может помочь использование замыканий, чтобы сохранить состояние переменных на момент их инициализации, или же просто избегать ссылки на переменные, которые могут быть не инициализированы, в асинхронных контекстах.
Вот пример исправленного кода, чтобы избежать ошибок:
```javascript
let testValue = 123;
function testFn() {
let condition = 1; // Измените значение на 1 для правил
let timer = setTimeout(() => {
if (condition === 1) { // Убедитесь, что значение корректное
console.log(testValue);
}
}, 1000); // Добавил задержку, чтобы было видно, как это работает
}
testFn(); // 123
```
Эти изменения обеспечивают, что в момент выполнения функции обратного вызова доступ к `testValue` всегда будет возможен, и ошибки больше не появятся.