الدوال المولدة في 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 هذه الميزة.
مصادر ومواصفات
- مسودة المعيار ECMAScript Latest Draft.
- معيار ECMAScript 2016.
- معيار ECMAScript 2015 (6th Edition).