ES6 趣探Generators(总结)

2023-05-16

这段时间在忙着学习typescript,那么就复习到了Generators,这就来总结一下我的学习成果
在这里插入图片描述

文章目录

  • ES6新特性
  • 语法
  • “偷懒的”迭代器
  • 控制权在我手里
  • 王炸案例
    • 双向通信
      • 源码理解
    • 抛入异常

ES6新特性

Generator 函数是 ES6 的新特性,它允许一个函数返回的可遍历对象生成多个值。学习generators之前,必须要先学习迭代器,如果没有学过迭代器,可以先去小补一下🕵️‍♀️不然后面会看不懂的,不过可以先收藏再回来补嘿嘿🥂

语法

在使用中出现 * 语法和一个新的关键词 yield

function*是一个用来创建generators函数的语法,调用一个generators函数会返回一个generators对象。而这个generators对象只遵循了迭代器的接口(即next() return() throw()函数),而关于关键字yield嘛,它的功能就比较复杂了,那就让我们开始吧!

在这里插入图片描述

“偷懒的”迭代器

这里让我们简单的认识一下generators函数,并用它来创建一个“非常懒惰”的迭代器:
a.js:

function* lazyMark(){
    let index = 0;
    while(index<3){
        yield index++;
    }
}
let gen = lazyMark();
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());

在这里插入图片描述
你是否看出了yield的其中一部分特性?
是的,yield的值被当成了value的值继续往下传递了!但是具体的特性接着看吧。

控制权在我手里

这是generators最让人舒服的地方,这里实际上就是它可以让一个正在执行的函数“立马暂停”,然后将是否继续往下执行的权利全权交给调用者。

上面讲到调用一个generators函数会返回一个generators对象。但是一个generators函数并不会在调用的时候执行,它就是简简单单的创建了一个generators对象仅此而已,调不调用还得看调用者。
例子:
a.js:

function* generator(){
    console.log("start!");
    yield 0;
    console.log("执行中...");
    yield 1;
    console.log("执行中...");
}
var iterator = generator();
console.log("开始测试...");
console.log(iterator);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

在这里插入图片描述

根据输出结果:
console.log(iterator);这一句语句的执行会发现:
(秘籍拿好,后面还要王炸呢🦘)

1️⃣函数体内部的东西并没有被执行!,而是返回了Object [Generator] {}这样的信息,这也应对了上面我们的结论。

2️⃣并且,只有使用next()方法,才会去执行函数体内部的东西。

3️⃣一旦遇到yield语句,generators函数就会暂停执行,只有在下一个next被调用的时候,generators函数才会恢复执行。并且之前的函数执行过了就不会再执行,直到遇到下一个yield的时候,就又会暂停,直到下次再被调用。

4️⃣因此,实际上generators函数的执行是由generators对象控制的。

再来看几个操作深入一下,这里的重点就是什么时候执行,执行了谁,谁没有被执行
在这里插入图片描述

王炸案例

双向通信

老规矩哈,直接上菜🥗
a.js:

function* generator(){
    var bar = yield "foo";
    // 以下是函数里的输出
    console.log("----generator函数里的输出----");
    console.log(bar); //bar!
    console.log("----generator函数里的输出结束----");
}
var iterator = generator();
console.log("开始测试...");
const foo = iterator.next();
console.log(foo.value); //foo
// 继续执行
const nextThing = iterator.next("xmonster");

在这里插入图片描述
(看到输出希望看官暂停几秒自己先思考一下)

在JavaScript中,generators的一项非常强大的功能就是允许双向通信,它包含:

  • 你可以通过iterator.next(value)控制yield表达式的结果
  • 当yield表达式使用iterator.throw(error)时,还可以抛出一个异常(下面的例子再介绍)
    在这里我们就是使用了第一种,我们控制了yield表达式的结果

源码理解

我们将上面的代码放到typescript官网的学习乐园中,探一探源码,上面的代码会变成:

var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
function generator() {
    var bar;
    return __generator(this, function (_a) {
        switch (_a.label) {
            case 0: return [4 /*yield*/, "foo"];
            case 1:
                bar = _a.sent();
                // 以下是函数里的输出
                console.log("----generator函数里的输出----");
                console.log(bar); //bar!
                console.log("----generator函数里的输出结束----");
                return [2 /*return*/];
        }
    });
}
var iterator = generator();
console.log("开始测试...");
var foo = iterator.next();
console.log(foo.value); //foo
// 继续执行
var nextThing = iterator.next("xmonster");

__generator非常复杂,没关系,让我们看重点,那就是function generator(),当我们调用的时候,会发现,这是一个switch语句,case0返回的就是yield的初始值foo,而当我们第二次调用的时候,这里出现了这句话:

bar = _a.sent();

说明,它可以接收一个参数,并且将这个参数赋给了bar!
我们这里虽然说是修改了yield的值,但是我觉得还是按照上面的理解比较好

抛入异常

a.js:

function* generator(){
    try {
        yield "foo";
    } catch (error) {
        console.log("----函数里的输出----");
        console.log(error.message);
        console.log("----函数里的输出结束----");   
    }
}
var iterator = generator();
console.log("开始测试...");
// 开始执行,获取第一个yield的值
var foo = iterator.next();
console.log(foo.value);  //foo
// 继续执行,引发异常“bar”
var nextThing = iterator.throw(new Error("bar"));

在这里插入图片描述
看一看源码,这里只展示function generator()

function generator() {
    var error_1;
    return __generator(this, function (_a) {
        switch (_a.label) {
            case 0:
                _a.trys.push([0, 2, , 3]);
                return [4 /*yield*/, "foo"];
            case 1:
                _a.sent();
                return [3 /*break*/, 3];
            case 2:
                error_1 = _a.sent();
                console.log("----函数里的输出----");
                console.log(error_1.message);
                console.log("----函数里的输出结束----");
                return [3 /*break*/, 3];
            case 3: return [2 /*return*/];
        }
    });
}

现在明白了吧!

error_1 = _a.sent();

在这里插入图片描述
总结如下:

  • 外部系统可以将值推入generators函数体
  • 外部系统可以将一个异常抛入generators函数体

好啦,这就是我对Generators的初步理解,如果有深入的话,我会继续更的,都看到这里了,不点赞再走吗?哈哈哈下次再见啦
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ES6 趣探Generators(总结) 的相关文章

  • Ant Design Pro从零到一(Mock使用)

    认识Mock 学到这里就算是开始踏入AntD的门 然后我们还得学习一下常用的一些操作 例如Mock 针对与Mock他大致就是用来模拟数据的 为什么会有它的出现呢 因为现在前后端开发基本是分离的 但是数据结构一般都会先定好 在日常开发中 为了
  • git提交代码报 vue-cli-service lint found some errors. Please fix them and try committing again

    原因 问过度娘在提交代码的时候 它会在提交代码前运行做代码风格检查 如果代码不符合相应规则 则报错 解决 直接把pre commit文件删除 进入项目 git文件夹 hooks 删除 如何你的项目文件夹下没有找到 git文件夹 检查一下看看
  • => js 中箭头函数使用总结

    箭头函数感性认识 箭头函数 是在es6 中添加的一种规范 x gt x x 相当于 function x return x x 箭头函数相当于 匿名函数 简化了函数的定义 语言的发展都是倾向于简洁 对人类友好的 减轻工作量的 就相当于我最钟
  • js获取数组中最大最小值及对应索引值(下标)

    1 使用原生Js实现该功能 主要是通过循环实现 getMaxMin data key gt if data return false let maxIndex 0 let minIndex 0 let maxNum data 0 key 0
  • JS数组与对象数据格式互相转换

    JS数组与对象数据格式互相转换 一 二维数组转数组对象 开发过程中后端传过来的数据和自己需要的数据格式不统一 需要数据格式的转化 let twoArr 20 30 40 30 40 50 40 50 60 let keys name1 na
  • js执行时序 宏任务和微任务

    宏任务一般是 包括整体代码script setTimeout setInterval I O UI render 微任务主要是 Promise Object observe MutationObserver process nextTick
  • $nextTick的作用和使用场景

    nextTick的作用和使用场景 vue中的nextTick主要用于处理数据动态变化后 DOM还未及时更新的问题 用nextTick就可以获取数据更新后最新DOM的变化 适用场景 第一种 有时需要根据数据动态的为页面某些dom元素添加事件
  • ES6箭头函数(三)-应用场景

    直接作为事件handler document addEventListener click ev gt console log ev 作为数组排序回调 var arr 1 9 2 4 3 8 sort a b gt if a b gt 0
  • 【Javascript】数组拼接的两种方法

    数组拼接的两种方法 1 改变原数组 1 push 扩展运算法 1 不改变原数组 1 concat 2 扩展运算符 1 改变原数组 1 push 扩展运算法 利用push搭配扩展运算符的方法 arr2经过扩展运算符 由 3 4 5 变成3 4
  • Vue+ElementUI电商项目(六)

    订单列表 创建订单列表路由组件并添加路由规则 在view中新建orderManagement文件夹 新建Order vue组件 组件中添加代码如下
  • ES6知识点总结一:const、let、箭头函数

    1 ES6常量及变量的声明const let ES6 新增了let命令来声明变量 const用来声明常量 ES6新增的let和const拥有 块级作用域 ES5只有 全局作用域 和 函数作用域 const与var区别 var声明的变量可以重
  • ES6入门:let、const、 var区别及注意事项

    ES6入门 let const var区别及注意事项 一 let const 1 用来声明变量或声明常量 2 let 代替 var 声明变量 const 声明常量 为了那些一旦初始化就不希望重新赋值的情况设计的 3 var let声明的就是
  • Element ui中menu组件(el-menu/el-menu-item/el-submenu/template) 层级结构和用法

    此篇文章写下的时间是2020年 所以如今Element UI都更新了不知道多少版了 肯定会有些许变化 请勿完全照搬照抄 虽然可能这部分代码没什么大的变动 但还是要以官方文档为准 此文仅仅是借鉴 理解具体思路 然后再按照官方的例子来应用到自己
  • ES6 Promise详解

    优质资源分享 学习路线指引 点击解锁 知识定位 人群定位 Python实战微信订餐小程序 进阶级 本课程是python flask 微信小程序的完美结合 从项目搭建到腾讯云部署上线 打造一个全栈订餐系统 Python量化交易实战 入门级 手
  • cesium很全的入门教程-翻译官网和加入自己理解

    Cesium WorkShop cesium快速入门教程 快速入门教程基本涵盖了大多数的CesiumJS API概念 主要用于Cesium基本入门 对Cesium有全面基本的了解和使用 一 概述 本教程会一步一步教会你做一个项目 主要介绍如
  • 浏览器无法加载本地文件

    问题描述 在Visual Studio Code 编写HTML文件时需要将 csv文件内容在浏览器控制台窗口输出 浏览器控制一直报错 如下图所示 原因 跨域资源共享问题 本地文件是放在file 这样的系统下 而非网络资源比如http 下 造
  • JavaScript 实现html导出为PDF文件

    相信各位前端工程狮们在一些报表项目 管理系统项目中都会遇到在这样的需求 申请报 表格 简历等等图文信息有导出为PDF文件 下面是记录我在项目中完成该需求的代码dome 发布出来也是希望对大家有些帮助 1 整体思路 将HTML元素打印或导出为
  • 137-----JS基础-----类的操作

    一 代码 不算难 如果后续操作到类的话 可以直接使用下面封装好的接口到自己的tool中
  • VUE实践优化:轮询机制与代码结构升级

    前言 我们之前探讨过 对于包含处理状态的表格数据 我们可以通过轮询的方式进行处理 轮询更新进度条 JavaScript中的定时器和异步编程技巧 然而 当我们离开页面时 定时器仍会继续触发请求 这会造成资源的浪费 因为返回的数据并没有被渲染出
  • VUE实践优化:轮询机制与代码结构升级

    前言 我们之前探讨过 对于包含处理状态的表格数据 我们可以通过轮询的方式进行处理 轮询更新进度条 JavaScript中的定时器和异步编程技巧 然而 当我们离开页面时 定时器仍会继续触发请求 这会造成资源的浪费 因为返回的数据并没有被渲染出

随机推荐