Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

迭代器和生成器 #4

Open
alianzhang opened this issue Mar 15, 2019 · 7 comments
Open

迭代器和生成器 #4

alianzhang opened this issue Mar 15, 2019 · 7 comments
Labels

Comments

@alianzhang
Copy link
Owner

alianzhang commented Mar 15, 2019

迭代器协议

可迭代协议

生成器

一点延伸 for of 与 forEach 与 for in

@alianzhang alianzhang changed the title 迭代器协议 迭代器和生成器 Mar 15, 2019
@alianzhang
Copy link
Owner Author

alianzhang commented Mar 15, 2019

迭代器协议

定义了一种标准的方式来产生一个有限或无限序列的值,并且当所有的值都已经被迭代后,就会有一个默认的返回值

迭代器iterator

在 JavaScript 中 迭代器是一个对象,它提供了一个next() 方法,用来返回序列中的下一项。这个方法返回包含两个属性done和 value的对象

简单迭代器实现

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

var it = makeIterator(['yo', 'ya']);

console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done);  // true

创造一个同时满足迭代器协议和可迭代协议的对象
一个良好的迭代即实现了迭代器协议,又实现了可迭代协议,方式就是可迭代协议返回的是自身

var obj = {
    count: 1,
    next() {
       const done = this.count > 3
       const value = this.count > 3 ?  undefined : this.count++
       return {value , done}
    },
    [Symbol.iterator]() { return this }
}
obj.next() // {value: 1, done: false}
obj.next() // {value: 2, done: false}
obj.next() // {value: 3, done: false}
obj.next() // {value: undefined, done: true}
obj.next() // {value: undefined, done: true}
...
for (let i of obj){console.log(i)}  // 1  2  3 

@alianzhang
Copy link
Owner Author

alianzhang commented Mar 15, 2019

可迭代协议

允许 JavaScript 对象去定义或定制它们的迭代行为。

可迭代对象iterable

一个定义了迭代行为的对象,具有Symbol.iterator属性

一些内置类型都是内置的可迭代类型并且有默认的迭代行为, 比如 String, Array, TypedArray,arguments, Map and Set它们的原型对象都有一个 @@iterator 方法
另一些类型则不是 (比如Object) 为了变成可迭代对象, 一个对象必须实现 @@iterator 方法, 意思是这个对象(或者它原型链 prototype chain 上的某个对象)必须有[Symbol.iterator]属性 :返回一个对象的无参函数,被返回对象符合迭代器协议。

自定义可迭代对象

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable]; // [1, 2, 3]
const foo ={
 0: 'a',
 1: 'b',
 length: 2,
 [Symbol.iterator]: Array.prototype[Symbol.iterator]
}

用于可迭代对象的语法for-of,扩展运算符,yield*,解构赋值

接受可迭代对象的函数Map([iterable]), WeakMap([iterable]), Set([iterable]) and WeakSet([iterable])

var myObj = {};
new Map([[1,"a"],[2,"b"],[3,"c"]]).get(2);               // "b"
new WeakMap([[{},"a"],[myObj,"b"],[{},"c"]]).get(myObj); // "b"
new Set([1, 2, 3]).has(3);                               // true
new Set("123").has("2");                                 // true
new WeakSet(function*() {
    yield {};
    yield myObj;
    yield {};
}()).has(myObj);                                         // true

判断对象是否为可迭代对象的方法:

typeof obj[Symbol.iterator] === 'function'

@alianzhang
Copy link
Owner Author

alianzhang commented Mar 15, 2019

生成器Generator:

生成器Generator对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。

generator function:function* 这种声明方式会定义一个生成器函数 ,它返回一个 Generator 对象,这个Generator只能被迭代一次

function* gen() { 
  yield 1;
  yield 2;
  yield 3;
}

let g = gen();   // "Generator { }"

Generator方法:
Generator.prototype.next()返回一个由 yield表达式生成的值。
Generator.prototype.return()返回给定的值并结束生成器。
Generator.prototype.throw()向生成器抛出一个错误。

yield 关键字用来暂停和恢复一个生成器函数
yield* 表达式用于委托给另一个generator 或可迭代对象

@alianzhang
Copy link
Owner Author

alianzhang commented Mar 15, 2019

生成器对象到底是一个迭代器还是一个可迭代对象?

生成器对象既是迭代器也是可迭代对象:一个良好的迭代即实现了迭代器协议,又实现了可迭代协议,方式就是可迭代协议返回的是自身

var aGeneratorObject = function*(){
    yield 1;
    yield 2;
    yield 3;
}();
typeof aGeneratorObject.next;
// "function", because it has a next method, so it's an iterator
typeof aGeneratorObject[Symbol.iterator];
// "function", because it has an @@iterator method, so it's an iterable
aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
// true, because its @@iterator method return its self (an iterator), so it's an well-formed iterable
[...aGeneratorObject];
// [1, 2, 3]

@alianzhang
Copy link
Owner Author

1.避免开发者使用for循环还要控制index等,我们有了iterator就可以用for of。
2.如何用50M内存处理3G数据。如果用for循环的话,需要一次把数据放到内存里处理但是内存太小了。迭代器不用,迭代器每次处理一个数据,只把这个数据放到内存里。
3.因为有每次next执行完后会停止执行,可以封装用于异步的api。

@alianzhang
Copy link
Owner Author

ES6迭代器和生成器

@alianzhang
Copy link
Owner Author

alianzhang commented Jan 2, 2020

for of 用于循环可迭代对象,包括有 Array, Set, Map, 字符串
另外,NodeList 不是 Array, Set, Map,但是一个可迭代对象,可以用 for of 遍历

document.getElementsByTagName("div") 返回的是类数组对象,不是一个数组,但是一个可迭代对象,可以用 for of 遍历
所谓类数组对象,就是含 length 和索引属性的对象

Array, Set, Map 都有 forEach 方法
但是 用 for of 循环对象时可以通过 break 提前终止,而 forEach 无法提前跳出循环

for in 遍历对象的可枚举属性,包括其原型链上的属性,且不保证顺序

若要遍历对象自身的可枚举属性,使用 hasOwnProperty() 方法来确定属性是否是对象自身属性
Object.getOwnPropertyNames(obj) , 返回对象自身可枚举或不可枚举属性
Object.assign() 方法将所有可枚举属性的值从一个或多个源对象复制到目标对象

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }  // 注意目标对象自身也会改变。

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant