目次
ジェネレーターとはfunction
yield 式はジェネレーター関数でのみ使用でき、他の場所で使用するとエラーが報告されます
類似点: どちらもステートメントの直後にある式の値を返すことができます
ジェネレーター関数内で別のジェネレーター関数を呼び出しても、デフォルトでは効果がありません
yield 式自体には戻り値がないか、常に unknown が返されます。次のメソッドはパラメータを受け取ることができ、そのパラメータは前の yield 式の戻り値として扱われます
ES6 では、デフォルトの Iterator インターフェイスがデータ構造の Symbol.iterator プロパティにデプロイされること、つまりデータ構造に Symbol.iterator プロパティがある限り、デプロイされることが規定されています。 、それは「トラバース可能」(反復可能) であると考えることができます。
for...of 循环 
Generator.prototype.return()
Generator 函数应用举例
ホームページ ウェブフロントエンド jsチュートリアル JavaScriptでのジェネレータ関数yield式例の詳細説明

JavaScriptでのジェネレータ関数yield式例の詳細説明

Nov 01, 2022 pm 05:04 PM
javascript

この記事では、JavaScript に関する関連知識を紹介します。主に、JS ジェネレーター関数の yield 式の例の詳細な説明を紹介します。ジェネレーター関数は、ES6 によって提供される非同期プログラミング ソリューションです。ぜひご覧ください。皆さんのお役に立てば幸いです。

[関連する推奨事項: JavaScript ビデオ チュートリアル Web フロントエンド ]

ジェネレーターとはfunction

JavaScript では、関数が実行を開始すると、最後まで実行されるか、return に遭遇したときに終了します。実行中に他のコードが中断することはできず、関数本体に値を渡すことはできません。外部

Generator 関数 (ジェネレーター) の出現により、関数の完全な操作を中断することが可能になり、その文法動作は従来の関数とは完全に異なります

Generator 関数は非同期関数ですES6 によって提供されるプログラミング ソリューションであり、これも形式的には通常の関数ですが、いくつかの注目すべき機能があります:

  • 関数キーワードと関数名の間にはアスタリスク "*" があります (関数キーワードと関数名の間にはアスタリスク "*" があります ( function キーワードの隣に配置します)
  • 関数本体で yield 式を使用して、さまざまな内部状態を定義します (複数の yield が存在する可能性があります)
  • Generator 関数を直接呼び出しても実行されません。実行結果を返しますが、イテレータ オブジェクト (イテレータ オブジェクト) を返します。
  • ジェネレータ関数内の各状態を横断して、イテレータ オブジェクトの次のメソッドを順番に呼び出します。
  // 传统函数
  function foo() {
    return 'hello world'
  }
  foo()   // 'hello world',一旦调用立即执行
  // Generator函数
  function* generator() {
    yield 'status one'         // yield 表达式是暂停执行的标记  
    return 'hello world'
  }
  let iterator = generator()   // 调用 Generator函数,函数并没有执行,返回的是一个Iterator对象
  iterator.next()              // {value: "status one", done: false},value 表示返回值,done 表示遍历还没有结束
  iterator.next()              // {value: "hello world", done: true},value 表示返回值,done 表示遍历结束
ログイン後にコピー

従来の関数は上記のコードで確認できます Generator関数の動作とは全く異なります 従来関数は呼び出し直後に実行され戻り値が出力されますが、Generator関数は実行されずにIteratorオブジェクトを返しますIterator オブジェクトの next メソッドを呼び出すことでトラバースされます。関数本体での実行がわかります。「移動する前にキックされている」ように感じられます。

  function* gen() {
    yield 'hello'
    yield 'world'
    return 'ending'
  }
  let it = gen()
  it.next()   // {value: "hello", done: false}
  it.next()   // {value: "world", done: false}
  it.next()   // {value: "ending", done: true}
  it.next()   // {value: undefined, done: true}
ログイン後にコピー

上記のコードは、2 つのジェネレーター関数を定義しています。 yield 式と return ステートメント (つまり、3 つの状態が生成されます)

Iterator オブジェクトの次のメソッドが呼び出されるたびに、内部ポインターは関数の先頭または関数が配置された場所から実行を開始します。一時停止する次の yield 式または return ステートメントに遭遇するまで、前回停止します。つまり、ジェネレーター関数はセクション単位で実行され、yield 式は実行を一時停止するためのマークであり、次のメソッドは実行を再開できます。トラバーサルが完了すると、他の状態が存在しないため、{value: unfined、done: true} が返されます。次のメソッドの呼び出しを続けると、この値が返されます。

yield 式

yield 式はジェネレーター関数でのみ使用でき、他の場所で使用するとエラーが報告されます

function (){
    yield 1;
  })()
  // SyntaxError: Unexpected number
  // 在一个普通函数中使用yield表达式,结果产生一个句法错误
ログイン後にコピー

yield 式を別の式で使用する場合は、括弧内に配置する必要があります

function* demo() {
    console.log('Hello' + yield); // SyntaxError
    console.log('Hello' + yield 123); // SyntaxError
    console.log('Hello' + (yield)); // OK
    console.log('Hello' + (yield 123)); // OK
  }
ログイン後にコピー

yield 式はパラメータとして使用されるか、代入式の右側に配置され、括弧は必要ありません

function* demo() {
    foo(yield 'a', yield 'b'); // OK
    let input = yield; // OK
  }
ログイン後にコピー

yield 式と return ステートメントの違い

類似点: どちらもステートメントの直後にある式の値を返すことができます

違い:

Every yield に遭遇すると、関数は実行を一時停止し、次回その位置から逆方向に実行を続けます。また、return ステートメントには位置を記憶する機能がありません。
  • 関数は return ステートメントを 1 回しか実行できません。ジェネレーター関数内には、yield
  • yield* 式をいくつでも指定できます。

ジェネレーター関数内で別のジェネレーター関数を呼び出しても、デフォルトでは効果がありません

function* foo() {
    yield 'aaa'
    yield 'bbb'
  }
  function* bar() {
    foo()
    yield 'ccc'
    yield 'ddd'
  }
  let iterator = bar()
  for(let value of iterator) {
    console.log(value)
  }
  // ccc
  // ddd
ログイン後にコピー

上記の例では、関数 bar によって生成されたトラバーサー オブジェクトをトラバースするために for...of を使用する場合、bar 自体の 2 つのステータス値のみが返されます。このとき、bar で foo を正しく呼び出したい場合は、yield* 式を使用する必要があります。

yield* 式は、Generator 関数内で別の Generator 関数を

execute

するために使用されます

 function* foo() {
    yield 'aaa'
    yield 'bbb'
  }
  function* bar() {
    yield* foo()      // 在bar函数中 **执行** foo函数
    yield 'ccc'
    yield 'ddd'
  }
  let iterator = bar()
  for(let value of iterator) {
    console.log(value)
  }
  // aaa
  // bbb
  // ccc
  // ddd
ログイン後にコピー
next() メソッドのパラメータ

yield 式自体には戻り値がないか、常に unknown が返されます。次のメソッドはパラメータを受け取ることができ、そのパラメータは前の yield 式の戻り値として扱われます

  function* gen(x) {
    let y = 2 * (yield (x + 1))   // 注意:yield 表达式如果用在另一个表达式中,必须放在圆括号里面
    let z = yield (y / 3)
    return x + y + z
  }
  let it = gen(5)
  /*** 正确的结果在这里 ***/
  console.log(it.next())  // 首次调用next,函数只会执行到 “yield(5+1)” 暂停,并返回 {value: 6, done: false}
  console.log(it.next())  // 第二次调用next,没有传递参数,所以 y的值是undefined,那么 y/3 当然是一个NaN,所以应该返回 {value: NaN, done: false}
  console.log(it.next())  // 同样的道理,z也是undefined,6 + undefined + undefined = NaN,返回 {value: NaN, done: true}
ログイン後にコピー

次のメソッドにパラメータが指定された場合、戻り結果はまったく異なります

{
  function* gen(x) {
    let y = 2 * (yield (x + 1))   // 注意:yield 表达式如果用在另一个表达式中,必须放在圆括号里面
    let z = yield (y / 3)
    return x + y + z
  }
  let it = gen(5)
  console.log(it.next())  // 正常的运算应该是先执行圆括号内的计算,再去乘以2,由于圆括号内被 yield 返回 5 + 1 的结果并暂停,所以返回{value: 6, done: false}
  console.log(it.next(9))  // 上次是在圆括号内部暂停的,所以第二次调用 next方法应该从圆括号里面开始,就变成了 let y = 2 * (9),y被赋值为18,所以第二次返回的应该是 18/3的结果 {value: 6, done: false}
  console.log(it.next(2))  // 参数2被赋值给了 z,最终 x + y + z = 5 + 18 + 2 = 25,返回 {value: 25, done: true}
}
ログイン後にコピー

Iterator インターフェイスとの関係

ES6 では、デフォルトの Iterator インターフェイスがデータ構造の Symbol.iterator プロパティにデプロイされること、つまりデータ構造に Symbol.iterator プロパティがある限り、デプロイされることが規定されています。 、それは「トラバース可能」(反復可能) であると考えることができます。

Symbol.iterator プロパティ自体は関数であり、現在のデータ構造のデフォルトのトラバーサー生成関数です。この関数を実行すると、トラバーサーが返されます。

Generator 関数を実行すると実際には反復子が返されるため、オブジェクトの Symbol.iterator プロパティに Generator を割り当てて、オブジェクトに Iterator インターフェイスを持たせることができます。

{
  let obj = {}
  function* gen() {
    yield 4
    yield 5
    yield 6
  }
  obj[Symbol.iterator] = gen
  for(let value of obj) {
    console.log(value)
  }
  // 4
  // 5
  // 6
  console.log([...obj])    // [4, 5, 6]
}
ログイン後にコピー

传统对象没有原生部署 Iterator接口,不能使用 for...of 和 扩展运算符,现在通过给对象添加Symbol.iterator 属性和对应的遍历器生成函数,就可以使用了

for...of 循环

由于 Generator 函数运行时生成的是一个 Iterator 对象,因此,可以直接使用 for...of 循环遍历,且此时无需再调用 next() 方法

这里需要注意,一旦 next() 方法的返回对象的 done 属性为 true,for...of 循环就会终止,且不包含该返回对象

{
  function* gen() {
    yield 1
    yield 2
    yield 3
    yield 4
    return 5
  }
  for(let item of gen()) {
    console.log(item)
  }
  // 1 2 3 4
}
ログイン後にコピー

Generator.prototype.return()

Generator 函数返回的遍历器对象,还有一个 return 方法,可以返回给定的值(若没有提供参数,则返回值的value属性为 undefined),并且 终结 遍历 Generator 函数


{
  function* gen() {
    yield 1
    yield 2
    yield 3
  }
  let it = gen()
  it.next()             // {value: 1, done: false}
  it.return('ending')   // {value: "ending", done: true}
  it.next()             // {value: undefined, done: true}
}
ログイン後にコピー


Generator 函数应用举例

应用一:假定某公司的年会上有一个抽奖活动,总共6个人可以抽6次,每抽一次,抽奖机会就会递减

按照常规做法就需要声明一个全局的变量来保存剩余的可抽奖次数,而全局变量会造成全局污染,指不定什么时候就被重新赋值了,所以往往并不被大家推荐


{
  let count = 6  // 声明一个全局变量
  // 具体抽奖逻辑的方法
  function draw() {
    // 执行一段抽奖逻辑
    // ...
    // 执行完毕
    console.log(`剩余${count}次`)
  }
  // 执行抽奖的方法
  function startDrawing(){
    if(count > 0) {
      count--
      draw(count)
    }
  }
  let btn = document.createElement('button')
  btn.id = 'start'
  btn.textContent = '开始抽奖'
  document.body.appendChild(btn)
  document.getElementById('start').addEventListener('click', function(){
    startDrawing()
  }, false)
}[object Object]
ログイン後にコピー

事实上,抽奖通常是每个人自己来抽,每抽一次就调用一次抽奖方法,而不是点一次就一次性就全部运行完,是可暂停的,这个不就是 Generator 函数的意义所在吗?

  // 具体抽奖逻辑的方法
  function draw(count) {
    // 执行一段抽奖逻辑
    // ...
    console.log(`剩余${count}次`)
  }
  // 执行抽奖的方法
  function* remain(count) {
    while(count > 0) {
      count--
      yield draw(count)
    }
  }
  let startDrawing = remain(6)
  let btn = document.createElement('button')
  btn.id = 'start'
  btn.textContent = '开始抽奖'
  document.body.appendChild(btn)
  document.getElementById('start').addEventListener('click', function(){
    startDrawing.next()
  }, false)
ログイン後にコピー

应用二:由于HTTP是一种无状态协议,执行一次请求后服务器无法记住是从哪个客户端发起的请求,因此当需要实时把服务器数据更新到客户端时通常采用的方法是长轮询和Websocket。这里也可以用 Generator 函数来实现长轮询

{
  // 请求的方法
  function* ajax() {
    yield new Promise((resolve, reject) => {
      // 此处用一个定时器来模拟请求数据的耗时,并约定当返回的json中code为0表示有新数据更新
      setTimeout(() => {
        resolve({code: 0})
      }, 200)
    })
  }
  // 长轮询的方法
  function update() {
    let promise = ajax().next().value    // 返回的对象的value属性是一个 Promise 实例对象
    promise.then(res => {
      if(res.code != 0) {
        setTimeout(() => {
          console.log('2秒后继续查询.....')
          update()
        }, 2000)
      } else{
        console.log(res)
      }
    })
  }
  update()
}
ログイン後にコピー

【相关推荐:JavaScript视频教程web前端

以上がJavaScriptでのジェネレータ関数yield式例の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScript で HTTP ステータス コードを簡単に取得する方法 JavaScript で HTTP ステータス コードを簡単に取得する方法 Jan 05, 2024 pm 01:37 PM

JavaScript で HTTP ステータス コードを取得する方法の紹介: フロントエンド開発では、バックエンド インターフェイスとの対話を処理する必要があることが多く、HTTP ステータス コードはその非常に重要な部分です。 HTTP ステータス コードを理解して取得すると、インターフェイスから返されたデータをより適切に処理できるようになります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法と、具体的なコード例を紹介します。 1. HTTP ステータス コードとは何ですか? HTTP ステータス コードとは、ブラウザがサーバーへのリクエストを開始したときに、サービスが

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

See all articles