From 7094bb2b9687e32cc614cbc0fd289408953f23ea Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Thu, 13 Jul 2023 12:30:18 +0330 Subject: [PATCH 01/11] translation of `generators` is added(partial) --- .../1-generators/article.md | 379 +++++++++++++----- 1 file changed, 282 insertions(+), 97 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index 55f6bf903..68fbbede8 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -1,318 +1,447 @@ # Generators -Regular functions return only one, single value (or nothing). +توابع معمول فقط یک‌بار می‌توانند یک مقدار(مثلا یک object یا undefined) را برگردانند. -Generators can return ("yield") multiple values, one after another, on-demand. They work great with [iterables](info:iterable), allowing to create data streams with ease. +اما generatorها می‌توانند چندین بار، بر اساس تقاضا، مقادیر متفاوت را برگردانند(اصطلاحا yield کنند.). generatorها با [iterableها](info:iterable) به خوبی کار می‌کنند و به کمک آن‌ها می‌توان جریان‌های داده ساخت. -## Generator functions +## توابع Generator -To create a generator, we need a special syntax construct: `function*`, so-called "generator function". +برای ساختن یک generator به یک سینتکس خاص نیاز است: *function، که به آن "تابع generator" می‌گویند. -It looks like this: +ظاهر یک تابع generator به صورت زیر است: ```js + function* generateSequence() { + yield 1; + yield 2; + return 3; + } + ``` -Generator functions behave differently from regular ones. When such function is called, it doesn't run its code. Instead it returns a special object, called "generator object", to manage the execution. -Here, take a look: +توابع generator با توابع معمول، رفتار متفاوتی دارند. زمانی که این توابع صدا می‌شوند، بدنه آن‌ها اجرا نمی‌شود؛ در عوض، یک آبجکت خاص به نام "generator object" برمی‌گردانند که به وسیله آن اجرای تابع را می‌توان کنترل کرد. + +برای مثال: ```js run + function* generateSequence() { + yield 1; + yield 2; + return 3; + } -// "generator function" creates "generator object" +//برمی‌گرداند generator یک آبجکت generator تابع + let generator = generateSequence(); -*!* + +\*!* + alert(generator); // [object Generator] -*/!* + +\*/!* + ``` -The function code execution hasn't started yet: + +اجرای بدنه تایع هنوز شروع نشده است: ![](generateSequence-1.svg) -The main method of a generator is `next()`. When called, it runs the execution until the nearest `yield ` statement (`value` can be omitted, then it's `undefined`). Then the function execution pauses, and the yielded `value` is returned to the outer code. +متد اصلی یک آبجکت generator متد `()next` است. هنگامی که صدا می‌شود، بدنه تابع تا اولین `yield value` اجرا می‌شود(`value` می‌تواند حذف شود که در این صورت `undefined` است.)؛ سپس اجرای تابع متوقف می‌شود و مقدار yield شده برگرداننده می‌شود. -The result of `next()` is always an object with two properties: -- `value`: the yielded value. -- `done`: `true` if the function code has finished, otherwise `false`. +مقدار برگردانده شده توسط متود `next` همواره یک آبجکت با 2 پراپرتی است: -For instance, here we create the generator and get its first yielded value: +- `value`: مقدار برگرداننده شده توسط `yield`. + +- `done`: یک Boolean است که در صورت اتمام بدنه تابع مقدار true و در غیر این صورت مقدار false دارد. + +برای مثال، در کد زیر، یک آبجکت generator ایجاد شده و اولین مقدار `yield` شده توسط آن گرفته شده است: ```js run + function* generateSequence() { + yield 1; + yield 2; + return 3; + } let generator = generateSequence(); -*!* +\*!* + let one = generator.next(); -*/!* + +\*/!* alert(JSON.stringify(one)); // {value: 1, done: false} + ``` -As of now, we got the first value only, and the function execution is on the second line: + +اکنون فقط مقدار اول را گرفته‌ایم و اجرای تابع در خط دوم متوقف شده است: ![](generateSequence-2.svg) -Let's call `generator.next()` again. It resumes the code execution and returns the next `yield`: +اکنون اگر دوباره `()generator.next` را صدا بزنیم اجرای تابع شروع می‌شود و تا `yield` بعدی و برگردانده شدن مقدار ادامه می‌یابد: ```js + let two = generator.next(); alert(JSON.stringify(two)); // {value: 2, done: false} + ``` + ![](generateSequence-3.svg) -And, if we call it a third time, the execution reaches the `return` statement that finishes the function: +و اگر برای بار سوم آن را صدا بزنیم، اجرای تابع به `return` می‌رسد و تمام می‌شود: ```js + let three = generator.next(); alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} + ``` + ![](generateSequence-4.svg) -Now the generator is done. We should see it from `done:true` and process `value:3` as the final result. +اکنون از روی `done:true` متوجه می‌شویم کار generator تمام شده و `value:3` آخرین مقدار برگردانده شده توسط generator است. -New calls to `generator.next()` don't make sense any more. If we do them, they return the same object: `{done: true}`. +دیگر صدا کردن `()generator.next` منطقی نیست. اگر این کار را انجام دهیم، آبجکت یکسانی با `done:true` برگردانده می‌شود. -```smart header="`function* f(…)` or `function *f(…)`?" -Both syntaxes are correct. +```smart header="`function* f(…)`یا`function *f(…)`؟" -But usually the first syntax is preferred, as the star `*` denotes that it's a generator function, it describes the kind, not the name, so it should stick with the `function` keyword. -``` +هر دو سینتکس صحیح هستند. -## Generators are iterable +ولی معمولا اولی ترجیح داده می‌شود؛ چون `*` نوع تابع و نه نام تابع را مشخص می‌کند. -As you probably already guessed looking at the `next()` method, generators are [iterable](info:iterable). +```` -We can loop over their values using `for..of`: +## generatorها iterable هستند. + +همانطور که احتمالا با توجه به `()next` متوجه شده‌اید، generatorها [iterable](info:iterable) هستند. + +با استفاد از `for..of` می‌توان از `value` آن‌ها استفاده کرد: ```js run + function* generateSequence() { + yield 1; + yield 2; + return 3; + } let generator = generateSequence(); for(let value of generator) { - alert(value); // 1, then 2 + + alert(value); // ابتدا 1 و سپس 2 + } -``` -Looks a lot nicer than calling `.next().value`, right? +```` -...But please note: the example above shows `1`, then `2`, and that's all. It doesn't show `3`! +این شیوه از صدا کردن `next` تمیزتر است؛ این‌گونه فکر نمی‌کنید؟ -It's because `for..of` iteration ignores the last `value`, when `done: true`. So, if we want all results to be shown by `for..of`, we must return them with `yield`: +...اما دقت کنید: مثال بالا ابتدا `1` و سپس `2` را نشان داد؛ خبری از `3` نیست! +علت این اتفاق این است که `for..of` آخرین مقدار را هنگامی که `done:true` است در نظر نمی‌گیرد. هنگام برگرداندن آخرین مقدار با `return`، بر خلاف `done:true`، `yield` است. در نتیجه برای نشان دادن تمام مقادیر باید آن‌ها را با `yield` برگردانیم: ```js run + function* generateSequence() { + yield 1; + yield 2; -*!* + +\*!* + yield 3; -*/!* + +\*/!* + } let generator = generateSequence(); for(let value of generator) { - alert(value); // 1, then 2, then 3 + + alert(value); // ابتدا 1 سپس 2 و بعد از آن 3 + } + ``` -As generators are iterable, we can call all related functionality, e.g. the spread syntax `...`: + +از آنجایی که generatorها iterable هستند، از تمام functionality آن‌ها نیز برای generatorها می‌توان استفاده کرد؛ مثل spread syntax `...`: ```js run + function* generateSequence() { + yield 1; + yield 2; + yield 3; + } let sequence = [0, ...generateSequence()]; alert(sequence); // 0, 1, 2, 3 + ``` -In the code above, `...generateSequence()` turns the iterable generator object into an array of items (read more about the spread syntax in the chapter [](info:rest-parameters-spread#spread-syntax)) -## Using generators for iterables +در کد بالا، `()generateSequence...`، باعث می‌شود آبجکت generator که iterable هم هست به آرایه‌ای از اعداد تبدیل شود.(درباره spread syntax در چپتر [](info:rest-parameters-spread#spread-syntax) بیشتر بخوانید.) -Some time ago, in the chapter [](info:iterable) we created an iterable `range` object that returns values `from..to`. +## استفاده از generatorها برای iterableها -Here, let's remember the code: +در چپتر [](info:iterable) یک آبجکت `range` ساختیم که مقادیر `from..to` را باز می‌گرداند. + +کد آن به شرح زیر بود: ```js run + let range = { + from: 1, + to: 5, - // for..of range calls this method once in the very beginning + // در ابتدا این متود را فقط یک بار صدا می‌کند for..of range + [Symbol.iterator]() { - // ...it returns the iterator object: - // onward, for..of works only with that object, asking it for next values + + // این، آبجکت ایتریتور را باز می‌گرداند: + + // فقط با آن آبجکت کار می‌کند و از آن مقادیر بعدی را می‌خواند for..of سپس return { + current: this.from, + last: this.to, - // next() is called on each iteration by the for..of loop + // صدا می‌شود for..of توسط iteration در هر next() + next() { - // it should return the value as an object {done:.., value :...} + + // باید مقدار را به عنوان یک آبجکت برگرداند: + // {value: ..., done: ...} + if (this.current <= this.last) { + return { done: false, value: this.current++ }; + } else { + return { done: true }; + } - } + + }, + }; - } + + }, + }; -// iteration over range returns numbers from range.from to range.to +// برمی‌گرداند range.to تا range.from اعداد را از range روی iteration alert([...range]); // 1,2,3,4,5 + ``` -We can use a generator function for iteration by providing it as `Symbol.iterator`. -Here's the same `range`, but much more compact: +می‌توان از یک تابع generator برای iteration به جای Symbol.iterator استفاده کرد. + +این همان `range` اما بسیار جمع و جور تر است: ```js run + let range = { + from: 1, + to: 5, - *[Symbol.iterator]() { // a shorthand for [Symbol.iterator]: function*() - for(let value = this.from; value <= this.to; value++) { + \*[Symbol.iterator]() { + + //[Symbol.iterator] نسخه جمع و جور : function*() + + for (let value = this.from; value <= this.to; value++) { + yield value; + } - } + + }, + }; -alert( [...range] ); // 1,2,3,4,5 +alert([...range]); // 1,2,3,4,5 + ``` -That works, because `range[Symbol.iterator]()` now returns a generator, and generator methods are exactly what `for..of` expects: -- it has a `.next()` method -- that returns values in the form `{value: ..., done: true/false}` -That's not a coincidence, of course. Generators were added to JavaScript language with iterators in mind, to implement them easily. +دلیل کارکرد روش بالا این است که `()range[Symbol.iterator]` دقیقا همان چیزی را برمی‌گرداند که `for..of` انتظار دارد: + +- متود `next` موجود است. + +- مقدار بازگشتی به فرم `{value:..., done:true/false}` است. + +این کارکرد یک اتفاق نیست، generatorها با توجه به iterator ها، برای پیاده‌سازی ساده‌تر آن‌ها به زبان اضافه شده‌اند. -The variant with a generator is much more concise than the original iterable code of `range`, and keeps the same functionality. +روشی که از generator استفاده می‌کند بسیار مختصرتر از روش اول `range` است و همان کارکرد را دارد. -```smart header="Generators may generate values forever" -In the examples above we generated finite sequences, but we can also make a generator that yields values forever. For instance, an unending sequence of pseudo-random numbers. +```smart header="generatorها ممکن است تا ابد مقدار تولید کنند" + +در مثال بالا، یک دنباله کران دار تولید کردیم، ولی می‌توان به همان روش یک دنباله بی‌کران از مقادیر را ساخت. مثل یک دنباله بی‌پایان از اعداد شبه تصادفی. -That surely would require a `break` (or `return`) in `for..of` over such generator. Otherwise, the loop would repeat forever and hang. ``` -## Generator composition -Generator composition is a special feature of generators that allows to transparently "embed" generators in each other. +## ترکیب generatorها + +ترکیب generatorها قابلیتی است که به وسیله آن می‌توان generatorها را در هم `embed` کرد. -For instance, we have a function that generates a sequence of numbers: +برای مثال یک generator داریم که یک دنباله از اعداد را تولید می‌کند: ```js + function* generateSequence(start, end) { + for (let i = start; i <= end; i++) yield i; + } + ``` -Now we'd like to reuse it to generate a more complex sequence: -- first, digits `0..9` (with character codes 48..57), -- followed by uppercase alphabet letters `A..Z` (character codes 65..90) -- followed by lowercase alphabet letters `a..z` (character codes 97..122) -We can use this sequence e.g. to create passwords by selecting characters from it (could add syntax characters as well), but let's generate it first. +اکنون می‎‌خواهیم از آن به نحوی بازاستفاده کنیم که دنباله پیچیده‌تری بتوان ایجاد کرد: -In a regular function, to combine results from multiple other functions, we call them, store the results, and then join at the end. +- ابتدا ارقام از `0` تا `9`(با کد کاراکتر 48 تا 57) +- سپس حروف بزرگ از `A` تا `Z`(با کد کاراکتر 65 تا 90) +- سپس حروف کوچک از `a` تا `z`(با کد کاراکتر 97 تا 122) -For generators, there's a special `yield*` syntax to "embed" (compose) one generator into another. +برای مثال از این دنباله می‌توان با انتخاب کاراکتر، برای تولید رمز عبور استفاده کرد. -The composed generator: +در توابع معمولی، برای ترکیب جواب‌ها از چندین تابع دیگر، آن‌ها را صدا می‌کنیم، مقادیر را ذخیره می‌کنیم و سپس در آخر آن‌ها را به هم `join` می‌کنیم. + +برای generatorها سینتکس`*yield` برای "embed" کردن یک generator درون دیگری استفاده می‌شود. + +generator ترکیب شده: ```js run + function* generateSequence(start, end) { + for (let i = start; i <= end; i++) yield i; + } function* generatePasswordCodes() { -*!* +\*!* + // 0..9 + yield* generateSequence(48, 57); // A..Z + yield* generateSequence(65, 90); // a..z + yield* generateSequence(97, 122); -*/!* + +\*/!* } let str = ''; for(let code of generatePasswordCodes()) { + str += String.fromCharCode(code); + } alert(str); // 0..9A..Za..z + ``` -The `yield*` directive *delegates* the execution to another generator. This term means that `yield* gen` iterates over the generator `gen` and transparently forwards its yields outside. As if the values were yielded by the outer generator. -The result is the same as if we inlined the code from nested generators: +عبارت `*yield` اجرا را به یک generator دیگر می‌سپارد(اصطلاحا `delegate` می‌کند). بدان معنا که `yeild* gen` روی `gen` ایتریت می‌کند و به صورت درونی مقدار yield شده را به بیرون هدایت می‌کند؛ انگار که کلا مقدار توسط generator دوم تولید شده است. + +اگر از generatorها به صورت inline و تو در تو استفاده کنیم نیز به همان نتیجه می‌رسیم: ```js run + function* generateSequence(start, end) { + for (let i = start; i <= end; i++) yield i; + } function* generateAlphaNum() { -*!* +\*!* + // yield* generateSequence(48, 57); + for (let i = 48; i <= 57; i++) yield i; // yield* generateSequence(65, 90); + for (let i = 65; i <= 90; i++) yield i; // yield* generateSequence(97, 122); + for (let i = 97; i <= 122; i++) yield i; -*/!* + +\*/!* } let str = ''; for(let code of generateAlphaNum()) { + str += String.fromCharCode(code); + } alert(str); // 0..9A..Za..z + ``` -A generator composition is a natural way to insert a flow of one generator into another. It doesn't use extra memory to store intermediate results. + +ترکیب generatorها یک راه معقول برای استفاده از جریان یک generator درون دیگری است و از حافظه بیشتر برای ذخیره مقادیر استفاده نمی‌کند. ## "yield" is a two-way street @@ -325,26 +454,36 @@ To do so, we should call `generator.next(arg)`, with an argument. That argument Let's see an example: ```js run + function* gen() { -*!* + +\*!* + // Pass a question to the outer code and wait for an answer + let result = yield "2 + 2 = ?"; // (*) -*/!* + +\*/!* alert(result); + } let generator = gen(); let question = generator.next().value; // <-- yield returns the value -generator.next(4); // --> pass the result into the generator +generator.next(4); // --> pass the result into the generator + ``` + ![](genYield2.svg) 1. The first call `generator.next()` should be always made without an argument (the argument is ignored if passed). It starts the execution and returns the result of the first `yield "2+2=?"`. At this point the generator pauses the execution, while staying on the line `(*)`. + 2. Then, as shown at the picture above, the result of `yield` gets into the `question` variable in the calling code. + 3. On `generator.next(4)`, the generator resumes, and `4` gets in as the result: `let result = 4`. Please note, the outer code does not have to immediately call `next(4)`. It may take time. That's not a problem: the generator will wait. @@ -352,42 +491,55 @@ Please note, the outer code does not have to immediately call `next(4)`. It may For instance: ```js + // resume the generator after some time + setTimeout(() => generator.next(4), 1000); + ``` + As we can see, unlike regular functions, a generator and the calling code can exchange results by passing values in `next/yield`. To make things more obvious, here's another example, with more calls: ```js run + function* gen() { + let ask1 = yield "2 + 2 = ?"; alert(ask1); // 4 - let ask2 = yield "3 * 3 = ?" + let ask2 = yield "3 * 3 = ?"; alert(ask2); // 9 + } let generator = gen(); -alert( generator.next().value ); // "2 + 2 = ?" +alert(generator.next().value); // "2 + 2 = ?" + +alert(generator.next(4).value); // "3 * 3 = ?" -alert( generator.next(4).value ); // "3 * 3 = ?" +alert(generator.next(9).done); // true -alert( generator.next(9).done ); // true ``` + The execution picture: ![](genYield2-2.svg) 1. The first `.next()` starts the execution... It reaches the first `yield`. + 2. The result is returned to the outer code. + 3. The second `.next(4)` passes `4` back to the generator as the result of the first `yield`, and resumes the execution. + 4. ...It reaches the second `yield`, that becomes the result of the generator call. + 5. The third `next(9)` passes `9` into the generator as the result of the second `yield` and resumes the execution that reaches the end of the function, so `done: true`. It's like a "ping-pong" game. Each `next(value)` (excluding the first one) passes a value into the generator, that becomes the result of the current `yield`, and then gets back the result of the next `yield`. @@ -403,25 +555,36 @@ To pass an error into a `yield`, we should call `generator.throw(err)`. In that For instance, here the yield of `"2 + 2 = ?"` leads to an error: ```js run + function* gen() { + try { + let result = yield "2 + 2 = ?"; // (1) alert("The execution does not reach here, because the exception is thrown above"); + } catch(e) { + alert(e); // shows the error + } + } let generator = gen(); let question = generator.next().value; -*!* +\*!* + generator.throw(new Error("The answer is not found in my database")); // (2) -*/!* + +\*/!* + ``` + The error, thrown into the generator at line `(2)` leads to an exception in line `(1)` with `yield`. In the example above, `try..catch` catches it and shows it. If we don't catch it, then just like any exception, it "falls out" the generator into the calling code. @@ -429,23 +592,34 @@ If we don't catch it, then just like any exception, it "falls out" the generator The current line of the calling code is the line with `generator.throw`, labelled as `(2)`. So we can catch it here, like this: ```js run + function* generate() { + let result = yield "2 + 2 = ?"; // Error in this line + } let generator = generate(); let question = generator.next().value; -*!* +\*!* + try { + generator.throw(new Error("The answer is not found in my database")); + } catch(e) { + alert(e); // shows the error + } -*/!* + +\*/!* + ``` + If we don't catch the error there, then, as usual, it falls through to the outer calling code (if any) and, if uncaught, kills the script. ## generator.return @@ -453,19 +627,28 @@ If we don't catch the error there, then, as usual, it falls through to the outer `generator.return(value)` finishes the generator execution and return the given `value`. ```js + function* gen() { + yield 1; + yield 2; + yield 3; + } const g = gen(); -g.next(); // { value: 1, done: false } -g.return('foo'); // { value: "foo", done: true } -g.next(); // { value: undefined, done: true } +g.next(); // { value: 1, done: false } + +g.return("foo"); // { value: "foo", done: true } + +g.next(); // { value: undefined, done: true } + ``` + If we again use `generator.return()` in a completed generator, it will return that value again ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return)). Often we don't use it, as most of time we want to get all returning values, but it can be useful when we want to stop generator in a specific condition. @@ -473,7 +656,9 @@ Often we don't use it, as most of time we want to get all returning values, but ## Summary - Generators are created by generator functions `function* f(…) {…}`. + - Inside generators (only) there exists a `yield` operator. + - The outer code and the generator may exchange results via `next/yield` calls. In modern JavaScript, generators are rarely used. But sometimes they come in handy, because the ability of a function to exchange data with the calling code during the execution is quite unique. And, surely, they are great for making iterable objects. From 88ed6d83011ad2d24485cd7f7c50feb7164b4696 Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Thu, 13 Jul 2023 14:41:32 +0330 Subject: [PATCH 02/11] Update article.md translation of `generators` is completed --- .../1-generators/article.md | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index 68fbbede8..d6c1c3bd1 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -54,7 +54,7 @@ alert(generator); // [object Generator] ``` -اجرای بدنه تایع هنوز شروع نشده است: +اجرای بدنه تابع هنوز شروع نشده است: ![](generateSequence-1.svg) @@ -137,7 +137,7 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} ## generatorها iterable هستند. -همانطور که احتمالا با توجه به `()next` متوجه شده‌اید، generatorها [iterable](info:iterable) هستند. +همان‌طور که احتمالا با توجه به `()next` متوجه شده‌اید، generatorها [iterable](info:iterable) هستند. با استفاد از `for..of` می‌توان از `value` آن‌ها استفاده کرد: @@ -319,7 +319,7 @@ alert([...range]); // 1,2,3,4,5 ```smart header="generatorها ممکن است تا ابد مقدار تولید کنند" -در مثال بالا، یک دنباله کران دار تولید کردیم، ولی می‌توان به همان روش یک دنباله بی‌کران از مقادیر را ساخت. مثل یک دنباله بی‌پایان از اعداد شبه تصادفی. +در مثال بالا، یک دنباله کران‌دار تولید کردیم، ولی می‌توان به همان روش یک دنباله بی‌کران از مقادیر را ساخت. مثل یک دنباله بی‌پایان از اعداد شبه تصادفی. ``` @@ -443,15 +443,15 @@ alert(str); // 0..9A..Za..z ترکیب generatorها یک راه معقول برای استفاده از جریان یک generator درون دیگری است و از حافظه بیشتر برای ذخیره مقادیر استفاده نمی‌کند. -## "yield" is a two-way street +## yield یک خیابان دو طرفه است. -Until this moment, generators were similar to iterable objects, with a special syntax to generate values. But in fact they are much more powerful and flexible. +تا الان، generatorها بسیار شبیه به آبجکت‌های iterable با یک سینتکس خاص برای تولید مقادیر بودند؛ درواقع اما generatorها بسیار قدرتمندتر و انعطاف پذیرتر هستند. -That's because `yield` is a two-way street: it not only returns the result to the outside, but also can pass the value inside the generator. +چون `yield` یک خیابان دو طرفه است: نه تنها مقدار را به بیرون برمی‌گرداند بلکه می‌تواند مقادیر را به داخل generator بیاورد. -To do so, we should call `generator.next(arg)`, with an argument. That argument becomes the result of `yield`. +برای این کار باید `()generator.next` را با یک argument صدا کنیم. این argument تبدیل به مقدار برگردانده شده توسط خود yield درون generator می‌شود. -Let's see an example: +برای مثال: ```js run @@ -459,7 +459,7 @@ function* gen() { \*!* - // Pass a question to the outer code and wait for an answer + // یک سوال را به کد بیرونی برگردانید و منتظر جواب شوید let result = yield "2 + 2 = ?"; // (*) @@ -471,37 +471,37 @@ function* gen() { let generator = gen(); -let question = generator.next().value; // <-- yield returns the value +let question = generator.next().value; // <-- مقدار را بر می‌گرداند yield -generator.next(4); // --> pass the result into the generator +generator.next(4); // --> برمی‌گرداند generator نتیجه را به ``` ![](genYield2.svg) -1. The first call `generator.next()` should be always made without an argument (the argument is ignored if passed). It starts the execution and returns the result of the first `yield "2+2=?"`. At this point the generator pauses the execution, while staying on the line `(*)`. +1. نمی‌توان اولین بار که `()generator.next` صدا می‌شود به آن argument داد و در صورت داده شدن، نادید گرفته خواهد شد. پس از صدا شدن متود، اجرای generator شروع می‌شود و مقدار اولین yield را برمی‌گرداند. اکنون اجرای generator متوقف شده و در خط `*` مانده است. -2. Then, as shown at the picture above, the result of `yield` gets into the `question` variable in the calling code. +2. سپس مانند تصویر بالا، نتیجه yield اول در متغیر `question` ذخیره می‌شود. -3. On `generator.next(4)`, the generator resumes, and `4` gets in as the result: `let result = 4`. +3. با اجرای `generator.next(4)`، اجرای generator دوباره شروع می‌‎شود و مقدار متغیر `result` برابر `4` می‌شود. -Please note, the outer code does not have to immediately call `next(4)`. It may take time. That's not a problem: the generator will wait. +توجه داشته باشید که نیاز نیست کد بیرونی فورا `(4)next` را صدا کند؛ اگر طول بکشد، generator صبر خواهد کرد. -For instance: +برای مثال: ```js -// resume the generator after some time +// پس از تاخیری دوباره شروع می‌شود generator اجرای setTimeout(() => generator.next(4), 1000); ``` -As we can see, unlike regular functions, a generator and the calling code can exchange results by passing values in `next/yield`. +همان‌طور که مشاهده می‌شود بر خلاف توابع معمولی، یک generator و کد صدا زننده‌اش می‌توانند با هم مقادیر را از طریق `next/yield` رد و بدل کنند. -To make things more obvious, here's another example, with more calls: +یک مثال دیگر: ```js run @@ -528,31 +528,31 @@ alert(generator.next(9).done); // true ``` -The execution picture: +تصویر اجرا: ![](genYield2-2.svg) -1. The first `.next()` starts the execution... It reaches the first `yield`. +1. اولین `()next`اجرای generator را آغاز می‌کند تا به اولین yield برسد. -2. The result is returned to the outer code. +2. نتیجه به کد بیرونی برگردانده می‌شود. -3. The second `.next(4)` passes `4` back to the generator as the result of the first `yield`, and resumes the execution. +3. صدا زده شدن `next(4)` مقدار `4` را به generator به عنوان نتیجه اولین yield باز می‌گرداند و اجرای generator را دوباره شروع می‌کند. -4. ...It reaches the second `yield`, that becomes the result of the generator call. +4. به yield دوم می‌رسد و مقدار آن نتیجه دومین بار صدا شدن `next` است. -5. The third `next(9)` passes `9` into the generator as the result of the second `yield` and resumes the execution that reaches the end of the function, so `done: true`. +5. صدا زده شدن `next(9)`مقدار `9` را به عنوان نتیجه دومین yield برمی‌گرداند و اجرای generator دوباره شروع می‌شود تا به انتهای تابع، `done:true` برسد. -It's like a "ping-pong" game. Each `next(value)` (excluding the first one) passes a value into the generator, that becomes the result of the current `yield`, and then gets back the result of the next `yield`. +درست مثل بازی پینگ پنگ؛ `(value)next` یک مقدار را به generator پاس می‌دهد که نتیجه yield فعلی می‌شود و سپس نتیجه yield بعدی به بیرون پاس داده می‌شود. ## generator.throw -As we observed in the examples above, the outer code may pass a value into the generator, as the result of `yield`. +همان‌طور که در مثال‌های بالا دیدیم، کد بیرونی می‌تواند یک مقدار را به generator در جواب yield پاس بدهد. -...But it can also initiate (throw) an error there. That's natural, as an error is a kind of result. +...اما می‌تواند در آن حین یک ارور پرتاب کند که طبیعی است؛ چون ارور نیز یک جور نتیجه است. -To pass an error into a `yield`, we should call `generator.throw(err)`. In that case, the `err` is thrown in the line with that `yield`. +برای اینکه یک ارور را به yield پاس بدهیم، باید `(err)genrator.throw` را صدا کنیم. در این صورت، `err` در خط با yield پرتاب می‌شود. -For instance, here the yield of `"2 + 2 = ?"` leads to an error: +برای مثال اینجا yield شدن "2 + 2 = ?" باعث ارور می‌شود: ```js run @@ -562,11 +562,11 @@ function* gen() { let result = yield "2 + 2 = ?"; // (1) - alert("The execution does not reach here, because the exception is thrown above"); + alert("اجرا به اینجا نمی‌رسد چون خط بالا ارور پرتاب کرده است"); } catch(e) { - alert(e); // shows the error + alert(e); // ارور را نشان می‌دهد } @@ -578,24 +578,24 @@ let question = generator.next().value; \*!* -generator.throw(new Error("The answer is not found in my database")); // (2) +generator.throw(new Error("پاسخ در دیتابیس من نیست")); // (2) \*/!* ``` -The error, thrown into the generator at line `(2)` leads to an exception in line `(1)` with `yield`. In the example above, `try..catch` catches it and shows it. +ارور پرتاب شده به داخل generator در خط `2` باعث exception در خط `1` دارای yield می‌شود که در مثال بالا توسط `try..catch` گرفته شده و نمایش داده می‌شود. -If we don't catch it, then just like any exception, it "falls out" the generator into the calling code. +اگر آن را catch نکنیم، مانند هر exception دیگری اجرا از generator به کد بیرونی منتقل می‌شود. -The current line of the calling code is the line with `generator.throw`, labelled as `(2)`. So we can catch it here, like this: +خط فعلی کد صدا زننده، خط دارای `generator.throw` با لیبل `2` است. پس خطا را این گونه هم می‌توان گرفت: ```js run function* generate() { - let result = yield "2 + 2 = ?"; // Error in this line + let result = yield "2 + 2 = ?"; // خطا در این خط } @@ -607,11 +607,11 @@ let question = generator.next().value; try { - generator.throw(new Error("The answer is not found in my database")); + generator.throw(new Error("پاسخ در دیتابیس من نیست")); } catch(e) { - alert(e); // shows the error + alert(e); // ارور را نمایش می‌دهد } @@ -620,11 +620,11 @@ try { ``` -If we don't catch the error there, then, as usual, it falls through to the outer calling code (if any) and, if uncaught, kills the script. +اگر ارور را catch نکنیم، در صورت وجود کد بیرونی اجرا به آن منتقل می‌شود و اگر آن‌جا نیز هندل نشده باشد، اجرای کد با خطا پایان می‌پذیرد. ## generator.return -`generator.return(value)` finishes the generator execution and return the given `value`. +این متود اجرای generator را به اتمام می‌رساند و مقدار argument را به عنوان نتیجه برمی‌گرداند. ```js @@ -649,20 +649,20 @@ g.next(); // { value: undefined, done: true } ``` -If we again use `generator.return()` in a completed generator, it will return that value again ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return)). +اگر در یک generatorخاتمه یافته دوباره از `()generator.return`استفاده کنیم، همان مقدار را دوباره برمی‌گرداند.([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return)). -Often we don't use it, as most of time we want to get all returning values, but it can be useful when we want to stop generator in a specific condition. +معمولا از آن استفاده نمی‌شود؛ چون اکثر زمان‌ها می‌خواهیم تمام مقادیر را بگیریم، اما موقعی که بخواهیم در شرایط خاص generator را متوقف کنیم کاربرد دارد. -## Summary +## خلاصه -- Generators are created by generator functions `function* f(…) {…}`. +- generatorها توسط تابع generator تولید می‌شوند. `{...} (...) function* f` -- Inside generators (only) there exists a `yield` operator. +- عملگر yield (فقط) در داخل generatorها وجود دارد. -- The outer code and the generator may exchange results via `next/yield` calls. +- کد بیرونی و generator ممکن است توسط `next/yield` با هم نتایج را رد و بدل کنند. -In modern JavaScript, generators are rarely used. But sometimes they come in handy, because the ability of a function to exchange data with the calling code during the execution is quite unique. And, surely, they are great for making iterable objects. +در جاوااسکریپت مدرن، generatorها کم استفاده می‌شوند. اما گاهی اوقات می‌توانند مفید باشند؛ رد و بدل کردن داده با کد صدا زننده، یک قابلیت منحصر بفرد است. هم‌چنین برای ساخت iterableها هم بکار می‌روند. -Also, in the next chapter we'll learn async generators, which are used to read streams of asynchronously generated data (e.g paginated fetches over a network) in `for await ... of` loops. +علاوه بر آن، در چپتر بعدی، async generatorها را یاد خواهیم گرفت که برای خواندن جریان‌های asynchronously generated data استفاده می‌شود؛ مثلا fetchهای paginatedشده در شبکه توسط `for await...of loop`. -In web-programming we often work with streamed data, so that's another very important use case. +از آنجایی که در برنامه نویسی وب، با جریان‌های داده، زیاد سر و کار داریم این یک کاربرد بسیار مهم است. From 398a8a5c17bd72fd42400ba2df6c3866f9c2e342 Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Thu, 13 Jul 2023 14:58:19 +0330 Subject: [PATCH 03/11] Update task.md added task description for `generators` --- .../01-pseudo-random-generator/task.md | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md index e7c251ad3..4620869a4 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md @@ -1,34 +1,44 @@ +# generator شبه تصادفی -# Pseudo-random generator +سناریوهای زیادی وجود دارند که در آن به دیتای تصادفی نیاز است. -There are many areas where we need random data. +یکی از آن‌ها تست کردن است. ممکن است ما برای یک تست خوب به دیتای تصادفی نیاز داشته باشیم: متن، عدد و غیره. -One of them is testing. We may need random data: text, numbers, etc. to test things out well. +در جاوااسکریپت می‌توان از `()Math.random` استفاده کرد. ولی می‌خواهیم این قابلیت را داشته باشیم که تست را دقیقا با همان دیتا بتوانیم تکرار کنیم. -In JavaScript, we could use `Math.random()`. But if something goes wrong, we'd like to be able to repeat the test, using exactly the same data. +برای این منظور "seeded pseudo-random generators" استفاده می‌شوند. این generatorها یک "seed" -مقدار اولیه- را می‌گیرند و طبق یک فرمول باقی دنباله را تولید می‌کنند. در نتیجه "seed" یکسان دنباله یکسانی را تولید می‌کند و کل دنباله را به راحتی می‌توان بازتولید کرد. فقط نیاز است "seed" را به یاد داشته باشیم. -For that, so called "seeded pseudo-random generators" are used. They take a "seed", the first value, and then generate the next ones using a formula so that the same seed yields the same sequence, and hence the whole flow is easily reproducible. We only need to remember the seed to repeat it. - -An example of such formula, that generates somewhat uniformly distributed values: +یک مثال از چنین فرمولی که مقادیری با توزیع تقریبا یکنواخت تولید می‌کند: ``` + next = previous * 16807 % 2147483647 + ``` -If we use `1` as the seed, the values will be: + +اگر از `1` به عنوان "seed" استفاده کنیم دنباله به شکل زیر خواهد بود: + 1. `16807` + 2. `282475249` + 3. `1622650073` -4. ...and so on... -The task is to create a generator function `pseudoRandom(seed)` that takes `seed` and creates the generator with this formula. +4. ...و به همین ترتیب ادامه می‌یابد... + +تسک، ساختن یک تابع generator با امضای `pseudoRandom(seed)` است که یک "seed" می‌گیرد و یک generator با فرمول داده شده می‌سازد. -Usage example: +مثلا: ```js + let generator = pseudoRandom(1); alert(generator.next().value); // 16807 + alert(generator.next().value); // 282475249 + alert(generator.next().value); // 1622650073 + ``` From f0567b652337a7acc32d0c22e2bdd82e0faadf4e Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Thu, 13 Jul 2023 15:01:25 +0330 Subject: [PATCH 04/11] Update solution.md added solution translation for `generators` --- .../01-pseudo-random-generator/solution.md | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md index 4355d0cfc..7e9c492f5 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md @@ -1,10 +1,15 @@ ```js run demo + function* pseudoRandom(seed) { + let value = seed; while(true) { + value = value * 16807 % 2147483647; + yield value; + } }; @@ -12,27 +17,41 @@ function* pseudoRandom(seed) { let generator = pseudoRandom(1); alert(generator.next().value); // 16807 + alert(generator.next().value); // 282475249 + alert(generator.next().value); // 1622650073 + ``` -Please note, the same can be done with a regular function, like this: + +توجه داشته باشید که این کار را با توابع عادی هم می‌توان انجام داد: ```js run + function pseudoRandom(seed) { + let value = seed; return function() { + value = value * 16807 % 2147483647; + return value; + } + } let generator = pseudoRandom(1); alert(generator()); // 16807 + alert(generator()); // 282475249 + alert(generator()); // 1622650073 + ``` -That also works. But then we lose ability to iterate with `for..of` and to use generator composition, that may be useful elsewhere. + +این گونه هم کار می‌کند. منتها قابلیت iterate کردن با `for..of` و generator composition از دست می‌رود که ممکن است جای دیگری مفید باشند. From 7af5b3c4b3cb5b004cbbe2f31c76b220ef4e04da Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Fri, 14 Jul 2023 15:21:43 +0330 Subject: [PATCH 05/11] update line breaks(partial) --- .../1-generators/article.md | 101 +----------------- 1 file changed, 3 insertions(+), 98 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index d6c1c3bd1..12726f870 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -11,49 +11,31 @@ ظاهر یک تابع generator به صورت زیر است: ```js - function* generateSequence() { - yield 1; - yield 2; - return 3; - } - ``` - توابع generator با توابع معمول، رفتار متفاوتی دارند. زمانی که این توابع صدا می‌شوند، بدنه آن‌ها اجرا نمی‌شود؛ در عوض، یک آبجکت خاص به نام "generator object" برمی‌گردانند که به وسیله آن اجرای تابع را می‌توان کنترل کرد. برای مثال: ```js run - function* generateSequence() { - yield 1; - yield 2; - return 3; - } //برمی‌گرداند generator یک آبجکت generator تابع - let generator = generateSequence(); - \*!* - alert(generator); // [object Generator] - \*/!* - ``` - اجرای بدنه تابع هنوز شروع نشده است: ![](generateSequence-1.svg) @@ -61,38 +43,27 @@ alert(generator); // [object Generator] متد اصلی یک آبجکت generator متد `()next` است. هنگامی که صدا می‌شود، بدنه تابع تا اولین `yield value` اجرا می‌شود(`value` می‌تواند حذف شود که در این صورت `undefined` است.)؛ سپس اجرای تابع متوقف می‌شود و مقدار yield شده برگرداننده می‌شود. مقدار برگردانده شده توسط متود `next` همواره یک آبجکت با 2 پراپرتی است: - - `value`: مقدار برگرداننده شده توسط `yield`. - - `done`: یک Boolean است که در صورت اتمام بدنه تابع مقدار true و در غیر این صورت مقدار false دارد. برای مثال، در کد زیر، یک آبجکت generator ایجاد شده و اولین مقدار `yield` شده توسط آن گرفته شده است: ```js run - function* generateSequence() { - yield 1; - yield 2; - return 3; - } let generator = generateSequence(); \*!* - let one = generator.next(); - \*/!* alert(JSON.stringify(one)); // {value: 1, done: false} - ``` - اکنون فقط مقدار اول را گرفته‌ایم و اجرای تابع در خط دوم متوقف شده است: ![](generateSequence-2.svg) @@ -100,27 +71,21 @@ alert(JSON.stringify(one)); // {value: 1, done: false} اکنون اگر دوباره `()generator.next` را صدا بزنیم اجرای تابع شروع می‌شود و تا `yield` بعدی و برگردانده شدن مقدار ادامه می‌یابد: ```js - let two = generator.next(); alert(JSON.stringify(two)); // {value: 2, done: false} - ``` - ![](generateSequence-3.svg) و اگر برای بار سوم آن را صدا بزنیم، اجرای تابع به `return` می‌رسد و تمام می‌شود: ```js - let three = generator.next(); alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} - ``` - ![](generateSequence-4.svg) اکنون از روی `done:true` متوجه می‌شویم کار generator تمام شده و `value:3` آخرین مقدار برگردانده شده توسط generator است. @@ -128,11 +93,9 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} دیگر صدا کردن `()generator.next` منطقی نیست. اگر این کار را انجام دهیم، آبجکت یکسانی با `done:true` برگردانده می‌شود. ```smart header="`function* f(…)`یا`function *f(…)`؟" - هر دو سینتکس صحیح هستند. ولی معمولا اولی ترجیح داده می‌شود؛ چون `*` نوع تابع و نه نام تابع را مشخص می‌کند. - ```` ## generatorها iterable هستند. @@ -142,25 +105,17 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} با استفاد از `for..of` می‌توان از `value` آن‌ها استفاده کرد: ```js run - function* generateSequence() { - yield 1; - yield 2; - return 3; - } let generator = generateSequence(); for(let value of generator) { - alert(value); // ابتدا 1 و سپس 2 - } - ```` این شیوه از صدا کردن `next` تمیزتر است؛ این‌گونه فکر نمی‌کنید؟ @@ -168,54 +123,37 @@ for(let value of generator) { ...اما دقت کنید: مثال بالا ابتدا `1` و سپس `2` را نشان داد؛ خبری از `3` نیست! علت این اتفاق این است که `for..of` آخرین مقدار را هنگامی که `done:true` است در نظر نمی‌گیرد. هنگام برگرداندن آخرین مقدار با `return`، بر خلاف `done:true`، `yield` است. در نتیجه برای نشان دادن تمام مقادیر باید آن‌ها را با `yield` برگردانیم: -```js run +```js run function* generateSequence() { - yield 1; - yield 2; - \*!* - yield 3; - \*/!* - } let generator = generateSequence(); for(let value of generator) { - alert(value); // ابتدا 1 سپس 2 و بعد از آن 3 - } - ``` - از آنجایی که generatorها iterable هستند، از تمام functionality آن‌ها نیز برای generatorها می‌توان استفاده کرد؛ مثل spread syntax `...`: ```js run - function* generateSequence() { - yield 1; - yield 2; - yield 3; - } let sequence = [0, ...generateSequence()]; alert(sequence); // 0, 1, 2, 3 - ``` - در کد بالا، `()generateSequence...`، باعث می‌شود آبجکت generator که iterable هم هست به آرایه‌ای از اعداد تبدیل شود.(درباره spread syntax در چپتر [](info:rest-parameters-spread#spread-syntax) بیشتر بخوانید.) ## استفاده از generatorها برای iterableها @@ -225,85 +163,52 @@ alert(sequence); // 0, 1, 2, 3 کد آن به شرح زیر بود: ```js run - let range = { - from: 1, - to: 5, // در ابتدا این متود را فقط یک بار صدا می‌کند for..of range - [Symbol.iterator]() { - // این، آبجکت ایتریتور را باز می‌گرداند: - // فقط با آن آبجکت کار می‌کند و از آن مقادیر بعدی را می‌خواند for..of سپس return { - current: this.from, - last: this.to, // صدا می‌شود for..of توسط iteration در هر next() - next() { - - // باید مقدار را به عنوان یک آبجکت برگرداند: - // {value: ..., done: ...} - + // {value: ..., done: ...}:باید مقدار را به عنوان یک آبجکت برگرداند if (this.current <= this.last) { - return { done: false, value: this.current++ }; - } else { - return { done: true }; - } - }, - }; - }, - }; // برمی‌گرداند range.to تا range.from اعداد را از range روی iteration alert([...range]); // 1,2,3,4,5 - ``` - می‌توان از یک تابع generator برای iteration به جای Symbol.iterator استفاده کرد. این همان `range` اما بسیار جمع و جور تر است: ```js run - let range = { - from: 1, - to: 5, - \*[Symbol.iterator]() { - - //[Symbol.iterator] نسخه جمع و جور : function*() - + *[Symbol.iterator]() {//[Symbol.iterator] نسخه جمع و جور : function*() for (let value = this.from; value <= this.to; value++) { - yield value; - } - }, - }; alert([...range]); // 1,2,3,4,5 - ``` From de269d01fae4466b97c57248673d08d4502a9135 Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Fri, 14 Jul 2023 15:37:25 +0330 Subject: [PATCH 06/11] formatting done --- .../1-generators/article.md | 92 +------------------ 1 file changed, 1 insertion(+), 91 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index 12726f870..a5f0fb9cb 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -211,11 +211,8 @@ let range = { alert([...range]); // 1,2,3,4,5 ``` - دلیل کارکرد روش بالا این است که `()range[Symbol.iterator]` دقیقا همان چیزی را برمی‌گرداند که `for..of` انتظار دارد: - - متود `next` موجود است. - - مقدار بازگشتی به فرم `{value:..., done:true/false}` است. این کارکرد یک اتفاق نیست، generatorها با توجه به iterator ها، برای پیاده‌سازی ساده‌تر آن‌ها به زبان اضافه شده‌اند. @@ -223,12 +220,11 @@ alert([...range]); // 1,2,3,4,5 روشی که از generator استفاده می‌کند بسیار مختصرتر از روش اول `range` است و همان کارکرد را دارد. ```smart header="generatorها ممکن است تا ابد مقدار تولید کنند" - در مثال بالا، یک دنباله کران‌دار تولید کردیم، ولی می‌توان به همان روش یک دنباله بی‌کران از مقادیر را ساخت. مثل یک دنباله بی‌پایان از اعداد شبه تصادفی. +چنین کاربردی قطعا به یک `break` یا `return` در `for..of` نیاز دارد. در غیر این صورت حلقه تا ابد تکرار می‌شود. ``` - ## ترکیب generatorها ترکیب generatorها قابلیتی است که به وسیله آن می‌توان generatorها را در هم `embed` کرد. @@ -236,18 +232,12 @@ alert([...range]); // 1,2,3,4,5 برای مثال یک generator داریم که یک دنباله از اعداد را تولید می‌کند: ```js - function* generateSequence(start, end) { - for (let i = start; i <= end; i++) yield i; - } - ``` - اکنون می‎‌خواهیم از آن به نحوی بازاستفاده کنیم که دنباله پیچیده‌تری بتوان ایجاد کرد: - - ابتدا ارقام از `0` تا `9`(با کد کاراکتر 48 تا 57) - سپس حروف بزرگ از `A` تا `Z`(با کد کاراکتر 65 تا 90) - سپس حروف کوچک از `a` تا `z`(با کد کاراکتر 97 تا 122) @@ -261,29 +251,21 @@ function* generateSequence(start, end) { generator ترکیب شده: ```js run - function* generateSequence(start, end) { - for (let i = start; i <= end; i++) yield i; - } function* generatePasswordCodes() { \*!* - // 0..9 - yield* generateSequence(48, 57); // A..Z - yield* generateSequence(65, 90); // a..z - yield* generateSequence(97, 122); - \*/!* } @@ -291,44 +273,32 @@ function* generatePasswordCodes() { let str = ''; for(let code of generatePasswordCodes()) { - str += String.fromCharCode(code); - } alert(str); // 0..9A..Za..z - ``` - عبارت `*yield` اجرا را به یک generator دیگر می‌سپارد(اصطلاحا `delegate` می‌کند). بدان معنا که `yeild* gen` روی `gen` ایتریت می‌کند و به صورت درونی مقدار yield شده را به بیرون هدایت می‌کند؛ انگار که کلا مقدار توسط generator دوم تولید شده است. اگر از generatorها به صورت inline و تو در تو استفاده کنیم نیز به همان نتیجه می‌رسیم: ```js run - function* generateSequence(start, end) { - for (let i = start; i <= end; i++) yield i; - } function* generateAlphaNum() { \*!* - // yield* generateSequence(48, 57); - for (let i = 48; i <= 57; i++) yield i; // yield* generateSequence(65, 90); - for (let i = 65; i <= 90; i++) yield i; // yield* generateSequence(97, 122); - for (let i = 97; i <= 122; i++) yield i; - \*/!* } @@ -336,16 +306,12 @@ function* generateAlphaNum() { let str = ''; for(let code of generateAlphaNum()) { - str += String.fromCharCode(code); - } alert(str); // 0..9A..Za..z - ``` - ترکیب generatorها یک راه معقول برای استفاده از جریان یک generator درون دیگری است و از حافظه بیشتر برای ذخیره مقادیر استفاده نمی‌کند. ## yield یک خیابان دو طرفه است. @@ -359,19 +325,13 @@ alert(str); // 0..9A..Za..z برای مثال: ```js run - function* gen() { - \*!* - // یک سوال را به کد بیرونی برگردانید و منتظر جواب شوید - let result = yield "2 + 2 = ?"; // (*) - \*/!* alert(result); - } let generator = gen(); @@ -379,16 +339,12 @@ let generator = gen(); let question = generator.next().value; // <-- مقدار را بر می‌گرداند yield generator.next(4); // --> برمی‌گرداند generator نتیجه را به - ``` - ![](genYield2.svg) 1. نمی‌توان اولین بار که `()generator.next` صدا می‌شود به آن argument داد و در صورت داده شدن، نادید گرفته خواهد شد. پس از صدا شدن متود، اجرای generator شروع می‌شود و مقدار اولین yield را برمی‌گرداند. اکنون اجرای generator متوقف شده و در خط `*` مانده است. - 2. سپس مانند تصویر بالا، نتیجه yield اول در متغیر `question` ذخیره می‌شود. - 3. با اجرای `generator.next(4)`، اجرای generator دوباره شروع می‌‎شود و مقدار متغیر `result` برابر `4` می‌شود. توجه داشته باشید که نیاز نیست کد بیرونی فورا `(4)next` را صدا کند؛ اگر طول بکشد، generator صبر خواهد کرد. @@ -396,22 +352,16 @@ generator.next(4); // --> برمی‌گرداند generator نتیجه را به برای مثال: ```js - // پس از تاخیری دوباره شروع می‌شود generator اجرای - setTimeout(() => generator.next(4), 1000); - ``` - همان‌طور که مشاهده می‌شود بر خلاف توابع معمولی، یک generator و کد صدا زننده‌اش می‌توانند با هم مقادیر را از طریق `next/yield` رد و بدل کنند. یک مثال دیگر: ```js run - function* gen() { - let ask1 = yield "2 + 2 = ?"; alert(ask1); // 4 @@ -419,7 +369,6 @@ function* gen() { let ask2 = yield "3 * 3 = ?"; alert(ask2); // 9 - } let generator = gen(); @@ -429,22 +378,16 @@ alert(generator.next().value); // "2 + 2 = ?" alert(generator.next(4).value); // "3 * 3 = ?" alert(generator.next(9).done); // true - ``` - تصویر اجرا: ![](genYield2-2.svg) 1. اولین `()next`اجرای generator را آغاز می‌کند تا به اولین yield برسد. - 2. نتیجه به کد بیرونی برگردانده می‌شود. - 3. صدا زده شدن `next(4)` مقدار `4` را به generator به عنوان نتیجه اولین yield باز می‌گرداند و اجرای generator را دوباره شروع می‌کند. - 4. به yield دوم می‌رسد و مقدار آن نتیجه دومین بار صدا شدن `next` است. - 5. صدا زده شدن `next(9)`مقدار `9` را به عنوان نتیجه دومین yield برمی‌گرداند و اجرای generator دوباره شروع می‌شود تا به انتهای تابع، `done:true` برسد. درست مثل بازی پینگ پنگ؛ `(value)next` یک مقدار را به generator پاس می‌دهد که نتیجه yield فعلی می‌شود و سپس نتیجه yield بعدی به بیرون پاس داده می‌شود. @@ -460,21 +403,14 @@ alert(generator.next(9).done); // true برای مثال اینجا yield شدن "2 + 2 = ?" باعث ارور می‌شود: ```js run - function* gen() { - try { - let result = yield "2 + 2 = ?"; // (1) alert("اجرا به اینجا نمی‌رسد چون خط بالا ارور پرتاب کرده است"); - } catch(e) { - alert(e); // ارور را نشان می‌دهد - } - } let generator = gen(); @@ -482,14 +418,10 @@ let generator = gen(); let question = generator.next().value; \*!* - generator.throw(new Error("پاسخ در دیتابیس من نیست")); // (2) - \*/!* - ``` - ارور پرتاب شده به داخل generator در خط `2` باعث exception در خط `1` دارای yield می‌شود که در مثال بالا توسط `try..catch` گرفته شده و نمایش داده می‌شود. اگر آن را catch نکنیم، مانند هر exception دیگری اجرا از generator به کد بیرونی منتقل می‌شود. @@ -497,11 +429,8 @@ generator.throw(new Error("پاسخ در دیتابیس من نیست")); // (2) خط فعلی کد صدا زننده، خط دارای `generator.throw` با لیبل `2` است. پس خطا را این گونه هم می‌توان گرفت: ```js run - function* generate() { - let result = yield "2 + 2 = ?"; // خطا در این خط - } let generator = generate(); @@ -509,22 +438,14 @@ let generator = generate(); let question = generator.next().value; \*!* - try { - generator.throw(new Error("پاسخ در دیتابیس من نیست")); - } catch(e) { - alert(e); // ارور را نمایش می‌دهد - } - \*/!* - ``` - اگر ارور را catch نکنیم، در صورت وجود کد بیرونی اجرا به آن منتقل می‌شود و اگر آن‌جا نیز هندل نشده باشد، اجرای کد با خطا پایان می‌پذیرد. ## generator.return @@ -532,28 +453,19 @@ try { این متود اجرای generator را به اتمام می‌رساند و مقدار argument را به عنوان نتیجه برمی‌گرداند. ```js - function* gen() { - yield 1; - yield 2; - yield 3; - } const g = gen(); g.next(); // { value: 1, done: false } - g.return("foo"); // { value: "foo", done: true } - g.next(); // { value: undefined, done: true } - ``` - اگر در یک generatorخاتمه یافته دوباره از `()generator.return`استفاده کنیم، همان مقدار را دوباره برمی‌گرداند.([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return)). معمولا از آن استفاده نمی‌شود؛ چون اکثر زمان‌ها می‌خواهیم تمام مقادیر را بگیریم، اما موقعی که بخواهیم در شرایط خاص generator را متوقف کنیم کاربرد دارد. @@ -561,9 +473,7 @@ g.next(); // { value: undefined, done: true } ## خلاصه - generatorها توسط تابع generator تولید می‌شوند. `{...} (...) function* f` - - عملگر yield (فقط) در داخل generatorها وجود دارد. - - کد بیرونی و generator ممکن است توسط `next/yield` با هم نتایج را رد و بدل کنند. در جاوااسکریپت مدرن، generatorها کم استفاده می‌شوند. اما گاهی اوقات می‌توانند مفید باشند؛ رد و بدل کردن داده با کد صدا زننده، یک قابلیت منحصر بفرد است. هم‌چنین برای ساخت iterableها هم بکار می‌روند. From 8c79a97245302c63665f75e70519901ae3cb4431 Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Fri, 14 Jul 2023 15:39:29 +0330 Subject: [PATCH 07/11] Update task format --- .../1-generators/01-pseudo-random-generator/task.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md index 4620869a4..112f5a44e 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md @@ -1,3 +1,4 @@ + # generator شبه تصادفی سناریوهای زیادی وجود دارند که در آن به دیتای تصادفی نیاز است. @@ -11,20 +12,13 @@ یک مثال از چنین فرمولی که مقادیری با توزیع تقریبا یکنواخت تولید می‌کند: ``` - next = previous * 16807 % 2147483647 - ``` - اگر از `1` به عنوان "seed" استفاده کنیم دنباله به شکل زیر خواهد بود: - 1. `16807` - 2. `282475249` - 3. `1622650073` - 4. ...و به همین ترتیب ادامه می‌یابد... تسک، ساختن یک تابع generator با امضای `pseudoRandom(seed)` است که یک "seed" می‌گیرد و یک generator با فرمول داده شده می‌سازد. @@ -32,13 +26,9 @@ next = previous * 16807 % 2147483647 مثلا: ```js - let generator = pseudoRandom(1); alert(generator.next().value); // 16807 - alert(generator.next().value); // 282475249 - alert(generator.next().value); // 1622650073 - ``` From 68dd23e3d671779099f8abe8a895f4061f20dfde Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Fri, 14 Jul 2023 15:41:01 +0330 Subject: [PATCH 08/11] Update solution formatting --- .../01-pseudo-random-generator/solution.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md index 7e9c492f5..7e5d45011 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md @@ -1,15 +1,10 @@ ```js run demo - function* pseudoRandom(seed) { - let value = seed; while(true) { - value = value * 16807 % 2147483647; - yield value; - } }; @@ -17,41 +12,27 @@ function* pseudoRandom(seed) { let generator = pseudoRandom(1); alert(generator.next().value); // 16807 - alert(generator.next().value); // 282475249 - alert(generator.next().value); // 1622650073 - ``` - توجه داشته باشید که این کار را با توابع عادی هم می‌توان انجام داد: ```js run - function pseudoRandom(seed) { - let value = seed; return function() { - value = value * 16807 % 2147483647; - return value; - } - } let generator = pseudoRandom(1); alert(generator()); // 16807 - alert(generator()); // 282475249 - alert(generator()); // 1622650073 - ``` - این گونه هم کار می‌کند. منتها قابلیت iterate کردن با `for..of` و generator composition از دست می‌رود که ممکن است جای دیگری مفید باشند. From 4f881de8fbf548246311f42a54839dcf0656b148 Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Sat, 15 Jul 2023 11:21:32 +0330 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: Mahdi Hashemi --- .../01-pseudo-random-generator/task.md | 4 +-- .../1-generators/article.md | 32 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md index 112f5a44e..6a1bcee8c 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md @@ -7,7 +7,7 @@ در جاوااسکریپت می‌توان از `()Math.random` استفاده کرد. ولی می‌خواهیم این قابلیت را داشته باشیم که تست را دقیقا با همان دیتا بتوانیم تکرار کنیم. -برای این منظور "seeded pseudo-random generators" استفاده می‌شوند. این generatorها یک "seed" -مقدار اولیه- را می‌گیرند و طبق یک فرمول باقی دنباله را تولید می‌کنند. در نتیجه "seed" یکسان دنباله یکسانی را تولید می‌کند و کل دنباله را به راحتی می‌توان بازتولید کرد. فقط نیاز است "seed" را به یاد داشته باشیم. +برای این منظور "seeded pseudo-random generators" (generatorهای شبه تصادفی با یک هسته اولیه) استفاده می‌شوند. این generatorها یک "seed" -مقدار اولیه- را می‌گیرند و طبق یک فرمول باقی دنباله را تولید می‌کنند. در نتیجه "seed" یکسان دنباله یکسانی را تولید می‌کند و کل دنباله را به راحتی می‌توان بازتولید کرد. فقط نیاز است "seed" را به یاد داشته باشیم. یک مثال از چنین فرمولی که مقادیری با توزیع تقریبا یکنواخت تولید می‌کند: @@ -21,7 +21,7 @@ next = previous * 16807 % 2147483647 3. `1622650073` 4. ...و به همین ترتیب ادامه می‌یابد... -تسک، ساختن یک تابع generator با امضای `pseudoRandom(seed)` است که یک "seed" می‌گیرد و یک generator با فرمول داده شده می‌سازد. +تسک، ساختن یک تابع generator با نام `pseudoRandom(seed)` است که یک "seed" می‌گیرد و یک generator با فرمول داده شده می‌سازد. مثلا: diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index a5f0fb9cb..f9d9e9df5 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -1,8 +1,8 @@ # Generators -توابع معمول فقط یک‌بار می‌توانند یک مقدار(مثلا یک object یا undefined) را برگردانند. +توابع معمولی فقط یک‌بار می‌توانند یک مقدار(مثلا یک object یا undefined) را برگردانند. -اما generatorها می‌توانند چندین بار، بر اساس تقاضا، مقادیر متفاوت را برگردانند(اصطلاحا yield کنند.). generatorها با [iterableها](info:iterable) به خوبی کار می‌کنند و به کمک آن‌ها می‌توان جریان‌های داده ساخت. +اما generatorها می‌توانند چندین بار، بر اساس تقاضا، مقادیر متفاوت را برگردانند(اصطلاحا yield کنند.). generatorها با [حلقه‌پذیرها](info:iterable) (iterable) به خوبی کار می‌کنند و به کمک آن‌ها می‌توان جریان‌های داده ساخت. ## توابع Generator @@ -18,7 +18,7 @@ function* generateSequence() { } ``` -توابع generator با توابع معمول، رفتار متفاوتی دارند. زمانی که این توابع صدا می‌شوند، بدنه آن‌ها اجرا نمی‌شود؛ در عوض، یک آبجکت خاص به نام "generator object" برمی‌گردانند که به وسیله آن اجرای تابع را می‌توان کنترل کرد. +توابع generator با توابع معمولی، رفتار متفاوتی دارند. زمانی که این توابع صدا می‌شوند، بدنه آن‌ها اجرا نمی‌شود؛ در عوض، یک شیء خاص به نام "generator object" برمی‌گردانند که به وسیله آن اجرای تابع را می‌توان کنترل کرد. برای مثال: @@ -29,7 +29,7 @@ function* generateSequence() { return 3; } -//برمی‌گرداند generator یک آبجکت generator تابع +//برمی‌گرداند generator یک شیء generator تابع let generator = generateSequence(); \*!* alert(generator); // [object Generator] @@ -40,13 +40,13 @@ alert(generator); // [object Generator] ![](generateSequence-1.svg) -متد اصلی یک آبجکت generator متد `()next` است. هنگامی که صدا می‌شود، بدنه تابع تا اولین `yield value` اجرا می‌شود(`value` می‌تواند حذف شود که در این صورت `undefined` است.)؛ سپس اجرای تابع متوقف می‌شود و مقدار yield شده برگرداننده می‌شود. +متد اصلی یک شیء generator متد `()next` است. هنگامی که صدا می‌شود، بدنه تابع تا اولین `yield value` اجرا می‌شود(`value` می‌تواند حذف شود که در این صورت `undefined` است.)؛ سپس اجرای تابع متوقف می‌شود و مقدار yield شده برگرداننده می‌شود. مقدار برگردانده شده توسط متود `next` همواره یک آبجکت با 2 پراپرتی است: - `value`: مقدار برگرداننده شده توسط `yield`. - `done`: یک Boolean است که در صورت اتمام بدنه تابع مقدار true و در غیر این صورت مقدار false دارد. -برای مثال، در کد زیر، یک آبجکت generator ایجاد شده و اولین مقدار `yield` شده توسط آن گرفته شده است: +برای مثال، در کد زیر، یک شیء generator ایجاد شده و اولین مقدار `yield` شده توسط آن گرفته شده است: ```js run function* generateSequence() { @@ -90,7 +90,7 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} اکنون از روی `done:true` متوجه می‌شویم کار generator تمام شده و `value:3` آخرین مقدار برگردانده شده توسط generator است. -دیگر صدا کردن `()generator.next` منطقی نیست. اگر این کار را انجام دهیم، آبجکت یکسانی با `done:true` برگردانده می‌شود. +دیگر صدا کردن `()generator.next` منطقی نیست. اگر این کار را انجام دهیم، شیء یکسانی با `done:true` برگردانده می‌شود. ```smart header="`function* f(…)`یا`function *f(…)`؟" هر دو سینتکس صحیح هستند. @@ -98,9 +98,9 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*} ولی معمولا اولی ترجیح داده می‌شود؛ چون `*` نوع تابع و نه نام تابع را مشخص می‌کند. ```` -## generatorها iterable هستند. +## generatorها حلقه‌پذیر هستند. -همان‌طور که احتمالا با توجه به `()next` متوجه شده‌اید، generatorها [iterable](info:iterable) هستند. +همان‌طور که احتمالا با توجه به `()next` متوجه شده‌اید، generatorها [حلقه‌پذیر](info:iterable) هستند. با استفاد از `for..of` می‌توان از `value` آن‌ها استفاده کرد: @@ -122,7 +122,7 @@ for(let value of generator) { ...اما دقت کنید: مثال بالا ابتدا `1` و سپس `2` را نشان داد؛ خبری از `3` نیست! -علت این اتفاق این است که `for..of` آخرین مقدار را هنگامی که `done:true` است در نظر نمی‌گیرد. هنگام برگرداندن آخرین مقدار با `return`، بر خلاف `done:true`، `yield` است. در نتیجه برای نشان دادن تمام مقادیر باید آن‌ها را با `yield` برگردانیم: +علت این اتفاق این است که `for..of` آخرین مقدار را هنگامی که `done:true` است در نظر نمی‌گیرد. آخرین مقدار برگردانده شده با `return`، بر خلاف `yield`، حاوی `done:true` است. در نتیجه برای نشان دادن تمام مقادیر در حلقه `for..of` باید آن‌ها را با `yield` برگردانیم: ```js run function* generateSequence() { @@ -140,7 +140,7 @@ for(let value of generator) { } ``` -از آنجایی که generatorها iterable هستند، از تمام functionality آن‌ها نیز برای generatorها می‌توان استفاده کرد؛ مثل spread syntax `...`: +از آنجایی که generatorها حلقه‌پذیر هستند، از تمام functionality آن‌ها نیز برای generatorها می‌توان استفاده کرد؛ مثل spread syntax `...`: ```js run function* generateSequence() { @@ -154,9 +154,9 @@ let sequence = [0, ...generateSequence()]; alert(sequence); // 0, 1, 2, 3 ``` -در کد بالا، `()generateSequence...`، باعث می‌شود آبجکت generator که iterable هم هست به آرایه‌ای از اعداد تبدیل شود.(درباره spread syntax در چپتر [](info:rest-parameters-spread#spread-syntax) بیشتر بخوانید.) +در کد بالا، `()generateSequence...`، باعث می‌شود شیء generator که حلقه‌پذیر هم هست به آرایه‌ای از اعداد تبدیل شود.(درباره spread syntax در فصل [](info:rest-parameters-spread#spread-syntax) بیشتر بخوانید.) -## استفاده از generatorها برای iterableها +## استفاده از generatorها برای حلقه‌پذیرها در چپتر [](info:iterable) یک آبجکت `range` ساختیم که مقادیر `from..to` را باز می‌گرداند. @@ -316,11 +316,11 @@ alert(str); // 0..9A..Za..z ## yield یک خیابان دو طرفه است. -تا الان، generatorها بسیار شبیه به آبجکت‌های iterable با یک سینتکس خاص برای تولید مقادیر بودند؛ درواقع اما generatorها بسیار قدرتمندتر و انعطاف پذیرتر هستند. +تا الان، generatorها بسیار شبیه به شیءهای حلقه‌پذیر با یک سینتکس خاص برای تولید مقادیر بودند؛ درواقع اما generatorها بسیار قدرتمندتر و انعطاف پذیرتر هستند. چون `yield` یک خیابان دو طرفه است: نه تنها مقدار را به بیرون برمی‌گرداند بلکه می‌تواند مقادیر را به داخل generator بیاورد. -برای این کار باید `()generator.next` را با یک argument صدا کنیم. این argument تبدیل به مقدار برگردانده شده توسط خود yield درون generator می‌شود. +برای این کار باید `()generator.next` را با یک آرگومان صدا کنیم. این argument تبدیل به مقدار برگردانده شده توسط خود yield درون generator می‌شود. برای مثال: @@ -476,7 +476,7 @@ g.next(); // { value: undefined, done: true } - عملگر yield (فقط) در داخل generatorها وجود دارد. - کد بیرونی و generator ممکن است توسط `next/yield` با هم نتایج را رد و بدل کنند. -در جاوااسکریپت مدرن، generatorها کم استفاده می‌شوند. اما گاهی اوقات می‌توانند مفید باشند؛ رد و بدل کردن داده با کد صدا زننده، یک قابلیت منحصر بفرد است. هم‌چنین برای ساخت iterableها هم بکار می‌روند. +در جاوااسکریپت مدرن، generatorها کم استفاده می‌شوند. اما گاهی اوقات می‌توانند مفید باشند؛ رد و بدل کردن داده با کد صدا زننده، یک قابلیت منحصر بفرد است. هم‌چنین برای ساخت حلقه‌پذیرها هم بکار می‌روند. علاوه بر آن، در چپتر بعدی، async generatorها را یاد خواهیم گرفت که برای خواندن جریان‌های asynchronously generated data استفاده می‌شود؛ مثلا fetchهای paginatedشده در شبکه توسط `for await...of loop`. From 45906b199bcde1465342d17516cb232566f63afa Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Sat, 15 Jul 2023 11:24:32 +0330 Subject: [PATCH 10/11] applied review suggestions --- 1-js/12-generators-iterators/1-generators/article.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index f9d9e9df5..18c35782f 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -42,7 +42,7 @@ alert(generator); // [object Generator] متد اصلی یک شیء generator متد `()next` است. هنگامی که صدا می‌شود، بدنه تابع تا اولین `yield value` اجرا می‌شود(`value` می‌تواند حذف شود که در این صورت `undefined` است.)؛ سپس اجرای تابع متوقف می‌شود و مقدار yield شده برگرداننده می‌شود. -مقدار برگردانده شده توسط متود `next` همواره یک آبجکت با 2 پراپرتی است: +مقدار برگردانده شده توسط متود `next` همواره یک شیء با 2 پراپرتی است: - `value`: مقدار برگرداننده شده توسط `yield`. - `done`: یک Boolean است که در صورت اتمام بدنه تابع مقدار true و در غیر این صورت مقدار false دارد. @@ -158,7 +158,7 @@ alert(sequence); // 0, 1, 2, 3 ## استفاده از generatorها برای حلقه‌پذیرها -در چپتر [](info:iterable) یک آبجکت `range` ساختیم که مقادیر `from..to` را باز می‌گرداند. +در چپتر [](info:iterable) یک شیء `range` ساختیم که مقادیر `from..to` را باز می‌گرداند. کد آن به شرح زیر بود: @@ -169,15 +169,15 @@ let range = { // در ابتدا این متود را فقط یک بار صدا می‌کند for..of range [Symbol.iterator]() { - // این، آبجکت ایتریتور را باز می‌گرداند: - // فقط با آن آبجکت کار می‌کند و از آن مقادیر بعدی را می‌خواند for..of سپس + // این، شیء ایتریتور را باز می‌گرداند: + // فقط با آن شیء کار می‌کند و از آن مقادیر بعدی را می‌خواند for..of سپس return { current: this.from, last: this.to, // صدا می‌شود for..of توسط iteration در هر next() next() { - // {value: ..., done: ...}:باید مقدار را به عنوان یک آبجکت برگرداند + // {value: ..., done: ...}:باید مقدار را به عنوان یک شیء برگرداند if (this.current <= this.last) { return { done: false, value: this.current++ }; } else { From ff60ecaa183ba237624a56af8d2d73c69bc54042 Mon Sep 17 00:00:00 2001 From: Ali Varaste Pour Date: Sat, 15 Jul 2023 11:28:20 +0330 Subject: [PATCH 11/11] removed extra char --- .../1-generators/article.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md index 18c35782f..c42d9e8af 100644 --- a/1-js/12-generators-iterators/1-generators/article.md +++ b/1-js/12-generators-iterators/1-generators/article.md @@ -31,9 +31,9 @@ function* generateSequence() { //برمی‌گرداند generator یک شیء generator تابع let generator = generateSequence(); -\*!* +*!* alert(generator); // [object Generator] -\*/!* +*/!* ``` اجرای بدنه تابع هنوز شروع نشده است: @@ -57,9 +57,9 @@ function* generateSequence() { let generator = generateSequence(); -\*!* +*!* let one = generator.next(); -\*/!* +*/!* alert(JSON.stringify(one)); // {value: 1, done: false} ``` @@ -128,9 +128,9 @@ for(let value of generator) { function* generateSequence() { yield 1; yield 2; -\*!* +*!* yield 3; -\*/!* +*/!* } let generator = generateSequence(); @@ -257,7 +257,7 @@ function* generateSequence(start, end) { function* generatePasswordCodes() { -\*!* +*!* // 0..9 yield* generateSequence(48, 57); @@ -266,7 +266,7 @@ function* generatePasswordCodes() { // a..z yield* generateSequence(97, 122); -\*/!* +*/!* } @@ -290,7 +290,7 @@ function* generateSequence(start, end) { function* generateAlphaNum() { -\*!* +*!* // yield* generateSequence(48, 57); for (let i = 48; i <= 57; i++) yield i; @@ -299,7 +299,7 @@ function* generateAlphaNum() { // yield* generateSequence(97, 122); for (let i = 97; i <= 122; i++) yield i; -\*/!* +*/!* } @@ -326,10 +326,10 @@ alert(str); // 0..9A..Za..z ```js run function* gen() { -\*!* +*!* // یک سوال را به کد بیرونی برگردانید و منتظر جواب شوید let result = yield "2 + 2 = ?"; // (*) -\*/!* +*/!* alert(result); } @@ -417,9 +417,9 @@ let generator = gen(); let question = generator.next().value; -\*!* +*!* generator.throw(new Error("پاسخ در دیتابیس من نیست")); // (2) -\*/!* +*/!* ``` ارور پرتاب شده به داخل generator در خط `2` باعث exception در خط `1` دارای yield می‌شود که در مثال بالا توسط `try..catch` گرفته شده و نمایش داده می‌شود. @@ -437,13 +437,13 @@ let generator = generate(); let question = generator.next().value; -\*!* +*!* try { generator.throw(new Error("پاسخ در دیتابیس من نیست")); } catch(e) { alert(e); // ارور را نمایش می‌دهد } -\*/!* +*/!* ``` اگر ارور را catch نکنیم، در صورت وجود کد بیرونی اجرا به آن منتقل می‌شود و اگر آن‌جا نیز هندل نشده باشد، اجرای کد با خطا پایان می‌پذیرد.