追求JS小姊姊系列 Day14 -- 方函式的能力展现:认识生成器,工具人更神气(上)

前情提要

方函式准备展示第二个型态

:有些情境下,时间就是不能掌握,这要求也太夸张了。
方函式:很不合理吧,连一个女生都没办法掌握了,何况是时间呢?

方函式:但身为头等工具人就是要能应对各种不合理
生成器型态就可用於应付所谓时间不平等的情境

(说完发现方函式拿出了像是遥控器的物件)


生成器模式登场

:第二型态能力是用... 遥控器控制你以为在演王牌天神?
方函式你懂生成器,生成器就会帮你,为了帮助你追到JS,我会告诉你,包含:

  1. 生成器的创建
  2. 生成器与一般函式的差异
  3. 生成器内的内容
  4. 生成器的使用方式
  5. 简易案例

:为何要帮我!?(工具人当到疯了吗?)


生成器的介绍方式:

  1. 创造方式: 新增*关键字放於function後方
function* generator(i){
    yield 1;
    yield* 2;
    return 3;
}
  1. yield,yield*是什麽
    yield
    生成器内的值是透过yield语句(中文翻译为产出),但实际上我们不只能藉由它传出(output)值,也能做到传入(input)值、甚至是抛出(throw)值
    yield*:
    可以将原本生成器的yield*後的内容交由另一个生成器去进行执行
//产生一个生成器
function* generator(i){
    console.log("我会被执行吗?");
    yield "test";
}

生成器跟一般函式的差异

  1. 呼叫
    下图分别是生成器generator()跟一般函式normalFn()
//生成器
function* generator(i){
    console.log("我会被执行吗?");
    yield 1;
    
}

//一般的函式 
function normalFn(i){
    console.log("我会被执行");
}

console.log(generator(1));
console.log(normalFn(1));

一般函式normalFn():你呼叫後会直接执行函式内的内容。
生成器:呼叫generator()只得到了undefined

(上图为:generator()normalFn()的执行结果)

那生成器的定位是什麽?来看看MDN怎麽说:

Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead

大意是:呼叫生成器本身并不会回传内容,而是会产生一个迭代器

方函式:就是透过我手上的这个东西。

生成器专属的遥控器 -- iterator object

制作方法:把生成器呼叫存入变数,这个动作背後的意义是:
产生一个用於控制生成器的操作器(iterator)

遥控器的使用方法next()
会回传一个物件 {value:,done:},以下进行解释:

  1. value: yield後的值
  2. done:会有两种情形(true/false)

done显示为false:代表生成器的内容还没执行完


//生成器
function* generator(i){
    yield 1;
}

//产生遥控器
let control =generator();

//开始操作
console.log(control.next(),"我是结果");

done显示为true:代表生成器的内容已经执行完

function* generator(i){
    yield 1;
}

//产生遥控器
let control =generator();

//开始操作
console.log(control.next(),"我是第一次执行");
console.log(control.next(),"希望这次看得到`true`");


基本略知、也会操作,那来看看传值吧

方函式:我们已知可藉由yield传出(output)值,那还记得之前提到:
它也能做到传入(input)值、甚至是抛出(throw)值 这件事吗?现在来试试看吧?

传入(input)值

  1. 建立迭代器时,同时将值传入参数:
function* generator(i){
    yield i;
}

//在这传入
let control =generator(123);

//开始操作
console.log(control.next(),"得到传入的值");
  1. next()方法传入:
    先知道:
    1. 这会让生成器的状态: 待命中/暂停生产 > 执行中
    2. 透过next方法传入的值,会被提供给暂停中的yield内容,什麽意思呢?

首次用呼叫生成器

function* generator(i){
    yield i;
    yield i;
}
const controls = generator();

//尝试在第一次next()传入值
let call1 = controls.next(5);
console.log(call1);

我们无法在第一次使用next方法就提供,若要第一次传入值,只能透过建立迭代器时传入,至於背後原因之後再说。

  1. throw()方法传入:
    我们可运用它将异常内容抛给生成器
注意:要先将生成器状态启动(解除待命中),才能使用抛出
function* generator(i){
    try{
        yield i;
    }catch(error){
        console.log(error,"yes,catch error!");
    }
}

//在这传入
let control =generator();
let x = control.next();
control.throw("can you throw?");

//开始操作

方函式:看到那麽多的名词,什麽暂停、启动状态,你是不是也该好奇生成器背後的原理呢?
:不,我只想休息...

-- to be continued --


那今天就到这边搂!今天分享喜欢的歌是:
That's Life (Remastered 2008)
https://www.youtube.com/watch?v=TnlPtaPxXfc

每天的休息,是为了後面的追求,明天见。


reference:

JavaScript — from callbacks to async/await
忍者2
22. Generators
function*


<<:  Shadow Element:控制 UI 元件的元件

>>:  DAY14:Toast显示讯息之简介

Extra01 - glob - 配置目标档案与目录

此为番外,此篇选入番外的原因是 glob 并不是个工具,但是是个会常被各种工具采用的一种配置方式。...

[Day27] CH13:画出你的藏宝图——图形使用者介面

终於来到我们最後一个主题了,今天我们要介绍的是图形使用者介面(graphical user inte...

RISC-V: 在指令之前的 Register File

昨天已经把程序码稍微整理了一下, 分出两大部分:处理器和记忆体, 以及加上 Formatter 让 ...

[Day12] TS:什麽!型别还有递回(recursion)的概念?用组合技实作 SnakeToCamelCase

这是我们今天要聊的内容,老样的,如果你已经可以轻松看懂,欢迎直接左转去看我同事 Andy 精彩的文...

【零基础成为 AI 解梦大师秘笈】Day27 - 周易解梦之人工智慧(8)

人工智慧8 前言 系列文章简介 大家好,我们是 AI . FREE Team - 人工智慧自由团队,...