Thắc mắc về cơ chế generator function JS

Dạ em có một generator function như sau:

function* test() {
  const foo = yield 3;
  console.log(foo);
  const bar = yield 4;
  console.log(bar);
}

const abc = test();

console.log(abc.next()); // { value: 3, done: false }
console.log(abc.next()); // { value: 4, done: false }
console.log(abc.next()); // { value: undefined, done: true }

Kết quả là:

{ value: 3, done: false }
undefined
{ value: 4, done: false }
undefined undefined
{ value: undefined, done: true }

Em có 5 thắc mắc mong được mọi người giải đáp.

:one: Tại sao function* test có 2 yield, yeild cuối cùng có value là 4 nhưng tại sao thuộc tính done vẫn là false (nghĩa là test vẫn chưa kết thúc) mà dòng console.log thứ 3 có valueundefineddone lại là true? Vậy lúc value là 4 thì con trỏ đang ở vị trí nào? trước số 4 hay sau số 4?

:two: Tại sao console.log(foo)console.log(bar) đặt sau yield nhưng bị undefined? Có nghĩa là yeild không gán giá trị cho barfoo đúng không?

:three: Em sửa lại đoạn code bằng cách truyền argument vào function next()

function* test() {
  const foo = yield 3;
  console.log(foo);
  const bar = yield 4;
  console.log(bar);
}

const abc = test();

abc.next(123);   //<====
abc.next(456);   //<====
abc.next(789);   //<====

Kết quả là:

123

456

Tại sao lúc này lại in ra được foobar?

:four: Vậy cuối cùng làm sao in được số 3 và số 4?

:five: Nguyên lý của function* trong javascript có giống với Iterator trong java như bài biết dưới đây không?

Có phải vì javascript không có class Iterator nên mới nghĩ ra function* để thay thế?

Em cảm ơn.

Em có đọc qua bài viết này nhưng vẫn không hiểu gì cả :cry:

  1. chỉ return done khi hết hàm (gặp return) hoặc gặp exception
  2. có truyền value đâu mà có giá trị?
y = yield x

thì y nhận từ cái next

console.log(abc.next()); // { value: 3, done: false }

next này rỗng thì nhận bằng gì?
3. tương tự ý (2)
4. ??? thì bỏ vô cái next 1 và 2?
5. giống. generator cơ bản là iterator ở mức ngôn ngữ lập trình

4 Likes

yield 3 không gán vào foo, yield 4 không gán vào bar à bác?


Em muốn in kiểu này được không ạ?

Screenshot 2022-06-24 195827

chứ không phải .next(3) , .next(4)

Vậy sao không gán foo = 3; luôn? :smiley:
yield là đưa ra ngoài mà.

4 Likes

Vậy chỉ có một cách duy nhất là cho yield xuất 3 ra ngoài rồi đưa trở vào trong qua .next(3) như này đúng không bạn?

function* test() {
  const foo = yield 3;
  console.log(foo);  // 3
  const bar = yield 4;
  console.log(bar);
}

const testGen = test();
const foo1 = testGen.next();
testGen.next(foo1.value);

Đây chỉ là quy ước chung của iterator protocol thôi. Iterator sẽ emit done:true object của bạn sau khi terminating value được yielded.

yield không gán giá trị khi bản thân nó yield, yield chỉ gán giá trị trong argument của function

Về nguyên tắc thì có vẻ giống, hiểu đơn giản thì nó là 1 datastructure đặc biệt hỗ trợ việc cắt nhỏ hàm và thời điểm thực thi hàm.
Lưu ý bài viết bạn dẫn không chỉ là Iterator mà là ListIterator trong Java, Iterator (protocol) trong Javascript không có previous method.

functions* là 1 expression trong JS, return 1 Generator, Generator này hỗ trợ Iterator protocol.

function* understandIterator() {
  const valueFromArgument = yield "Initial yield";
  console.log(`valueFromArgument ${valueFromArgument}`);
  const secondValueFromArgument = yield "And receive from iterator";
  console.log(`secondValueFromArgument ${secondValueFromArgument}`);
}

iter = understandIterator()
console.log(`Return from iterator ${iter.next().value}`)
console.log(`Return from iterator ${iter.next("Passing a value").value}`)

FYI: Singularity nhận hiệu đính CV miễn phí, tăng 20% lương của bạn nhờ có CV chuẩn quốc tế: https://resume.singularity.vn/

5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?