الدوال المولدة في JavaScript

من موسوعة حسوب

التصريح عن الدالة المولدة (generator function declaration) يُعرِّف دالة مولدِّةً التي تُعيد الكائن Generator. لاحظ أنَّ التصريح عن الدوال المولدة يكون عبر الكلمة المحجوزة function ويليها رمز النجمة *.

يمكن أيضًا تعريف الدوال المولِّدة عبر الدالة البانية GeneratorFunction وعبر تعابير تعريف الدوال المولدة (function* expression).

البنية العامة

function* name([param[, param[, ... param]]]) {
   statements
}

name

اسم الدالة

param

اسم الوسيط المُرَّر إلى الدالة، العدد الأقصى للوسائط التي يمكن تمريرها إلى الدالة يختلف حسب المحرِّك الذي يُفسِّر اللغة.

statements

التعابير البرمجية التي تُشكِّل جسم الدالة.

الوصف

المولِّدات هي الدوال التي يمكن الخروج منها والعودة إليها لاحقًا، وسيُحفَظ سياقها (أي ارتباطات المتغيرات) بين عمليات الدخول والخروج.

استدعاء دالة مولِّدة لن يؤدي إلى تنفيذ جسم الدالة مباشرة، وإنما سيُعاد كائن iterator للدالة، وعند استدعاء الدالة next()‎ في كائن iterator فسيُنفَّذ جسم الدالة من البداية إلى أوّل تعبير yield، الذي يُحدِّد ما هي القيمة التي سيُعيدها iterator؛ أو تعبير yield*‎ الذي يحوِّل التنفيذ إلى دالة مولِّدة أخرى.

الدالة next()‎ ستُعيد كائنًا له الخاصية value التي تحتوي على القيم المُعادة من تعبير yield وخاصية أخرى باسم done التي تُشير إذا كانت الدالة المولِّدة قد كانت آخر قيمة أعطتها (yielded) هي قيمة منطقية (Boolean).

استدعاء الدالة next()‎ مع تمرير وسيط إليها سيؤدي إلى استئناف عمل الدالة المولِّدة مع وضع التعبير الذي مُرِّر إليها مكان آخر تعبير yield الذي توقف التنفيذ عنده آخر مرة.

سيؤدي التعبير البرمجي return إلى إعادة الخاصية done عند تنفيذه في المولِّدات، وإذا أُعيدتَ قيمة مع التعبير return فستُمرَّر إلى الخاصية value؛ انتبه إلى أنَّ المولِّدات التي أعادت قيمةً لا تستطيع أن تعطي (yield) أيّة قيمة أخرى.

أمثلة

مثال بسيط

function* idMaker() {
  var index = 0;
  while (index < 3)
    yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
// ...

مثال مع استخدام yield*‎

function* anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function* generator(i) {
  yield i;
  yield* anotherGenerator(i);
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20

تمرير وسائط إلى المولِّدات

function* logGenerator() {
  console.log(0);
  console.log(1, yield);
  console.log(2, yield);
  console.log(3, yield);
}

var gen = logGenerator();

// سيبدأ أوّل استدعاء للدالة من بدايتها
// حتى الوصول إلى أوّل تعبير yield
gen.next();             // 0
gen.next('pretzel');    // 1 pretzel
gen.next('california'); // 2 california
gen.next('mayonnaise'); // 3 mayonnaise

إعادة قيمة في المولِّدات

function* yieldAndReturn() {
  yield "Y";
  return "R";
  yield "unreachable";
}

var gen = yieldAndReturn()
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }

لا يمكن إنشاء كائن من المولِّدات

لاحظ أنَّ المثال الآتي لن يعمل لعدم القدرة على إنشاء كائن من دالة مولِّدة:

function* f() {}
var obj = new f; // TypeError: f is not a constructor

دعم المتصفحات

الميزة Chrome Firefox Internet Explorer Opera Safari
الدعم الأساسي 39 26 غير مدعومة 26 10

على النقيض من متصفح IE، يدعم متصفح Edge هذه الميزة.

مصادر ومواصفات