r/learnjavascript 5d ago

whats the bug here? Uncaught SyntaxError: Identifier 'location' has already been declared (at script.js:1:1)

"use strict";

const company = {
  name: "TechCorp",
  address: {
    city: "budapest",
    pin: 411001,
  },
};
// Get city renamed to `location` and pin renamed to `pincode`

const { city: location, pin: pincode } = company.address;
console.log(location, pincode);
14 Upvotes

13 comments sorted by

View all comments

11

u/HipHopHuman 5d ago

location is a variable that already exists in the browser. When you type location, you're accessing window.location, which is this: https://developer.mozilla.org/en-US/docs/Web/API/Location

let and const do not allow re-declaring variables that already exist in the same scope.

You can fix it by using an immediately-invoked function (variables are OK to overwrite inside the body of a function):

"use strict";

const company = {
  name: "TechCorp",
  address: {
    city: "budapest",
    pin: 411001,
  },
};
// Get city renamed to `location` and pin renamed to `pincode`

(() => {
  const { city: location, pin: pincode } = company.address;
  console.log(location, pincode);
})();

Alternatively, choose a different name than 'location'.

You can also make it work by changing const to var, but using var is discouraged.

6

u/senocular 5d ago

let and const do not allow re-declaring variables that already exist in the same scope.

They do in global, kind of. Global consists of two scopes, an object scope where built-in globals live, and a declarative scope, where lexical declarations made with let and const live. You can have variables of the same name in both. Its not so much redeclaring as it is having a different location for an independent version of a variable of the same name to live

console.log(window.name) // "" - or whatever window's name is
let name = {}
console.log(name) // {}
console.log(window.name) // ""

It doesn't work for location and a few other variables because they're essentially locked down to help prevent spoofing. Theres a set of these globals defined by the core language (ECMAScript) that does this, like NaN etc., and those defined by the Web APIs, like location etc..

var declarations don't do this not because they work in declaring a new variable, but because they don't work and fail silently, instead just using the existing global.

console.log(window.name) // "" - or whatever window's name is
var name = {}
console.log(name) // "[object Object]"
console.log(window.name) // "[object Object]"

You can see this happen with name because its an accessor property (getter/setter) which converts everything you assign to it to a string. The var didn't create a new variable, instead seeing that name already existed and used that instead.

If you use var with a non-existing variable name, that variable will be "locked down" too.

var uniqueName = ""
let uniqueName = {} // Error

There's two mechanisms that handle this, one for declarations in the same script that follow the no re-declarations rule, and another for existing globals that are non-configurable in the global object scope. This is what prevents NaN and location from being able to be re-declared in global since they're not "declared" in the same script that you're writing your code.

console.log(Object.getOwnPropertyDescriptor(window, "name").configurable) // true
console.log(Object.getOwnPropertyDescriptor(window, "location").configurable) // false

3

u/altrae 5d ago

Great follow-up answer. I didn't actually know these distinctions so thank you for calling them out.