Flask接口签名sign原理与实例代码浅析
217
2023-04-17
深入理解ES6的迭代器与生成器
本文介绍了深入理解ES6的迭代器与生成器,分享给大家,具体如下:
循环语句的问题
var colors = ["red", "green", "blue"];
for(var i=0; i console.log(colors[i]); } 在ES6之前,这种标准的for循环,通过变量来跟踪数组的索引。如果多个循环嵌套就需要追踪多个变量,代码复杂度会大大增加,也容易产生错用循环变量的bug。 迭代器的出现旨在消除这种复杂性并减少循环中的错误。 什么是迭代器 我们先感受一下用ES5语法模拟创建一个迭代器: function createIterator(items) { var i = 0; return { // 返回一个迭代器对象 next: function() { // 迭代器对象一定有个next()方法 var done = (i >= items.length); var value = !done ? items[i++] : undefined; return { // next()方法返回结果对象 value: value, done: done }; } }; } var iterator = createIterator([1, 2, 3]); 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: undefiend, done: true}" // 之后所有的调用都会返回相同内容 console.log(iterator.next()); // "{ value: undefiend, done: true}" 以上,我们通过调用createIterator()函数,返回一个对象,这个对象存在一个next()方法,当next()方法被调用时,返回格式{ value: 1, done: false}的结果对象。 因此,我们可以这么定义:迭代器是一个拥有next()方法的特殊对象,每次调用next()都返回一个结果对象。 借助这个迭代器对象,我们来改造刚开始那个标准的for循环【暂时先忘记ES6的for-of循环新特性】: var colors = ["red", "green", "blue"]; var iterator = createIterator(colors); while(!iterator.next().done){ console.log(iterator.next().value); } what?,消除循环变量而已,需要搞这么麻烦,代码上不是得不偿失了吗? 并非如此,毕竟createIterator()只需写一次,就可以一直复用。不过ES6引入了生成器对象,可以让创建迭代器的过程变得更加简单。 什么是生成器 生成器是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。 function *createIterator(items) { for(let i=0; i yield items[i]; } } let iterator = createIterator([1, 2, 3]); // 既然生成器返回的是迭代器,自然就可以调用迭代器的next()方法 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: undefiend, done: true}" // 之后所有的调用都会返回相同内容 console.log(iterator.next()); // "{ value: undefiend, done: true}" 上面,我们用ES6的生成,大大简化了迭代器的创建过程。我们给生成器函数createIterator()传入一个items数组,函数内部,for循环不断从数组中生成新的元素放入迭代器中,每遇到一个yield语句循环都会停止;每次调用迭代器的next()方法,循环便继续运行并停止在下一条yield语句处。 生成器的创建方式 生成器是个函数: function *createIterator(items) { ... } 可以用函数表达式方式书写: let createIterator = function *(item) { ... } 也可以添加到对象中,ES5风格对象字面量: let o = { createIterator: function *(items) { ... } }; let iterator = o.createIterator([1, 2, 3]); ES6风格的对象方法简写方式: let o = { *createIterator(items) { ... } }; let iterator = o.createIterator([1, 2, 3]); 可迭代对象 在ES6中,所有的集合对象(数组、Set集合及Map集合)和字符串都是可迭代对象,可迭代对象都绑定了默认的迭代器。 来了来了,姗姗来迟的ES6循环新特性for-of: var colors = ["red", "green", "blue"]; for(let color of colors){ console.log(color); } for-of循环,可作用在可迭代对象上,正是利用了可迭代对象上的默认迭代器。大致过程是:for-of循环每执行一次都会调用可迭代对象的next()方法,并将迭代器返回的结果对象的value属性存储在变量中,循环将继续执行这一过程直到返回对象的done属性的值为true。 如果只需要迭代数组或集合中的值,用for-of循环代替for循环是个不错的选择。 访问默认迭代器 可迭代对象,都有一个Symbol.iterator方法,for-of循环时,通过调用colors数组的Symbol.iterator方法来获取默认迭代器的,这一过程是在javascript引擎背后完成的。 我们可以主动获取一下这个默认迭代器来感受一下: let values = [1, 2, 3]; let iterator = values[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}" 在这段代码中,通过Symbol.iterator获取了数组values的默认迭代器,并用它遍历数组中的元素。在javaScript引擎中执行for-of循环语句也是类似的处理过程。 用Symbol.iterator属性来检测对象是否为可迭代对象: function isIterator(object) { return typeof object[Symbol.iterator] === "function"; } console.log(isIterable([1, 2, 3])); // true console.log(isIterable(new Set())); // true console.log(isIterable(new Map())); // true console.log(isIterable("Hello")); // true 创建可迭代对象 当我们在创建对象时,给Symbol.iterator属性添加一个生成器,则可以将其变成可迭代对象: let collection = { items: [], *[Symbol.iterator]() { // 将生成器赋值给对象的Symbol.iterator属性来创建默认的迭代器 for(let item of this.items) { yield item; } } }; collection.items.push(1); collection.items.push(2); collection.items.push(3); for(let x of collection) { console.log(x); } 内建迭代器 ES6中的集合对象,数组、Set集合和Map集合,都内建了三种迭代器: entries() 返回一个迭代器,其值为多个键值对。如果是数组,第一个元素是索引位置;如果是Set集合,第一个元素与第二个元素一样,都是值。 values() 返回一个迭代器,其值为集合的值。 keys() 返回一个迭代器,其值为集合中的所有键名。如果是数组,返回的是索引;如果是Set集合,返回的是值(Set的值被同时用作键和值)。 不同集合的默认迭代器 每个集合类型都有一个默认的迭代器,在for-of循环中,如果没有显式指定则使用默认的迭代器。按常规使用习惯,我们很容易猜到,数组和Set集合的默认迭代器是values(),Map集合的默认迭代器是entries()。 请看以下示例: let colors = [ "red", "green", "blue"]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ECMAScript 6"); data.set("format", "print"); // 与调用colors.values()方法相同 for(let value of colors) { console.log(value); } // 与调用tracking.values()方法相同 for(let num of tracking) { console.log(num); } // 与调用data.entries()方法相同 for(let entry of data) { console.log(entry); } 这段代码会输入以下内容: "red" "green" "blue" 1234 5678 9012 ["title", "Understanding ECMAScript 6"] ["format", "print"] for-of循环配合解构特性,操纵数据会更方便: for(let [key, value] of data) { console.log(key + "=" + value); } 展开运算符操纵可迭代对象 let set = new Set([1, 2, 3, 4, 5]), array = [...set]; console.log(array); // [1,2,3,4,5] 展开运算符可以操作所有的可迭代对象,并根据默认迭代器来选取要引用的值,从迭代器读取所有值。然后按返回顺序将它们依次插入到数组中。因此如果想将可迭代对象转换为数组,用展开运算符是最简单的方法。
console.log(colors[i]);
}
在ES6之前,这种标准的for循环,通过变量来跟踪数组的索引。如果多个循环嵌套就需要追踪多个变量,代码复杂度会大大增加,也容易产生错用循环变量的bug。
迭代器的出现旨在消除这种复杂性并减少循环中的错误。
什么是迭代器
我们先感受一下用ES5语法模拟创建一个迭代器:
function createIterator(items) {
var i = 0;
return { // 返回一个迭代器对象
next: function() { // 迭代器对象一定有个next()方法
var done = (i >= items.length);
var value = !done ? items[i++] : undefined;
return { // next()方法返回结果对象
value: value,
done: done
};
}
};
}
var iterator = createIterator([1, 2, 3]);
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: undefiend, done: true}"
// 之后所有的调用都会返回相同内容
console.log(iterator.next()); // "{ value: undefiend, done: true}"
以上,我们通过调用createIterator()函数,返回一个对象,这个对象存在一个next()方法,当next()方法被调用时,返回格式{ value: 1, done: false}的结果对象。
因此,我们可以这么定义:迭代器是一个拥有next()方法的特殊对象,每次调用next()都返回一个结果对象。
借助这个迭代器对象,我们来改造刚开始那个标准的for循环【暂时先忘记ES6的for-of循环新特性】:
var colors = ["red", "green", "blue"];
var iterator = createIterator(colors);
while(!iterator.next().done){
console.log(iterator.next().value);
}
what?,消除循环变量而已,需要搞这么麻烦,代码上不是得不偿失了吗?
并非如此,毕竟createIterator()只需写一次,就可以一直复用。不过ES6引入了生成器对象,可以让创建迭代器的过程变得更加简单。
什么是生成器
生成器是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。
function *createIterator(items) {
for(let i=0; i yield items[i]; } } let iterator = createIterator([1, 2, 3]); // 既然生成器返回的是迭代器,自然就可以调用迭代器的next()方法 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: undefiend, done: true}" // 之后所有的调用都会返回相同内容 console.log(iterator.next()); // "{ value: undefiend, done: true}" 上面,我们用ES6的生成,大大简化了迭代器的创建过程。我们给生成器函数createIterator()传入一个items数组,函数内部,for循环不断从数组中生成新的元素放入迭代器中,每遇到一个yield语句循环都会停止;每次调用迭代器的next()方法,循环便继续运行并停止在下一条yield语句处。 生成器的创建方式 生成器是个函数: function *createIterator(items) { ... } 可以用函数表达式方式书写: let createIterator = function *(item) { ... } 也可以添加到对象中,ES5风格对象字面量: let o = { createIterator: function *(items) { ... } }; let iterator = o.createIterator([1, 2, 3]); ES6风格的对象方法简写方式: let o = { *createIterator(items) { ... } }; let iterator = o.createIterator([1, 2, 3]); 可迭代对象 在ES6中,所有的集合对象(数组、Set集合及Map集合)和字符串都是可迭代对象,可迭代对象都绑定了默认的迭代器。 来了来了,姗姗来迟的ES6循环新特性for-of: var colors = ["red", "green", "blue"]; for(let color of colors){ console.log(color); } for-of循环,可作用在可迭代对象上,正是利用了可迭代对象上的默认迭代器。大致过程是:for-of循环每执行一次都会调用可迭代对象的next()方法,并将迭代器返回的结果对象的value属性存储在变量中,循环将继续执行这一过程直到返回对象的done属性的值为true。 如果只需要迭代数组或集合中的值,用for-of循环代替for循环是个不错的选择。 访问默认迭代器 可迭代对象,都有一个Symbol.iterator方法,for-of循环时,通过调用colors数组的Symbol.iterator方法来获取默认迭代器的,这一过程是在javascript引擎背后完成的。 我们可以主动获取一下这个默认迭代器来感受一下: let values = [1, 2, 3]; let iterator = values[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}" 在这段代码中,通过Symbol.iterator获取了数组values的默认迭代器,并用它遍历数组中的元素。在javaScript引擎中执行for-of循环语句也是类似的处理过程。 用Symbol.iterator属性来检测对象是否为可迭代对象: function isIterator(object) { return typeof object[Symbol.iterator] === "function"; } console.log(isIterable([1, 2, 3])); // true console.log(isIterable(new Set())); // true console.log(isIterable(new Map())); // true console.log(isIterable("Hello")); // true 创建可迭代对象 当我们在创建对象时,给Symbol.iterator属性添加一个生成器,则可以将其变成可迭代对象: let collection = { items: [], *[Symbol.iterator]() { // 将生成器赋值给对象的Symbol.iterator属性来创建默认的迭代器 for(let item of this.items) { yield item; } } }; collection.items.push(1); collection.items.push(2); collection.items.push(3); for(let x of collection) { console.log(x); } 内建迭代器 ES6中的集合对象,数组、Set集合和Map集合,都内建了三种迭代器: entries() 返回一个迭代器,其值为多个键值对。如果是数组,第一个元素是索引位置;如果是Set集合,第一个元素与第二个元素一样,都是值。 values() 返回一个迭代器,其值为集合的值。 keys() 返回一个迭代器,其值为集合中的所有键名。如果是数组,返回的是索引;如果是Set集合,返回的是值(Set的值被同时用作键和值)。 不同集合的默认迭代器 每个集合类型都有一个默认的迭代器,在for-of循环中,如果没有显式指定则使用默认的迭代器。按常规使用习惯,我们很容易猜到,数组和Set集合的默认迭代器是values(),Map集合的默认迭代器是entries()。 请看以下示例: let colors = [ "red", "green", "blue"]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ECMAScript 6"); data.set("format", "print"); // 与调用colors.values()方法相同 for(let value of colors) { console.log(value); } // 与调用tracking.values()方法相同 for(let num of tracking) { console.log(num); } // 与调用data.entries()方法相同 for(let entry of data) { console.log(entry); } 这段代码会输入以下内容: "red" "green" "blue" 1234 5678 9012 ["title", "Understanding ECMAScript 6"] ["format", "print"] for-of循环配合解构特性,操纵数据会更方便: for(let [key, value] of data) { console.log(key + "=" + value); } 展开运算符操纵可迭代对象 let set = new Set([1, 2, 3, 4, 5]), array = [...set]; console.log(array); // [1,2,3,4,5] 展开运算符可以操作所有的可迭代对象,并根据默认迭代器来选取要引用的值,从迭代器读取所有值。然后按返回顺序将它们依次插入到数组中。因此如果想将可迭代对象转换为数组,用展开运算符是最简单的方法。
yield items[i];
}
}
let iterator = createIterator([1, 2, 3]);
// 既然生成器返回的是迭代器,自然就可以调用迭代器的next()方法
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: undefiend, done: true}"
// 之后所有的调用都会返回相同内容
console.log(iterator.next()); // "{ value: undefiend, done: true}"
上面,我们用ES6的生成,大大简化了迭代器的创建过程。我们给生成器函数createIterator()传入一个items数组,函数内部,for循环不断从数组中生成新的元素放入迭代器中,每遇到一个yield语句循环都会停止;每次调用迭代器的next()方法,循环便继续运行并停止在下一条yield语句处。
生成器的创建方式
生成器是个函数:
function *createIterator(items) { ... }
可以用函数表达式方式书写:
let createIterator = function *(item) { ... }
也可以添加到对象中,ES5风格对象字面量:
let o = {
createIterator: function *(items) { ... }
};
let iterator = o.createIterator([1, 2, 3]);
ES6风格的对象方法简写方式:
let o = {
*createIterator(items) { ... }
};
let iterator = o.createIterator([1, 2, 3]);
可迭代对象
在ES6中,所有的集合对象(数组、Set集合及Map集合)和字符串都是可迭代对象,可迭代对象都绑定了默认的迭代器。
来了来了,姗姗来迟的ES6循环新特性for-of:
var colors = ["red", "green", "blue"];
for(let color of colors){
console.log(color);
}
for-of循环,可作用在可迭代对象上,正是利用了可迭代对象上的默认迭代器。大致过程是:for-of循环每执行一次都会调用可迭代对象的next()方法,并将迭代器返回的结果对象的value属性存储在变量中,循环将继续执行这一过程直到返回对象的done属性的值为true。
如果只需要迭代数组或集合中的值,用for-of循环代替for循环是个不错的选择。
访问默认迭代器
可迭代对象,都有一个Symbol.iterator方法,for-of循环时,通过调用colors数组的Symbol.iterator方法来获取默认迭代器的,这一过程是在javascript引擎背后完成的。
我们可以主动获取一下这个默认迭代器来感受一下:
let values = [1, 2, 3];
let iterator = values[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}"
在这段代码中,通过Symbol.iterator获取了数组values的默认迭代器,并用它遍历数组中的元素。在javaScript引擎中执行for-of循环语句也是类似的处理过程。
用Symbol.iterator属性来检测对象是否为可迭代对象:
function isIterator(object) {
return typeof object[Symbol.iterator] === "function";
}
console.log(isIterable([1, 2, 3])); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new Map())); // true
console.log(isIterable("Hello")); // true
创建可迭代对象
当我们在创建对象时,给Symbol.iterator属性添加一个生成器,则可以将其变成可迭代对象:
let collection = {
items: [],
*[Symbol.iterator]() { // 将生成器赋值给对象的Symbol.iterator属性来创建默认的迭代器
for(let item of this.items) {
yield item;
}
}
};
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);
for(let x of collection) {
console.log(x);
}
内建迭代器
ES6中的集合对象,数组、Set集合和Map集合,都内建了三种迭代器:
entries() 返回一个迭代器,其值为多个键值对。如果是数组,第一个元素是索引位置;如果是Set集合,第一个元素与第二个元素一样,都是值。
values() 返回一个迭代器,其值为集合的值。
keys() 返回一个迭代器,其值为集合中的所有键名。如果是数组,返回的是索引;如果是Set集合,返回的是值(Set的值被同时用作键和值)。
不同集合的默认迭代器
每个集合类型都有一个默认的迭代器,在for-of循环中,如果没有显式指定则使用默认的迭代器。按常规使用习惯,我们很容易猜到,数组和Set集合的默认迭代器是values(),Map集合的默认迭代器是entries()。
请看以下示例:
let colors = [ "red", "green", "blue"];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();
data.set("title", "Understanding ECMAScript 6");
data.set("format", "print");
// 与调用colors.values()方法相同
for(let value of colors) {
console.log(value);
}
// 与调用tracking.values()方法相同
for(let num of tracking) {
console.log(num);
}
// 与调用data.entries()方法相同
for(let entry of data) {
console.log(entry);
}
这段代码会输入以下内容:
"red"
"green"
"blue"
1234
5678
9012
["title", "Understanding ECMAScript 6"]
["format", "print"]
for-of循环配合解构特性,操纵数据会更方便:
for(let [key, value] of data) {
console.log(key + "=" + value);
}
展开运算符操纵可迭代对象
let set = new Set([1, 2, 3, 4, 5]),
array = [...set];
console.log(array); // [1,2,3,4,5]
展开运算符可以操作所有的可迭代对象,并根据默认迭代器来选取要引用的值,从迭代器读取所有值。然后按返回顺序将它们依次插入到数组中。因此如果想将可迭代对象转换为数组,用展开运算符是最简单的方法。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~