1

First off, not a duplicate, I did look at the other "ReferenceErrors" here on SO. However, my problem is not scope related nor a misspelling.

My issue is that copy apparently isn't defined despite I clearly defined it at the very first line. What is going on?

My goal is to redefine the variable copy inside the loop.

var copy = 'test 1';

for (let i = 0; i < 2; i++) {
  let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
  console.log(t); // Output: 'test 2';
  let copy = t; // <-- ReferenceError: copy is not defined
}
Andreas
  • 19,756
  • 7
  • 41
  • 49
xing Zì
  • 309
  • 2
  • 11
  • 2
    The first time you redefine `copy`, it overwrites the global one and becomes scoped to its iteration block (as a `let` variable). On the next iteration it doesn't exist anymore. – Jeto Mar 30 '19 at 11:07
  • 1
    Possible duplicate of [Are variables declared with let or const not hoisted in ES6?](https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6) and [What is the temporal dead zone?](https://stackoverflow.com/questions/33198849) – adiga Mar 30 '19 at 11:14
  • @Jeto it doesn't overwrite the global variable – adiga Mar 30 '19 at 11:19
  • @adiga Yeah I meant in the context of that block scope. But it's probably not the best word. It takes precedence at least. – Jeto Mar 30 '19 at 11:34

5 Answers5

2

I guess the issue here is you are trying to declare twice the copy variable in the loop:

let copy = t;

The solution is to remove let from your for loop as the following:

var copy = 'test 1';

for (let i = 0; i < 2; i++) {
  let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
  console.log(t);
  copy = t; // removed let
}

So you are not declaring twice the copy variable.

Additionally I recommend to read the What's the difference between using “let” and “var”? titled article.

norbitrial
  • 12,734
  • 5
  • 20
  • 46
  • That's not the issue. Add just the line `let copy = "test 2"` inside the `for` loop and it won't throw any error. This is because of Temporal dead zone. – adiga Mar 30 '19 at 11:14
1

This is happening because of the temporal dead zone, you declare copy using let which has a block scope so in this case it is limited to the scope of the for loop.

now inside the for-loop you are trying to access copy thinking that it is the outer variable declared using var but it is not so, it is actually referring to the inner copy declared using let.

Variables declared using let are not hoisted to the top and cannot be used before declaration. This phenomenon is known as temporal dead zone.

The same is true for variable declared using const.

for (let i = 0; i < 2; i++) {
  let t = copy.replace(/(\d+)/,... //copy is actually not available here, accessing it here will result in a ReferenceError
  ...
  let copy = t; //copy will be available after this declaration

To fix it, don't declare it again with let, just re-assign the outer variable:

(function(){
  var copy = 'test 1';
  for (let i = 0; i < 2; i++) {
    let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
    console.log(t); 
    copy = t; //copy is the outer variable
  }
})();
Fullstack Guy
  • 14,425
  • 3
  • 18
  • 35
0

This is a Temporal dead zone (TDZ) issue.

In your loop, copy is hoisted to the top of the loop. However, instead of being undefined, like var, it is "not initialized" and accessing it throws an error.

var copy = 'test 1';

for (let i = 0; i < 2; i++) {
  // copy is hoisted here
  // It is not initialized
  //Accessing copy here throws ReferenceError
  let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
  console.log(t); // Output: 'test 2';
  let copy = t; // <-- ReferenceError: copy is not defined
}
jro
  • 768
  • 1
  • 7
  • 18
0

The reason this is happening is because you declare copy twice but this is only half of the truth.

Look This code will work. Note that you declare the copy twice. But this will not throw will undefined error

var copy = 'test 1';

for (let i = 0; i < 2; i++) {
  let copy = t; 
}

While this will surely throw an error

var copy = 'test 1';

for (let i = 0; i < 2; i++) {
  let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
  let copy = t; 
}

This is because of the let copy. let copy's scope is inside the for loop. Compiler will always try to find the variable that is closest to the function you called. hence undefined error will throw. In your case, your trying to call the var copy but the compiler found the let copy that's why it returning error not on the let copy itself but in these lines

let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;});
keysl
  • 1,761
  • 9
  • 14
0

you can use it like this:

var copy = 'test 1'; 

    for (let i=0; i<2; i++) { 
      let t = copy.replace(/(\d+)/, function (fullMatch, n) {return `${Number(n) + 1}`;}); 
    console.log(t); // Output: 'test 2'; 
    copy = t; // <-- ReferenceError: copy is not defined 
    }

Or use a new variable name like: let copy1 To avoid ReferenceError

Dev-Learner
  • 161
  • 3