user10686399
user10686399

Reputation:

What are name clashes and how do ES6 Symbols avoid name clashes between properties?

I am trying to understand Symbols in ES6 better, and I have read this answer:

https://stackoverflow.com/a/22280202/5591717

They are now known as unique symbols and their only intended use is to avoid name clashes between properties.

Does a name clash only ever mean, one name shadowing another name? Or does it also mean an error, where something can't be be redeclared?

An example:

let color = Symbol('this is a color')

let apple = {
  [color]: 'red'
}

console.log(apple[color]) //red
console.log(apple.color) //undefined 

apple[color] = 'black'

console.log(apple[color]) //black
console.log(apple.color) //undefined

apple.color = 'white'

console.log(apple[color]) //black
console.log(apple.color) //white

It looks like properties can be shadowed, even if they are accessed through Symbols.

And they also allow dot notation properties with the same name as the Symbol name to coexist with a different value. Is this what is meant by avoiding name clashes?

Upvotes: 1

Views: 698

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370709

This is not shadowing:

In computer programming, variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. This outer variable is said to be shadowed...

eg

const foo = 'foo';
(() => {
  // entirely separate variable which shadows outer variable with same name
  const foo = 'foo2';
})();

The variable name you store the Symbol in has no effect on anything (which is good - code execution shouldn't depend on what variable names are used). You could have named it mySymbol instead of color, and the engine would have the exact same output:

let mySymbol = Symbol('this is a mySymbol')

let apple = {
  [mySymbol]: 'red'
}

console.log(apple[mySymbol]) //red
console.log(apple.color) //undefined 

apple[mySymbol] = 'black'

console.log(apple[mySymbol]) //black
console.log(apple.color) //undefined

apple.color = 'white'

console.log(apple[mySymbol]) //black
console.log(apple.color) //white

Name clashes are avoided when entirely separate sections of the code need to store data on an object. The different sections of the code may not be aware of each other, but they want to make sure that the property that one uses is not the same as another. This can be accomplished by each section using its own Symbol, making it impossible for the two sections of code to accidentally use the same property name and thus cause bugs. For example:

// module1.js

const module1 = (() => {
  const module1Sym = Symbol();
  return (obj) => {
    // put some data on obj which can be retrieved by this module later
    obj[module1Sym] = 'module 1 data';
  };
})();

// module2.js

const module2 = (() => {
  const module2Sym = Symbol();
  return (obj) => {
    // put some data on obj which can be retrieved by this module later
    obj[module2Sym] = 'module 2 data';
  };
})();

const obj = {};
module1(obj);
module2(obj);

If one module used the property name module1data instead, there could be problems - what if some other module which called itself module1 was trying to store data on the object? Then, things would break down:

// module1Foo.js

const module1Foo = (() => {
  return (obj) => {
    // put some data on obj which can be retrieved by this module later
    obj.module1Data = 'foo data';
  };
})();

// module1Bar.js

const module1Bar = (() => {
  return (obj) => {
    // put some data on obj which can be retrieved by this module later
    obj.module1Data = 'bar data';
  };
})();

const obj = {};
module1Foo(obj);
module1Bar(obj);

// Uh oh, foo data got overwritten
console.log(obj);

The above is an example of a name clash. Two modules accidentally used the same property name.

Upvotes: 3

Related Questions