YvetteLau / Step-By-Step

不积跬步,无以至千里;
704 stars 66 forks source link

可迭代对象有什么特点? #28

Open YvetteLau opened 5 years ago

luohong123 commented 5 years ago

可迭代对象的特点

image

代码如下:

function makeIterator(array){
    var nextIndex = 0;
    return {
       next: function(){
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
}
// 使用 next 方法依次访问对象中的键值
var it = makeIterator(['step', 'by','step']);
console.log(it.next().value); // 'step'
console.log(it.next().value); // 'by'
console.log(it.next().value); // 'step'
console.log(it.next().value);  // undefined
console.log(it.next().done); // true

参考文章

AILINGANGEL commented 5 years ago

可迭代对象可以采用统一的接口对对象进行遍历,比如for...of, 而不需要关注对象内部的具体结构。在JS中可迭代的对象需要返回一个包含next方法的对象,next方法再返回一个包含value和done两个属性的对象。value是指每次迭代的值,而done用来表示是否已经迭代完毕。

给一个对象定义一个迭代器,使之可以采用for...of来迭代属性所对应的值.

let obj = {
    name: 'age',
    age: 20,
    sex: 'female',
    [Symbol.iterator]() {
        var self = this;
        var i = 0;
        var keys = Object.keys(this);
        return {
            next() {
                if (i < keys.length) {
                    return {
                        value: self[keys[i++]],
                        done: false
                    }
                } else {
                    return {
                        value: undefined,
                        done: true
                    }
                }
            }
        }
    }
}
for (let item of obj) {
    console.log(item); // age 20 female
}
shenanheng commented 5 years ago

数据结构: a:Array b:Object c:Map d:Set 可迭代的对象 => 数据结构只要部署了迭代器的接口 在原生的数据类型中(有Symbol.iterator)

特点: a:获取value与done b:next()方法可以指向下一个指针

riluocanyang commented 5 years ago

可迭代对象有什么特点?

数组常用的可迭代方法有:

  1. every()
  2. some()
  3. filter()
  4. forEach()
  5. map()
  6. for...of ...

    对象常用的可迭代方法有:

  7. Object.keys()
  8. Object.values()
  9. Object.entries()
  10. for... in
  11. for... of ...

它们的特点:

迭代器(Iterator):其内部都返回了next()方法,每次调用next方法都返回了一个对象,这个对象有两个属性,分别是value和done,value表示下一个将要返回的值,如果没有更多数据,done值为true。 迭代对象(Iterable):具有迭代器的属性,也就是能够通过一个函数返回一个迭代器。

woyiweita commented 5 years ago

可迭代对象可通过 for...of进行循环。

模拟迭代器:

    function makeIterator(arr) {
        var nextIndex = 0;
        return {
            next: function () {
                return nextIndex < arr.length ? {
                    done: false,
                    value: arr[nextIndex++]
                } : {
                    done: true
                };
            }
        }
    }

    var it = makeIterator(['a', 'b', 1, 6, NaN, null, undefined]);
    var res;
    do {
        res = it.next();
        console.info(res.value);
    } while (!res.done);

为了实现可迭代,一个对象必须实现 iterator 方法,这意味着这个对象(或其原型链中的一个对象)必须具有带 Symbol.iterator 键的属性

判断当前对象是否为可迭代对象,检测该对象是否具备 Symbol.iterator 属性。

    // 以数组为例
    Array.prototype.hasOwnProperty(Symbol.iterator); // => true

可通过检测当前对象是否具有Symbol.iterator属性来判断当前对象是否为可迭代对象。Symbol.iterator 是一个函数,所以通过typeof来检测返回值,如果返回值为'function'则为可迭代对象,如果返回值为'undefined'则为不可迭代对象。

    typeof [][Symbol.iterator]; // => 'function'
    typeof {}[Symbol.iterator]; // => 'undefined'
    typeof new Set()[Symbol.iterator]; // => 'function'
    typeof new Map()[Symbol.iterator]; // => 'function'
    typeof ''[Symbol.iterator]; // => 'function'
    var list = document.querySelectorAll('p'); // 获取dom节点
    typeof list[Symbol.iterator]; // => 'function'
    typeof new Int8Array()[Symbol.iterator]  // => 'function'
    (function(){
        typeof arguments[Symbol.iterator]; // => 'function'
    })();

原生具备 Iterator 接口的数据结构如下。

数组如何使用.next() 方法:

    var arr = [1,2,3];
    var si = arr[Symbol.iterator]();
    si.next(); //=> {value: 1, done: false}
    si.next(); //=> {value: 2, done: false}
    si.next(); //=> {value: 3, done: false}
    si.next(); //=> {value: undefined, done: true}

如何实现一个自定义的可迭代对象:

    var myIterator = {};
    myIterator[Symbol.iterator] = function* () {
        yield 'Bryan';
        yield 'programmer';
        yield 'bachelordom';
    }
    for (let val of myIterator) {
        console.info(val);
    }
    // Bryan
    // programmer
    // bachelordom

总结

可迭代对象的特点:

jodiezhang commented 5 years ago

首先了解遍历器的概念(iterator) 它是一种接口,为各种不同的数据结构提供统一的访问机制。 任何数据结构,只要部署了Iterator接口,就可以完成遍历操作。 Iterator的作用有三个: 一个是为各种数据提供一个统一的,简便的访问接口 二是使得数据结构的成员能够按照某种次序排列 三是ES6创造了一种新的遍历命令,for...of循环,Iterator接口主要供for...of消费

Iterator的遍历过程如下: 1.创建一个指针对象,指向当前数据结构的起始位置。 2.第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员 3.第二次调用指针对象的next方法,指针就指向数据结构的第二个成员 4.不断调用指针对象的next方法,直到它指向数据结构的结束位置 每次调用next方法都会返回数据结构的当前成员信息。具体来说,就是返回一个包含value和done两个属性的对象。其中value是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

var it=makeIterator(['a','b']);
it.next()
it.next()
it.next()

function makeIterator(array) {
var nextIndex=0;
return {
next: function(){
return nextIndex<array.length?
          {value:array[nextIndex++],done:false}:
          {value:undefined,done:true};
}
}
}

数据结构只要部署了Iterator接口,我们就称这种数据结构为可遍历的或者可迭代的。 ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性,或者说一个数据结构只要具有Symbol.iterator属性,就可以认为是可遍历的(iterable)。 原生具备Iterator接口的数据结构如下:

Array
Map
Set
String
TypeArray
函数的arguments对象
NodeList对象

为一个对象添加Iterator 接口

let obj={
data: ['hello','world'],
[Symbol.iterator](){
const self=this;
let index=0;
return {
next(){
if(index<self.data.length){
return {
value:self.data[index++],
data: false
}
}else{
return {value:undefined,done:true}
}
}
}
}
}

Symbol.iterator方法最简单的实现还是用Generator函数

let obj={
*[Symbol.iterator](){
yield 'hello';
yield 'world';
}
}
for(let x of obj){
console.log(x);
}

引用:ES6标准入门-阮一峰

chongyangwang commented 5 years ago

数组的可迭代方法:

  1. array.foreach
  2. array.some
  3. array.every
  4. array.map
  5. array.filter

对象的可迭代方法

  1. object.keys() 2.object.values()
  2. for of
  3. for in

实现 copy form https://github.com/luohong123

function makeIterator(array){
    var nextIndex = 0;
    return {
       next: function(){
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
}
// 使用 next 方法依次访问对象中的键值
var it = makeIterator(['step', 'by','step']);
console.log(it.next().value); // 'step'
console.log(it.next().value); // 'by'
console.log(it.next().value); // 'step'
console.log(it.next().value);  // undefined
console.log(it.next().done); // true
yelin1994 commented 5 years ago

可迭代对象有什么特点

遍历器(Interator)

定义: 他是一种接口, 为各种不同的数据结构提供统一的访问机制。 任何数据只要部署interator接口,就可以完成遍历操作。其主要供for...of 消费。(w3c定义)

遍历过程:

原生具备可迭代(遍历的对象)(这边以for...of 区分):

var a = { name: 'Jimmy', age: 18, job: 'actor' } for (var i of a) { console.log(i) }

或者也可采用

Object.prototype[Symbol.iterator] = function () { var i = 0 const names = Object.entries(this) return { next: function () { var done = (i >= names.length) var value = !done ? names[i++]: undefined return { done: done, value: value } } } } var a = { name: 'Jimmy', age: 18, job: 'actor' } for (var i of a) { console.log(i) }

YvetteLau commented 5 years ago

ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,换个角度,也可以认为,一个数据结构只要具有 Symbol.iterator 属性(Symbol.iterator 方法对应的是遍历器生成函数,返回的是一个遍历器对象),那么就可以其认为是可迭代的。

可迭代对象的特点

let arry = [1, 2, 3, 4];
let iter = arry[Symbol.iterator]();
console.log(iter.next()); //{ value: 1, done: false }
console.log(iter.next()); //{ value: 2, done: false }
console.log(iter.next()); //{ value: 3, done: false }

原生具有 Iterator 接口的数据结构:

自定义一个可迭代对象

上面我们说,一个对象只有具有正确的 Symbol.iterator 属性,那么其就是可迭代的,因此,我们可以通过给对象新增 Symbol.iterator 使其可迭代。

let obj = {
    name: "Yvette",
    age: 18,
    job: 'engineer',
    *[Symbol.iterator]() {
        const self = this;
        const keys = Object.keys(self);
        for (let index = 0; index < keys.length; index++) {
            yield self[keys[index]];//yield表达式仅能使用在 Generator 函数中
        }
    }
};

for (var key of obj) {
    console.log(key); //Yvette 18 engineer
}
KRISACHAN commented 5 years ago

可迭代对象的特点就是可迭代。。。 一个具有 @@iterator 方法的对象,当然这个可以通过 Symbol.iterator 去生成

MissNanLan commented 5 years ago

遍历器(Iterator)它是一种借口,为各种不同的数据结构提供统一的访问机制。 任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。 它的作用有三个: 一是为各种数据结构,提供一个统一的、简便的访问接口; 二是使得数据接口的成员能够按照某种次序排列; 三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要提供for...of消费

遍历过程,创建一个指针对象,调用指针的next方法,每调用依次next方法,就会返回valuedone两个属性对象,value属性是当前成员的值,done属性是一个布尔值,表示循环可以结束

var it = makeIterator(['a','b']);
console.log(it.next());
console.log(it.next());
console.log(it.next());

function makeIterator(array){
  var nextIndex = 0;
  return {
    next: function(){
      return nextIndex < array.length ?
        { value: array[nextIndex++],done: false }:
        {value:undefined,done: true}
    }
  }
}

具有原生Iterator接口的数据结构

Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象

凡是部署了Symbol.iterator属性,都称之为部署了遍历器接口,返回一个遍历器对象;对于原生部署了Iterator接口,for...of会自动去遍历,如果没有的话(比如对象),都需要自己在Symbol.iterator属性上面部署

总结: 一个数据结构(数组、Map、Set,某些类似数组的对象——比如arguments对象,DOM NodeList对象,Generator对象,字符串等),才可以被for...of循环遍历。 换句话说就是for...of 循环内部调用的是数据结构Symbol.iterator方法

[更多请参考参考阮一峰](http://es6.ruanyifeng.com/#docs/iterator