javascript- Uncaught SyntaxError: Identifier * has already been declared
Asked Answered
A

3

50
console.log(a) //output:ƒ a(){}
var a = 1;
function a(){};
var a = 10;
console.log(a) //output:10

====================

var a = 1;
if(true){
  function a(){};
  var a = 10;
}
console.log(a) // this code throws Uncaught SyntaxError: Identifier 'a' has already been declared

both above code snippets are same except the if block.why does the latter throws error when its permissible in javascript to delcare same variable twice in the same scope with var as below

 function a(){};
 var a = 10; //no error

Also for a slightly different scenario after removing var from `var a = 10 in the above code ,then it works fine but output is surprising

 var a = 1;
 if(true) {
   function a(){};
   a = 10;
 }
 console.log(a) //output:ƒ a(){}

I am surprised to see this output as I am expecting 10 ..because two variables declared inside the if block refer to the same variable declared above as javascript var doesnt respect block scope but functional scope...so why not the output for above should be 10? where as the below code outputs 10 as i expected when replaced the function definition with function expression.

  var a = 1;
  if(true) {
    var a = function(){ console.log() }
    a = 10;
  }
  console.log(a) //output:10
Alage answered 11/4, 2018 at 12:9 Comment(2)
Well, function declarations inside if blocks were invalid in ES5, so using them will have ES6 semantics with stricter rules about duplicate declarations.Nativeborn
Related, if not duplicate: Why does redeclaring a function identifier within a try block throw a SyntaxError?Nativeborn
N
38

This is surprising as javascript var doesn't respect block scope but functional scope...

Sure, but you didn't use var for the declaration of a in the block scope. You used a function declaration, which does respect block scopes (otherwise it would be completely invalid code, as in ES5 strict mode).

It's permissible in javascript to declare same variable twice in the same scope with var as below

Same applies here. The function declaration in the block uses ES6 declaration semantics (like let or const), which does not allow redeclarations.

Nativeborn answered 11/4, 2018 at 12:37 Comment(0)
S
15

Case 1

console.log(a) //output:ƒ a(){}
var a = 1;
function a(){};
var a = 10;
console.log(a) //output:10

Will be rendered as

var a;
a = function(){}; // now a holds the value as a function
console.log(a); // output : f a(){}
a = 1; // a is a var that holds value 1
a = 10; // a is a var that holds value 10
console.log(a); // output : 10

Case 2

var a = 1;
if(true){
   function a(){};
   var a = 10;
}
console.log(a)

Will be rendered as

var a;
a = 1;
if(true) {
    a = function() {};
    let a; // The function declaration in the block uses ES6 declaration semantics (like let or const), which does not allow re-declarations.
    var a; // throws Uncaught SyntaxError: Identifier 'a' has already been declared
    a = 10;
}
console.log(a);

Case 3

var a = 1;
if(true){
    function a(){};
    a = 10;
 }
console.log(a)

Will be rendered as

var a;
a = 1;
if(true) {
    a = function() {};
    let a;
    a = 10;
}
console.log(a); // output : f a(){}

Case 4

var a = 1;
if(true){
    var a= function(){console.log()}
    a = 10;
}
console.log(a)

Will be rendered as

var a;
a = 1;
if(true) {
    a = function(){console.log()}
    a = 10;
}
console.log(a) // output:10

Case 5

var a = 1;
if(true){
    function a(){};
    a = 10;
    console.log(a) 
}
console.log(a) 

Will be rendered as

var a;
a = 1;
if(true){
    a = function() {};
    let a;
    a = 10;
    console.log(a); // output:10
}
console.log(a); // output : f a(){}
Simply answered 11/4, 2018 at 12:41 Comment(10)
More like let a in case 3.Nativeborn
@Nativeborn - Thank you. I have taken reference from your answer while posting my understanding. Hope it is okay with you. If not, I will be happy to remove my answser.Simply
@PrashantTapase - Thank you. I have updated my answer for better understanding and you can now see the behavior with the false statements as well.Simply
@nikhilagw It's fine :-)Nativeborn
@nikhilagw great..its very clear and Thanks for the answer with detailed scenarios ...could you also please mention how this piece of code is rendered ...if(true) { function b(){} } ? Thanks in advanceAlage
I am asking this because when i execute this code in chrome console ..console.log(b); //output:undefined if(true) { function b(){} } console.log(b); //output:ƒ b(){} so I am doubtful if function declarations are treated like let/const as b is available outside the block as wellAlage
@Alage - In your case it will be like this. var b; console.log(b); if(true) { b = function(){}} console.log(b); Because of this the first console gives undefined and the second gives the function. The declarations are hoisted to parent function scope, however, the value is set in the scope only. Any function definition in the block, basically ends up blocking the variable name in that block just like let and const do, however, the association of the function is always with the parent function scope. Hope it clarifies.Simply
Its very clear now.Thanks a lot nikhilagw.Thanks @NativebornAlage
@venkata, nikhilagw: the details of sloppy mode block scope function declarations in browsers are just weird. You should use strict mode and ignore what you just saw :-)Nativeborn
@Nativeborn - Agreed. Makes sense. :)Simply
C
6

The simple solution to this is to use IIFE

(function() {
var sahil = {
  checkThis: function() {
    console.log(this);

    function checkOther() {
      console.log(this);
    }
    checkOther(); // checkThis() function called in "global context", will
                  // return "this" as "window"
  }
};
var moo = sahil.checkThis;
moo(); // moo() function called in "global context", will return "this" as "window" })();
Cabotage answered 7/1, 2019 at 3:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.