Home  >  Article  >  Web Front-end  >  Iterator is a unified interface method for accessing data collections.

Iterator is a unified interface method for accessing data collections.

不言
不言Original
2018-07-20 10:15:321715browse

This article introduces you to the unified interface method of Iterator accessing data collections. It has certain reference value. Friends in need can refer to it.

Introduction

TraverserIterator is a unified interface provided by ES6 for accessing data collections. For any data collection that has a traverser interface deployed internally, users can obtain the corresponding data structure in the same way. If you are using the latest version of the Chrome browser, then you need to know that the Miss Argument we are familiar with has quietly opened another path that can reach her heart.

1 Main topic

A certain data collection deploys the Iterator interface, which means that its Symbol.iterator attribute points to an interface that can return Iterator Interface functions. Any method that uses a traverser to access a data collection by default will call this property to get the traverser object, and then access the members of the data structure in the set order (see the last section for Symbol.iterator further reading). For example, the iterator of a native array is [][Symbol.iterator], or you can directly obtain Array.prototype[Symbol.iterator] through the prototype of its constructor.

1.1 Basic behavior

Calling the Iterator interface will return a new iterator object (pointer object).
There must be a next method in the object, which is used to access the next data member. The pointer initially points to the beginning of the current data structure.

The first time the object's next method is called, the pointer points to the first member of the data structure.
The second time the next method of the object is called, the pointer points to the second member of the data structure.
Continuously call the next method of the object until it points to the end of the data structure.

Every time the next method is called, the same data structure will be returned: { value, done }.
Where value represents the value currently pointing to the member, if not, it is undefined.
Where done is a Boolean value, indicating whether the traversal has ended. The end is true, otherwise false.

The standard of the traverser interface is very simple and does not provide methods such as operating internal pointers, determining whether there is a value, etc. Just keep calling the next method, and when done is false, get the current value, done Just stop when it is true. The first time I came into contact with the behavior pattern of the traverser was in the winter of 2016. At that time, I didn’t have enough background to understand the applicability and power of simplicity. It wasn't until now - just before I was about to pack up and be forced to leave the company that I suddenly woke up. What a painful realization.

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 Simple implementation

There are different traverser implementation methods for different data structures. We simply implement the array traverser method.

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

In addition to deploying the next method for the traverser object, there can also be return and throw method. The return method will be called when the for of loop is exited early (usually because of an error, or the break statement is triggered). The throw method is mainly used in conjunction with the Generator function. This method is not used by general traverser objects, so it will not be introduced.

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 Native support

2.1 The default holding traverser

The data structures of the native default holding traverser interface are:
Basic type: Array , Set, Map (four basic data collections: Array, Object, Set and Map).
Array-like objects: 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}

Traversers and previous traversal methods
Just because a data collection has a traverser interface does not mean that all methods that traverse it use this interface. In fact, only a few new methods and certain methods added in ES6 will be used, which will be introduced below. For arrays, using for and for of can access the same members, but the actual operations are different.

// 改变数组默认的遍历器接口。
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。
});

The object does not have a default traverser interface
Why does the object not have a default traverser interface? This should be explained from two aspects. First, the traverser is a linear processing structure. For any non-linear data structure, deploying the traverser interface is equivalent to deploying a linear transformation. Second, the object is originally an unordered collection. If you want it to be ordered, you can use Map instead. This means that everyone has his own strengths and everyone has his own duties. If the dung beetle doesn't roll the dung ball and goes to collect honey, then, well, the flower girl may suffer.

自行生成的类数组对象(拥有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封装数组方法

The above is the detailed content of Iterator is a unified interface method for accessing data collections.. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn