Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do you access Symbol.iterator via brackets?

If I created an array, for instance, var array=[1,2,3,4]; to return an iterator I would do var iterator = array[Symbol.iterator](); I don't understand why you access the Symbol.iterator property through brackets? Why isn't it just array.Symbol.iterator?

like image 349
akotch Avatar asked Jul 24 '18 01:07

akotch


3 Answers

There is no property on an array called Symbol (unless you put one there). Instead you are looking up the values whose key is the symbol primitive that Symbol.iterator points to. Symbol.iterator returns a symbol and you use that symbol as the lookup key. It's a little like looking up a property with a variable:

let a = [1, 2, 3]
a.someProp = "hello"

let key = "someProp"

// this doesn't work for the same reason s.Symbol.iterator doesn't:
// a.key

// but this does:
console.log(a[key])

// So with a Symbol:

let k = Symbol.iterator
console.log(typeof k)
// k is now a reference to the symbol that is the key
// you can use that to returns the iterator function
console.log(a[k])    // <-- that returns your iterator function
console.log([...a[k]()])

// equivalent to:
console.log([...a[Symbol.iterator]()])
like image 113
Mark Avatar answered Oct 13 '22 13:10

Mark


Because that's how the iterable protocol works. See MDN:

The iterable protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for..of construct. Some built-in types are built-in iterables with a default iteration behavior, such as Array or Map, while other types (such as Object) are not.

In order to be iterable, an object must implement the @@iterator method, meaning that the object (or one of the objects up its prototype chain) must have a property with a @@iterator key which is available via constant Symbol.iterator:

The interpreter needs a way to determine whether a generic object is iterable. While it could have been specified that each iterable object has a string iterator property that, when called, returns an iterator for that object, that might be a problem for (pre-iterator) objects that may have happened to have the iterator property but don't conform to the actual specification iterator protocol.

Requiring that the iterator property is accessed via a (unique, iterator-specific) Symbol ensures that no such problematic collisions can take place.

(as a side note: array.Symbol.iterator would require Symbol to be a property of array, which wouldn't make much sense - Symbol is a global object)

like image 29
CertainPerformance Avatar answered Oct 13 '22 13:10

CertainPerformance


array.Symbol.iterator says "access the Symbol member of the array variable, and then access that value's iterator member" however that will return the error Uncaught TypeError: Cannot read property 'iterator' of undefined because the array doesn't have a member called Symbol and so it returns undefined and undefined doesn't have an iterator member.

The dot . operator in JS is left-associative so it's evaluated from left-to-right. You need to use brackets to clarify what you want, and what you want is to access the iterator of Symbol and then use that value to access a member of the array variable.

To use a math analogy, the difference between array.Symbol.iterator and array[Symbol.iterator] is like the difference between 6 / 0 + 2 (undefined, can't divide by 0) and 6 / (0 + 2) (= 3, valid operation!).

like image 36
pretzelhammer Avatar answered Oct 13 '22 13:10

pretzelhammer