marijnh / Eloquent-JavaScript

The sources for the Eloquent JavaScript book
https://eloquentjavascript.net
3.01k stars 795 forks source link

Ch. 6 Symbols #373

Closed MarHoff closed 6 years ago

MarHoff commented 6 years ago

Hello, and first of thanks a lot for this good job,

I also apologize because I'm writing this issue while learning, maybe this matter would have become self evident at the end of the chapter.

I have difficulties coping with this concept of Symbols and the provided examples don't lift the fog as well as they might:

When I claimed that property names are strings, that wasn't entirely accurate. They usually are, but they can also be ((symbol))s. Symbols are values created with the Symbol function. Unlike strings, newly created symbols are unique—you cannot create the same symbol twice.

let sym = Symbol("sym");
console.log(sym == Symbol("sym"));
// → false
Rabbit.prototype[sym] = 55;
console.log(blackRabbit[sym]);
// → 55

I really don't understand in which context symbols are unique. But in my understanding Symbol() is a constructor for a 'symbol' object that is indeed unique as an object. You said later that

The string you pass to Symbol is included when you convert it to a string, and is useful to make it easier to recognize a symbol when, for example, showing it in the console. But it has no meaning beyond that.

Maybe you could make the example more clear by using a string differentiated from the let binding name. And then use some computation on the symbol object.

let sym = Symbol("foo sym");
console.log(sym == Symbol("foo"));
// → false
console.log(typeof sym);
// → symbol
console.log(sym.toString());
// → Symbol(foo sym)

Rabbit.prototype[sym] = 55;
console.log(blackRabbit[sym]);
// → 55

Later I had same difficulties understanding the added value of using symbol with example code after this paragraph:

Being useable as property names and being unique makes symbols suitable for defining interfaces that can peacefully live alongside arbitrary other properties.

const toStringSymbol = Symbol("toString");
Array.prototype[toStringSymbol] = function() {
  return `${this.length} cm of blue yarn`;
};

console.log([1, 2].toString());
// → 1,2
console.log([1, 2][toStringSymbol]());
// → 2 cm of blue yarn

However this will perfectly work as well as name you choose avoided any collision:

Array.prototype.toStringSymbol = function() {
  return `${this.length} cm of blue yarn`;
};

console.log([1, 2].toString());
// → 1,2
console.log([1, 2].toStringSymbol());
// → 2 cm of blue yarn

So it would be easy to dismiss the concept altogether why bother? The following code example might lead to more head scratching but might also invite reader to more reflexion :

const toString = Symbol("foo toString");
Array.prototype[toString] = function() {
  return `${this.length} cm of blue yarn`;
};

console.log([1, 2].toString());
// → 1,2
console.log([1, 2][toString]());
// → 2 cm of blue yarn

And a far as I understand now what actually guarantee that a symbol is unique is the ability to use a 'const' binding when defining it.

MarHoff commented 6 years ago

Also to wrap up the last example should be something along the line of the following code:

const MySymbol = Symbol("My unique Symbol");
let stringObject = {
  [MySymbol]() { return "something"; }
};
console.log(stringObject[MySymbol]());
// → something

And also this work but i have no idea why. Does it implicitly create a symbol as well?

Array.prototype[toString] = function() {
  return `${this.length} cm of blue yarn`;
};

console.log([1, 2].toString());
// → 1,2
console.log([1, 2][toString]());
// → 2 cm of blue yarn
marijnh commented 6 years ago

Attached patch tries to clarify this section a little.

MarHoff commented 6 years ago

Thanks a lot for all the work and sorry for late comment about it ;)