이 기사에서는 Iterator를 통해 데이터 수집에 액세스하는 통합 인터페이스 방법을 소개합니다. 이는 필요한 참조 가치가 있습니다.
Traverser Iterator
는 데이터 컬렉션에 액세스하기 위해 ES6에서 제공하는 통합 인터페이스입니다. 내부적으로 배포된 순회 인터페이스가 있는 모든 데이터 컬렉션의 경우 사용자는 동일한 방식으로 해당 데이터 구조를 얻을 수 있습니다. 최신 버전의 Chrome
브라우저를 사용하고 계시다면, 우리에게 익숙한 미스 어레이가 그녀의 마음에 닿을 수 있는 또 다른 길을 조용히 열어주었다는 것을 알아야 합니다. Iterator
是ES6为访问数据集合提供的统一接口。任何内部部署了遍历器接口的数据集合,对于用户来说,都可以使用相同方式获取到相应的数据结构。如果使用的是最新版Chrome
浏览器,那么你要知道——我们所熟悉的数组小姐,已悄悄的打开了另一扇可抵达她心扉的小径。
某个数据集合部署了Iterator
接口,是指其Symbol.iterator
属性指向一个能返回Iterator
接口的函数。任何默认使用遍历器访问数据集合的方法,都会调用此属性以得到遍历器对象,再按照设定的顺序依次访问该数据结构的成员(关于Symbol.iterator
请看最后一节的延伸阅读)。比如原生数组的遍历器为[][Symbol.iterator]
,也可以直接通过其构造函数的原型获取Array.prototype[Symbol.iterator]
。
调用Iterator
接口会返回一个新的遍历器对象(指针对象)。
对象中必然有next
方法,用于访问下一个数据成员。指针初始时指向当前数据结构的起始位置。
第一次调用对象的next
方法,指针指向数据结构的第一个成员。
第二次调用对象的next
方法,指针指向数据结构的第二个成员。
不断的调用对象的next
方法,直到它指向数据结构的结束位置。
每次调用next
方法,都会返回相同的数据结构:{ value, done }
。
其中value
表示当前指向成员的值,没有则为undefined
。
其中done
是一个布尔值,表示遍历是否结束,结束为true
,否则false
。
遍历器接口的标准十分简洁,不提供诸如:操作内部指针、判断是否有值等等方法。只需要一直不断的调用next
方法,当done
为false
时获取当时的value
,done
为true
时停止即可。第一次接触遍历器的行为模式是在2016的冬天,那时底蕴不够鸡毛也没长全,理解不了简洁性的适用和强大。直到现在——在即将打包被迫离开公司的前夕才蓦然的醒觉。多么痛的领悟啊。
let iterator = [1, 2, 3][Symbol.iterator](); console.log( iterator.next() ); // {value: 1, done: false} console.log( iterator.next() ); // {value: 2, done: false} console.log( iterator.next() ); // {value: 3, done: false} console.log( iterator.next() ); // {value: undefined, done: true}
面向不同的数据结构,有不同的遍历器实现方法,我们简单的实现下数组的遍历器方法。
let res = null; let iterator = myIterator([3, 7]); console.log( iterator.next() ); // {value: 3, done: false} console.log( iterator.next() ); // {value: 7, done: false} console.log( iterator.next() ); // {value: undefined, done: true} function myIterator(array = []) { let index = 0; return { next() { return index < array.length ? { value: array[index++], done: false } : { value: undefined, done: true }; } }; }
除了为遍历器对象部署next
方法,还可以有return
和throw
方法。其中return
方法会在提前退出for of
循环时(通常是因为出错,或触发了break
语句)被调用。而throw
方法主要是配合Generator
函数使用,一般的遍历器对象用不到这个方法,所以不予介绍。
let obj = { [Symbol.iterator]() { let index = 0; let array = [1, 2, 3]; return { next() { return index < array.length ? { value: array[index++], done: false } : { value: undefined, done: true }; }, return() { console.log('Trigger return.'); return {}; } }; } }; for (let v of obj) { console.log(v); // 打印出:1, 2, 3,没触发 return 函数。 } for (let v of obj) { if (v === 2) break; console.log(v); // 打印出:1,之后触发 return 函数。 } for (let v of obj) { if (v === 3) break; console.log(v); // 打印出:1, 2,之后触发 return 函数。 } for (let v of obj) { if (v === 4) break; console.log(v); // 打印出:1, 2, 3,没触发 return 函数。 } for (let v of obj) { if (v === 2) throw Error('error'); console.log(v); // 打印出:1,之后触发 return 函数,并报错停止执行。 }
原生默认持有遍历器接口的数据结构有:
基本类型:Array
, Set
, Map
(四种基本数据集合:Array
, Object
, Set
和 Map
)。
类数组对象:arguments
, NodeList
, String
。
let iterator = '123'[Symbol.iterator](); console.log( iterator.next() ); // {value: "1", done: false} console.log( iterator.next() ); // {value: "2", done: false} console.log( iterator.next() ); // {value: "3", done: false} console.log( iterator.next() ); // {value: undefined, done: true}
遍历器与先前的遍历方法
一个数据集合拥有遍历器接口,并不意味着所有遍历它的方法都是使用此接口。实际上,只有ES6新增的几种方式和某些方法会使用,下面会有介绍。以数组来说,对其使用for
和for of
虽然可访问到相同的成员,但是实际的操作方式却不同。
// 改变数组默认的遍历器接口。 Array.prototype[Symbol.iterator] = function () { let index = 0; let array = this; console.log('Use iterator'); return { next() { return index < array.length ? { value: array[index++], done: false } : { value: undefined, done: true }; } } }; let arr = [1, 2]; for (let v of arr) { console.log(v); // 打印出 Use iterator, 1, 2。 } for (let i = 0; i < arr.length; i++) { console.log(arr[i]); // 打印出 1, 2。 } arr.forEach(d => { console.log(d); // 打印出 1, 2。 });
对象没有默认的遍历器接口
为什么对象没有默认的遍历器接口?这要从两方面说明。一为遍历器是种线性处理结构,对于任何非线性的数据结构,部署了遍历器接口,就等于部署一种线性转换。二是对象本来就是一个无序的集合,如果希望其有序,可以使用Map
Iterator
인터페이스를 배포합니다. 이는 해당 Symbol.iterator
속성이 를 반환할 수 있는 데이터 세트를 가리킨다는 의미입니다. 반복자
함수. 기본적으로 traverser를 사용하여 데이터 컬렉션에 액세스하는 모든 메소드는 이 속성을 호출하여 traverser 객체를 가져온 다음 설정된 순서에 따라 데이터 구조의 멤버에 액세스합니다(Symbol.iterator
의 마지막 섹션 참조). code> 섹션을 참조하세요). 예를 들어, 기본 배열의 반복자는 [][Symbol.iterator]
이거나 해당 배열의 프로토타입을 통해 직접 Array.prototype[Symbol.iterator]
를 얻을 수 있습니다. 건설자. 🎜Iterator
인터페이스를 호출하면 새 반복자 개체(포인터 개체)가 반환됩니다. next
메서드가 있어야 합니다. 포인터는 처음에 현재 데이터 구조의 시작 부분을 가리킵니다. 🎜🎜객체의 next
메서드가 처음 호출되면 포인터는 데이터 구조의 첫 번째 멤버를 가리킵니다. next
메서드가 두 번째로 호출되면 포인터는 데이터 구조의 두 번째 멤버를 가리킵니다. next
메서드를 계속 호출합니다. 🎜🎜next
메서드가 호출될 때마다 동일한 데이터 구조({ value, done }
)가 반환됩니다. 값
은 현재 멤버를 가리키는 값을 나타내고, 그렇지 않은 경우 정의되지 않음
입니다. done
은 순회가 종료되었는지 여부를 나타내는 부울 값입니다. 끝은 true
이고, 그렇지 않으면 false
입니다. 🎜🎜트래버서 인터페이스의 표준은 매우 간단하며 내부 포인터 작동, 값이 있는지 확인하는 등의 메서드를 제공하지 않습니다. next
메서드를 계속 호출하고 done
이 false
이면 현재 값
, 를 가져옵니다. 완료되면 중지
는 true
입니다. 트래버서의 행동 패턴을 처음 접한 것은 2016년 겨울이었습니다. 당시에는 단순성의 적용 가능성과 위력을 이해할 만큼 충분한 배경 지식이 없었습니다. 지금까지는 아니었지만, 짐을 싸서 강제로 회사를 떠나려고 했을 때 갑자기 잠에서 깨어났습니다. 참으로 고통스러운 깨달음입니다. 🎜let obj = { 0: 'a', 1: 'b', length: 2, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; let iterator = obj[Symbol.iterator](); console.log( iterator.next() ); // {value: "a", done: false} console.log( iterator.next() ); // {value: "b", done: false} console.log( iterator.next() ); // {value: undefined, done: true}
let obj = { 0: 'a', 1: 'b', length: 2, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; console.log( Object.keys(obj) ); // ["0", "1", "length"] for (let v of obj) { console.log(v); // 依次打印出:"a", "b"。 } for (let k in obj) { console.log(k); // 依次打印出:"0", "1", "length"。 }
next
메서드를 배포하는 것 외에도 return
및 throw도 있을 수 있습니다.
메소드. return
메소드는 for of
루프를 조기에 종료할 때 호출됩니다(대개 오류 또는 break
문 트리거로 인해). throw
메서드는 주로 Generator
함수와 함께 사용되며, 이 메서드는 일반 Traverser 객체에서는 사용되지 않으므로 소개하지 않습니다. 🎜for (let v of [1, 2, 3]) { console.log(v); // 依次打印出:1, 2, 3。 }🎜2 기본 지원🎜
배열
, Set, Map
(네 가지 기본 데이터 컬렉션: Array
, Object
, Set
및 지도
). 인수
, NodeList
, 문자열
. 🎜let [...a] = [3, 2, 1]; // [3, 2, 1] let b = [...[3, 2, 1]]; // [3, 2, 1]🎜순회자 및 이전 순회 방법
for
및 for of
를 사용하면 동일한 멤버에 액세스할 수 있지만 실제 작업은 다릅니다. 🎜for (let v of G()) { console.log(v); // 依次打印出:1, 2, 3, 4, 5 } function* G() { yield 1; yield* [2,3,4]; yield 5; }🎜객체에 기본 순회 인터페이스가 없습니다.
Map
을 대신 사용할 수 있습니다. 이는 모든 사람이 자신만의 장점을 갖고 있으며 각자 자신의 의무를 갖고 있음을 의미합니다. 쇠똥구리가 쇠똥구리를 굴리지 않고 꿀을 모으러 간다면, 꽃 파는 아가씨가 고통을 받을 수도 있습니다. 🎜自行生成的类数组对象(拥有length
属性),不具备遍历器接口。这与String
等原生类数组对象不同,毕竟人家是亲生的,一出生就含着金钥匙(也不怕误吞)。不过我们可以将数组的遍历器接口直接应用于自行生成的类数组对象,简单有效无副作用。
let obj = { 0: 'a', 1: 'b', length: 2, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; let iterator = obj[Symbol.iterator](); console.log( iterator.next() ); // {value: "a", done: false} console.log( iterator.next() ); // {value: "b", done: false} console.log( iterator.next() ); // {value: undefined, done: true}
为对象添加遍历器接口,也不影响之前不使用遍历器的方法,比如for in
, Object.keys
等等(两者不等同)。
let obj = { 0: 'a', 1: 'b', length: 2, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; console.log( Object.keys(obj) ); // ["0", "1", "length"] for (let v of obj) { console.log(v); // 依次打印出:"a", "b"。 } for (let k in obj) { console.log(k); // 依次打印出:"0", "1", "length"。 }
for of for of
是专门用来消费遍历器的,其遍历的是键值(for in
遍历的是键名)。
for (let v of [1, 2, 3]) { console.log(v); // 依次打印出:1, 2, 3。 }
扩展运算符
无论是解构赋值或扩展运算都是默认调用遍历器的。
let [...a] = [3, 2, 1]; // [3, 2, 1] let b = [...[3, 2, 1]]; // [3, 2, 1]
yield*
在Generator
函数中有yield*
命令,如果其后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
for (let v of G()) { console.log(v); // 依次打印出:1, 2, 3, 4, 5 } function* G() { yield 1; yield* [2,3,4]; yield 5; }
其它场合
有些接受数组作为参数的函数,会默认使用数组的遍历器接口,所以也等同于默认调用。比如Array.from()
, Promise.all()
。
相关推荐:
위 내용은 Iterator는 데이터 컬렉션에 액세스하기 위한 통합 인터페이스 방법입니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!