>웹 프론트엔드 >JS 튜토리얼 >Iterator는 데이터 컬렉션에 액세스하기 위한 통합 인터페이스 방법입니다.

Iterator는 데이터 컬렉션에 액세스하기 위한 통합 인터페이스 방법입니다.

不言
不言원래의
2018-07-20 10:15:321793검색

이 기사에서는 Iterator를 통해 데이터 수집에 액세스하는 통합 인터페이스 방법을 소개합니다. 이는 필요한 참조 가치가 있습니다.

Introduction

Traverser Iterator는 데이터 컬렉션에 액세스하기 위해 ES6에서 제공하는 통합 인터페이스입니다. 내부적으로 배포된 순회 인터페이스가 있는 모든 데이터 컬렉션의 경우 사용자는 동일한 방식으로 해당 데이터 구조를 얻을 수 있습니다. 최신 버전의 Chrome 브라우저를 사용하고 계시다면, 우리에게 익숙한 미스 어레이가 그녀의 마음에 닿을 수 있는 또 다른 길을 조용히 열어주었다는 것을 알아야 합니다. Iterator是ES6为访问数据集合提供的统一接口。任何内部部署了遍历器接口的数据集合,对于用户来说,都可以使用相同方式获取到相应的数据结构。如果使用的是最新版Chrome浏览器,那么你要知道——我们所熟悉的数组小姐,已悄悄的打开了另一扇可抵达她心扉的小径。

1 正题

某个数据集合部署了Iterator接口,是指其Symbol.iterator属性指向一个能返回Iterator接口的函数。任何默认使用遍历器访问数据集合的方法,都会调用此属性以得到遍历器对象,再按照设定的顺序依次访问该数据结构的成员(关于Symbol.iterator请看最后一节的延伸阅读)。比如原生数组的遍历器为[][Symbol.iterator],也可以直接通过其构造函数的原型获取Array.prototype[Symbol.iterator]

1.1 基本行为

调用Iterator接口会返回一个新的遍历器对象(指针对象)。  
对象中必然有next方法,用于访问下一个数据成员。指针初始时指向当前数据结构的起始位置。

第一次调用对象的next方法,指针指向数据结构的第一个成员。  
第二次调用对象的next方法,指针指向数据结构的第二个成员。  
不断的调用对象的next方法,直到它指向数据结构的结束位置。

每次调用next方法,都会返回相同的数据结构:{ value, done }。  
其中value表示当前指向成员的值,没有则为undefined。  
其中done是一个布尔值,表示遍历是否结束,结束为true,否则false

遍历器接口的标准十分简洁,不提供诸如:操作内部指针、判断是否有值等等方法。只需要一直不断的调用next方法,当donefalse时获取当时的valuedonetrue时停止即可。第一次接触遍历器的行为模式是在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}

1.2 简单实现

面向不同的数据结构,有不同的遍历器实现方法,我们简单的实现下数组的遍历器方法。

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 };
    }
  };
}

1.3 return & throw

除了为遍历器对象部署next方法,还可以有returnthrow方法。其中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(&#39;Trigger return.&#39;);
        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(&#39;error&#39;);
  console.log(v); // 打印出:1,之后触发 return 函数,并报错停止执行。
}

2 原生支持

2.1 默认持有遍历器

原生默认持有遍历器接口的数据结构有:
基本类型:Array, Set, Map(四种基本数据集合:Array, Object, SetMap)。
类数组对象:arguments, NodeList, String

let iterator = &#39;123&#39;[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新增的几种方式和某些方法会使用,下面会有介绍。以数组来说,对其使用forfor of虽然可访问到相同的成员,但是实际的操作方式却不同。

// 改变数组默认的遍历器接口。
Array.prototype[Symbol.iterator] = function () {
  let index = 0;
  let array = this;

  console.log(&#39;Use iterator&#39;);

  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

1 주요 주제🎜🎜특정 데이터 컬렉션은 Iterator 인터페이스를 배포합니다. 이는 해당 Symbol.iterator 속성이 를 반환할 수 있는 데이터 세트를 가리킨다는 의미입니다. 반복자 함수. 기본적으로 traverser를 사용하여 데이터 컬렉션에 액세스하는 모든 메소드는 이 속성을 호출하여 traverser 객체를 가져온 다음 설정된 순서에 따라 데이터 구조의 멤버에 액세스합니다(Symbol.iterator의 마지막 섹션 참조). code> 섹션을 참조하세요). 예를 들어, 기본 배열의 반복자는 [][Symbol.iterator]이거나 해당 배열의 프로토타입을 통해 직접 Array.prototype[Symbol.iterator]를 얻을 수 있습니다. 건설자. 🎜

1.1 기본 동작

🎜 Iterator 인터페이스를 호출하면 새 반복자 개체(포인터 개체)가 반환됩니다.
객체에는 다음 데이터 멤버에 액세스하는 데 사용되는 next 메서드가 있어야 합니다. 포인터는 처음에 현재 데이터 구조의 시작 부분을 가리킵니다. 🎜🎜객체의 next 메서드가 처음 호출되면 포인터는 데이터 구조의 첫 번째 멤버를 가리킵니다.
객체의 next 메서드가 두 번째로 호출되면 포인터는 데이터 구조의 두 번째 멤버를 가리킵니다.
데이터 구조의 끝을 가리킬 때까지 개체의 next 메서드를 계속 호출합니다. 🎜🎜next 메서드가 호출될 때마다 동일한 데이터 구조({ value, done })가 반환됩니다.
여기서 은 현재 멤버를 가리키는 값을 나타내고, 그렇지 않은 경우 정의되지 않음입니다.
여기서 done은 순회가 종료되었는지 여부를 나타내는 부울 값입니다. 끝은 true이고, 그렇지 않으면 false입니다. 🎜🎜트래버서 인터페이스의 표준은 매우 간단하며 내부 포인터 작동, 값이 있는지 확인하는 등의 메서드를 제공하지 않습니다. next 메서드를 계속 호출하고 donefalse이면 현재 , 를 가져옵니다. 완료되면 중지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}

1.2 간단한 구현

🎜 다양한 데이터 구조에 대해 다양한 순회기 구현 방법이 있습니다. 우리는 단순히 배열 순회기 방법을 구현합니다. 🎜
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"。
}

1.3 return & throw

🎜traverser 객체에 대한 next 메서드를 배포하는 것 외에도 returnthrow도 있을 수 있습니다. 메소드. return 메소드는 for of 루프를 조기에 종료할 때 호출됩니다(대개 오류 또는 break 문 트리거로 인해). throw 메서드는 주로 Generator 함수와 함께 사용되며, 이 메서드는 일반 Traverser 객체에서는 사용되지 않으므로 소개하지 않습니다. 🎜
for (let v of [1, 2, 3])  {
  console.log(v); // 依次打印出:1, 2, 3。
}
🎜2 기본 지원🎜

2.1 기본적으로 순회기 보유

🎜기본적으로 순회기 인터페이스를 보유하는 데이터 구조는 다음과 같습니다.
기본 유형: 배열, Set, Map(네 가지 기본 데이터 컬렉션: Array, Object, Set지도).
배열형 객체: 인수, NodeList, 문자열. 🎜
let [...a] = [3, 2, 1]; // [3, 2, 1]
let b = [...[3, 2, 1]]; // [3, 2, 1]
🎜순회자 및 이전 순회 방법
데이터 컬렉션에 순회자 인터페이스가 있다고 해서 이를 순회하는 모든 방법이 이 인터페이스를 사용한다는 의미는 아닙니다. 실제로 몇 가지 새로운 메소드와 ES6에 추가된 특정 메소드만 사용될 예정인데, 이에 대해 아래에서 소개하겠습니다. 배열의 경우 forfor 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"。
}

2.2 默认调用遍历器

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()

相关推荐:

angularjs关于页面模板清除的使用方法

在JS中用slice封装数组方法

위 내용은 Iterator는 데이터 컬렉션에 액세스하기 위한 통합 인터페이스 방법입니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.