【发布时间】:2018-12-31 12:32:07
【问题描述】:
如果我创建了一个数组,例如 var array=[1,2,3,4]; 来返回一个迭代器,我会这样做 var iterator = array[Symbol.iterator](); 我不明白你为什么要通过括号访问 Symbol.iterator 属性?为什么不只是array.Symbol.iterator?
【问题讨论】:
标签: javascript arrays iterator symbols
如果我创建了一个数组,例如 var array=[1,2,3,4]; 来返回一个迭代器,我会这样做 var iterator = array[Symbol.iterator](); 我不明白你为什么要通过括号访问 Symbol.iterator 属性?为什么不只是array.Symbol.iterator?
【问题讨论】:
标签: javascript arrays iterator symbols
在名为Symbol 的数组上没有属性(除非您在其中放置一个)。相反,您正在查找其键是 Symbol.iterator 指向的符号原语的值。 Symbol.iterator 返回一个符号,您使用该符号作为查找键。这有点像用变量查找属性:
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]()])
【讨论】:
因为这就是可迭代协议的工作方式。见MDN:
可迭代协议允许 JavaScript 对象定义或自定义它们的迭代行为,例如在 for..of 构造中循环的值。一些内置类型是具有默认迭代行为的内置可迭代对象,例如 Array 或 Map,而其他类型(例如 Object)则不是。
为了可迭代,对象必须实现@@iterator 方法,这意味着对象(或其原型链上的对象之一)必须具有带有@@iterator 键的属性,该键可通过常量 Symbol 获得.iterator:
解释器需要一种方法来确定一个 generic 对象是否是可迭代的。虽然可以指定每个可迭代对象都有一个字符串 iterator 属性,当调用该属性时,该属性会返回该对象的迭代器,这对于可能碰巧具有 @987654323 的(预迭代器)对象可能是一个问题@property 但不符合实际的规范迭代器协议。
要求通过(唯一的、特定于迭代器的)Symbol 访问迭代器属性可确保不会发生此类有问题的冲突。
(附带说明:array.Symbol.iterator 将要求 Symbol 成为 array 的属性,这没有多大意义 - Symbol 是一个全局对象)
【讨论】:
array.Symbol.iterator 表示“访问array 变量的Symbol 成员,然后访问该值的iterator 成员”但是这将返回错误Uncaught TypeError: Cannot read property 'iterator' of undefined,因为该数组没有名为Symbol 所以它返回 undefined 并且 undefined 没有 iterator 成员。
JS 中的点. 运算符是左关联的,因此它是从左到右计算的。您需要使用方括号来明确您想要什么,您想要的是访问Symbol 的iterator,然后使用该值访问array 变量的成员。
使用数学类比,array.Symbol.iterator 和 array[Symbol.iterator] 之间的区别就像 6 / 0 + 2(未定义,不能除以 0)和 6 / (0 + 2)(= 3,有效操作!)之间的区别。
【讨论】: