8

Given

let obj = {name: 1};
console.log(typeof obj.name, obj.name); // `"number"`, `1`

Why is name identifier cast to string when using var at object destructuring assignment?

let obj = {name: 1};
var {name} = obj; 
console.log(name, typeof name); // `1` `string`

But not using let or const?

let obj = {name: 1};
let {name} = obj; 
console.log(name, typeof name);

We can avoid this unexpected result by defining a different identifier

let obj = {name: 1};
var {name:_name} = obj; 
console.log(_name, typeof _name);

though curious as to the significance of var returning different results than let or const for the name identifier at a browser environment?

guest271314
  • 1
  • 15
  • 104
  • 177

1 Answers1

5

This behaviour is defined by the scope in which the code is being executed.

name refers to window.name property, which descriptor has a setter to convert it to string when being assigned as window.name = 1:

A valid browsing context name is any string with at least one character that does not start with a U+005F LOW LINE character. (Names starting with an underscore are reserved for special keywords.)

When being executed in global scope, var name = ... assigns a value to window.name. While let and const declare block-scoped variables.

When being executed in local scope, name will refer to local variable in both cases:

(() => {
 var obj = {name: 1};
 var {name} = obj; 
 console.log(typeof name); // 'number'
})();
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • The solution is to use block scope and `"use strict"` to avoid unexpected results? – guest271314 Jun 07 '17 at 06:19
  • 1
    @guest271314 Yes. Function scope is enough. That's the reason why we used to use all these IIFEs everywhere - to not clash with global scope. I removed 'use strict' from the snippet for clarity. It is desirable by default but won't affect the result, so it's not relevant here. – Estus Flask Jun 07 '17 at 06:24
  • Is this behaviour, of `var` that is, one of the reasons `let` and `const` were developed and implemented? And a reason to avoid using `var` now that the former are now available for usage at browser environments? – guest271314 Jun 07 '17 at 06:42
  • 1
    @guest271314 Yes, it is. Nowadays if there's a need for global, we do `window.foo = ...`. Accidental assignment to global with `var foo = ...` is never desirable. Actually, intentional assignment to global with `var foo = ...` isn't desirable too, because it won't work in strict mode. – Estus Flask Jun 07 '17 at 06:53
  • I wouldn't call global `let`/`const` declarations "block-scoped". – Bergi Jun 07 '17 at 08:16
  • @Bergi I guess this should be addressed in terms of execution contexts instead, eh? – Estus Flask Jun 07 '17 at 08:39
  • @estus I'd just call it "global scope". If you want to use spec terminology, it's "lexical environment" though not "execution context". – Bergi Jun 07 '17 at 08:46