Reputation:
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
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