ஜாவாஸ்கிரிப்ட்டின் இட்டரேட்டர் புரோட்டோகாலில் தேர்ச்சி பெறுங்கள். எந்த ஆப்ஜெக்டையும் இடரேட் செய்யக்கூடியதாக மாற்றுவது, `for...of` லூப்களைக் கட்டுப்படுத்துவது மற்றும் சிக்கலான டேட்டா கட்டமைப்புகளுக்குத் தனிப்பயன் இடரேஷன் லாஜிக்கை செயல்படுத்துவது எப்படி என்பதை நடைமுறை உதாரணங்களுடன் கற்கவும்.
ஜாவாஸ்கிரிப்டில் தனிப்பயன் இடரேஷனைத் திறத்தல்: இட்டரேட்டர் புரோட்டோகால் பற்றிய ஆழமான பார்வை
புரோகிராமிங்கில் இடரேஷன் என்பது மிகவும் அடிப்படையான கருத்துக்களில் ஒன்றாகும். பட்டியலிலுள்ள உருப்படிகளைச் செயல்படுத்துவது முதல் டேட்டா ஸ்ட்ரீம்களைப் படிப்பது வரை, நாம் தொடர்ந்து தகவல்களின் வரிசைகளுடன் வேலை செய்கிறோம். ஜாவாஸ்கிரிப்டில், for...of லூப் மற்றும் ஸ்ப்ரெட் சிண்டாக்ஸ் (...) போன்ற சக்திவாய்ந்த மற்றும் நேர்த்தியான கருவிகள் நம்மிடம் உள்ளன, அவை Arrays, Strings மற்றும் Maps போன்ற உள்ளமைக்கப்பட்ட வகைகளில் இடரேஷன் செய்வதை ஒரு தடையற்ற அனுபவமாக மாற்றுகின்றன.
ஆனால், இந்த ஆப்ஜெக்ட்களை எது இவ்வளவு சிறப்பானதாக மாற்றுகிறது என்று நீங்கள் எப்போதாவது யோசித்திருக்கிறீர்களா? ஏன் நீங்கள் for (const char of "hello") என்று எழுத முடிகிறது, ஆனால் for (const prop of {a: 1, b: 2}) என்று எழுத முடியவில்லை? இதற்கான பதில், ECMAScript தரத்தின் ஒரு சக்திவாய்ந்த, ஆனால் பெரும்பாலும் தவறாகப் புரிந்துகொள்ளப்பட்ட அம்சத்தில் உள்ளது: இட்டரேட்டர் புரோட்டோகால் (the Iterator Protocol).
இந்த புரோட்டோகால் ஜாவாஸ்கிரிப்ட்டின் உள்ளமைக்கப்பட்ட ஆப்ஜெக்ட்களுக்கான ஒரு உள் பொறிமுறை மட்டுமல்ல. இது ஒரு திறந்த தரநிலை, எந்தவொரு ஆப்ஜெக்ட்டும் ஏற்றுக்கொள்ளக்கூடிய ஒரு ஒப்பந்தம். இந்த புரோட்டோகாலை செயல்படுத்துவதன் மூலம், உங்கள் சொந்த தனிப்பயன் ஆப்ஜெக்ட்களில் எப்படி இடரேட் செய்வது என்று ஜாவாஸ்கிரிப்டுக்கு நீங்கள் கற்பிக்க முடியும், அவற்றை மொழியில் முதல்-வகுப்பு குடிமக்களாக மாற்றலாம். பைனரி ட்ரீ, லிங்க்ட் லிஸ்ட், ஒரு விளையாட்டின் முறை வரிசை அல்லது நிகழ்வுகளின் காலவரிசை என எதுவாக இருந்தாலும், உங்கள் தனிப்பயன் டேட்டா கட்டமைப்புகளுக்கு for...of இன் அதே தொடரியல் நேர்த்தியை நீங்கள் திறக்கலாம்.
இந்த விரிவான வழிகாட்டியில், நாம் இட்டரேட்டர் புரோட்டோகாலை எளிமையாக விளக்குவோம். அதன் முக்கிய கூறுகளை உடைத்து, புதிதாகத் தனிப்பயன் இட்டரேட்டர்களை உருவாக்குவது பற்றி படிப்படியாகப் பார்ப்போம், எல்லையற்ற வரிசைகள் போன்ற மேம்பட்ட பயன்பாட்டு நிகழ்வுகளை ஆராய்வோம், இறுதியாக, ஜெனரேட்டர் ஃபங்ஷன்களைப் பயன்படுத்தி நவீன, எளிமைப்படுத்தப்பட்ட அணுகுமுறையைக் கண்டுபிடிப்போம். இறுதியில், இடரேஷன் எப்படி உள்ளுக்குள் செயல்படுகிறது என்பதைப் புரிந்துகொள்வது மட்டுமல்லாமல், மேலும் வெளிப்படையான, மீண்டும் பயன்படுத்தக்கூடிய மற்றும் இயல்பான ஜாவாஸ்கிரிப்ட் குறியீட்டை எழுதவும் நீங்கள் அதிகாரம் பெறுவீர்கள்.
இடரேஷனின் மையம்: ஜாவாஸ்கிரிப்ட் இட்டரேட்டர் புரோட்டோகால் என்றால் என்ன?
முதலில், "இட்டரேட்டர் புரோட்டோகால்" என்பது நீங்கள் நீட்டிக்கும் ஒரு ஒற்றை கிளாஸ் அல்லது நீங்கள் அழைக்கும் ஒரு குறிப்பிட்ட ஃபங்ஷன் அல்ல என்பதைப் புரிந்துகொள்வது முக்கியம். இது ஒரு ஆப்ஜெக்ட் "இடரேபில்" ஆகக் கருதப்படவும், ஒரு "இட்டரேட்டரை" உருவாக்கவும் பின்பற்ற வேண்டிய விதிகள் அல்லது மரபுகளின் தொகுப்பாகும். இதை ஒரு ஒப்பந்தமாக நினைப்பது சிறந்தது. உங்கள் ஆப்ஜெக்ட் இந்த ஒப்பந்தத்தில் கையெழுத்திட்டால், ஜாவாஸ்கிரிப்ட் இன்ஜின் அதன் மீது எப்படி லூப் செய்வது என்பதைத் தெரிந்து கொள்வதாக உறுதியளிக்கிறது.
இந்த ஒப்பந்தம் இரண்டு தனித்தனி பகுதிகளாகப் பிரிக்கப்பட்டுள்ளது:
- இடரேபில் புரோட்டோகால் (The Iterable Protocol): இது ஒரு ஆப்ஜெக்ட் முதலில் இடரேட் செய்யக்கூடியதா என்பதைத் தீர்மானிக்கிறது.
- இட்டரேட்டர் புரோட்டோகால் (The Iterator Protocol): இது ஆப்ஜெக்ட் எப்படி ஒரு நேரத்தில் ஒரு மதிப்பாக இடரேட் செய்யப்படும் என்பதன் இயக்கவியலை வரையறுக்கிறது.
இந்த ஒப்பந்தத்தின் ஒவ்வொரு பகுதியையும் விரிவாக ஆராய்வோம்.
ஒப்பந்தத்தின் முதல் பாதி: இடரேபில் புரோட்டோகால்
இடரேபில் புரோட்டோகால் ஆச்சரியப்படும் வகையில் எளிமையானது. இதற்கு ஒரே ஒரு தேவை மட்டுமே உள்ளது:
ஒரு ஆப்ஜெக்ட் இடரேபில் (iterable) ஆகக் கருதப்படுகிறது, அது ஒரு இட்டரேட்டரைப் பெறுவதற்கான ஒரு மெத்தடை வழங்கும் ஒரு குறிப்பிட்ட, நன்கு அறியப்பட்ட ப்ராப்பர்ட்டியைக் கொண்டிருந்தால். இந்த நன்கு அறியப்பட்ட ப்ராப்பர்ட்டி Symbol.iterator ஐப் பயன்படுத்தி அணுகப்படுகிறது.
எனவே, ஒரு ஆப்ஜெக்ட் இடரேபில் ஆக இருக்க, அது [Symbol.iterator] என்ற கீ வழியாக அணுகக்கூடிய ஒரு மெத்தடைக் கொண்டிருக்க வேண்டும். இந்த மெத்தட் அழைக்கப்படும்போது, அது ஒரு இட்டரேட்டர் ஆப்ஜெக்டைத் திரும்பத் தர வேண்டும் (அதை நாம் அடுத்த பகுதியில் பார்ப்போம்).
நீங்கள் கேட்கலாம், "Symbol என்றால் என்ன, ஏன் 'iterator' போன்ற ஒரு ஸ்டிரிங் பெயரைப் பயன்படுத்தக்கூடாது?" ஒரு Symbol என்பது ES6 இல் அறிமுகப்படுத்தப்பட்ட ஒரு தனித்துவமான மற்றும் மாற்ற முடியாத ப்ரிமிடிவ் டேட்டா வகை. அதன் முக்கிய நோக்கம் ஆப்ஜெக்ட் ப்ராப்பர்ட்டிகளுக்கான ஒரு தனித்துவமான கீயாகச் செயல்படுவதாகும், இது தற்செயலான பெயர் மோதல்களைத் தடுக்கிறது. புரோட்டோகால் 'iterator' போன்ற ஒரு எளிய ஸ்டிரிங்கைப் பயன்படுத்தியிருந்தால், உங்கள் சொந்த குறியீடு வேறு நோக்கத்திற்காக அதே பெயரில் ஒரு ப்ராப்பர்ட்டியை வரையறுத்திருக்கலாம், இது கணிக்க முடியாத பிழைகளுக்கு வழிவகுக்கும். Symbol.iterator ஐப் பயன்படுத்துவதன் மூலம், மொழி விவரக்குறிப்பு மற்ற குறியீடுகளுடன் மோதாத ஒரு தனித்துவமான, தரப்படுத்தப்பட்ட கீயை உறுதி செய்கிறது.
இதை உள்ளமைக்கப்பட்ட இடரேபில்களில் நாம் எளிதாகச் சரிபார்க்கலாம்:
const anArray = [1, 2, 3];
const aString = "global";
const aMap = new Map();
console.log(typeof anArray[Symbol.iterator]); // "function"
console.log(typeof aString[Symbol.iterator]); // "function"
console.log(typeof aMap[Symbol.iterator]); // "function"
// A plain object is not iterable by default
const anObject = { a: 1, b: 2 };
console.log(typeof anObject[Symbol.iterator]); // "undefined"
ஒப்பந்தத்தின் இரண்டாம் பாதி: இட்டரேட்டர் புரோட்டோகால்
ஒரு ஆப்ஜெக்ட் [Symbol.iterator]() மெத்தடை வழங்குவதன் மூலம் அது இடரேபில் என்று நிரூபித்தவுடன், கவனம் அந்த மெத்தட் திரும்பத் தரும் ஆப்ஜெக்ட்டிற்கு மாறுகிறது: அதுதான் இட்டரேட்டர். இட்டரேட்டர் தான் உண்மையான வேலைக்காரன்; அதுதான் இடரேஷன் செயல்முறையை நிர்வகித்து மதிப்புகளின் வரிசையை உருவாக்குகிறது.
இட்டரேட்டர் புரோட்டோகாலும் மிகவும் நேரடியானது. இதற்கு ஒரே ஒரு தேவை மட்டுமே உள்ளது:
ஒரு ஆப்ஜெக்ட் இட்டரேட்டர் (iterator) ஆகும், அது next() என்ற பெயரில் ஒரு மெத்தடைக் கொண்டிருந்தால். இந்த next() மெத்தட், அழைக்கப்படும்போது, இரண்டு குறிப்பிட்ட ப்ராப்பர்ட்டிகளுடன் ஒரு ஆப்ஜெக்டைத் திரும்பத் தர வேண்டும்:
done(boolean): இந்த ப்ராப்பர்ட்டி இடரேஷனின் நிலையைக் குறிக்கிறது. வரிசையில் இன்னும் மதிப்புகள் வரவிருந்தால் அதுfalseஆக இருக்கும். இடரேஷன் முடிந்தவுடன் அதுtrueஆகிவிடும்.value(any type): இந்த ப்ராப்பர்ட்டி வரிசையில் உள்ள தற்போதைய மதிப்பைக் கொண்டுள்ளது.donetrueஆக இருக்கும்போது,valueப்ராப்பர்ட்டி விருப்பத்திற்குரியது மற்றும் பொதுவாகundefinedஐக் கொண்டிருக்கும்.
இதைச் செயல்பாட்டில் காண, எந்தவொரு இடரேபில் ஆப்ஜெக்ட்டிலிருந்தும் முற்றிலும் பிரிக்கப்பட்ட, கைமுறையாக உருவாக்கப்பட்ட ஒரு இட்டரேட்டரைப் பார்ப்போம். இந்த இட்டரேட்டர் 1 முதல் 3 வரை எண்ணும்.
const manualCounterIterator = {
count: 1,
next: function() {
if (this.count <= 3) {
return { value: this.count++, done: false };
} else {
return { value: undefined, done: true };
}
}
};
// We call next() repeatedly to get each value
console.log(manualCounterIterator.next()); // { value: 1, done: false }
console.log(manualCounterIterator.next()); // { value: 2, done: false }
console.log(manualCounterIterator.next()); // { value: 3, done: false }
console.log(manualCounterIterator.next()); // { value: undefined, done: true }
console.log(manualCounterIterator.next()); // { value: undefined, done: true } - It stays done
இது ஒவ்வொரு for...of லூப்பையும் இயக்கும் அடிப்படை இயக்கவியல் ஆகும். நீங்கள் for (const item of iterable) என்று எழுதும்போது, ஜாவாஸ்கிரிப்ட் இன்ஜின் திரைக்குப் பின்னால் பின்வருவனவற்றைச் செய்கிறது:
- அது ஒரு இட்டரேட்டரைப் பெற
iterableஆப்ஜெக்ட்டில்[Symbol.iterator]()மெத்தடை அழைக்கிறது. - பின்னர் அது அந்த இட்டரேட்டரில்
next()மெத்தடை மீண்டும் மீண்டும் அழைக்கிறது. donefalseஆக இருக்கும் ஒவ்வொரு திரும்பிய ஆப்ஜெக்ட்டிற்கும், அதுvalueஐ உங்கள் லூப் மாறிக்கு (item) ஒதுக்கி, லூப் பாடியை இயக்குகிறது.next()donetrueஆக இருக்கும் ஒரு ஆப்ஜெக்டைத் திரும்பத் தரும்போது, லூப் முடிவடைகிறது.
புதிதாக உருவாக்குதல்: தனிப்பயன் இடரேஷனுக்கான ஒரு நடைமுறை வழிகாட்டி
இப்போது நாம் கோட்பாட்டைப் புரிந்துகொண்டோம், அதை நடைமுறைப்படுத்துவோம். நாம் Timeline என்ற ஒரு தனிப்பயன் கிளாஸை உருவாக்குவோம். இந்த கிளாஸ் வரலாற்று நிகழ்வுகளின் தொகுப்பை நிர்வகிக்கும், மேலும் நமது இலக்கு அதை நேரடியாக இடரேட் செய்யக்கூடியதாக மாற்றுவது, நிகழ்வுகளை காலவரிசைப்படி லூப் செய்ய அனுமதிப்பதாகும்.
பயன்பாட்டு நிகழ்வு: ஒரு `Timeline` கிளாஸ்
நமது Timeline கிளாஸ் நிகழ்வுகளைச் சேமிக்கும், ஒவ்வொன்றும் ஒரு year மற்றும் ஒரு description கொண்ட ஒரு ஆப்ஜெக்ட்டாக இருக்கும். இந்த நிகழ்வுகளை, ஆண்டு வாரியாக வரிசைப்படுத்தி, ஒரு for...of லூப்பைப் பயன்படுத்தி இடரேட் செய்ய நாம் விரும்புகிறோம்.
class Timeline {
constructor() {
this.events = [];
}
addEvent(year, description) {
this.events.push({ year, description });
}
}
const myTimeline = new Timeline();
myTimeline.addEvent(1995, "JavaScript is created");
myTimeline.addEvent(2009, "Node.js is introduced");
myTimeline.addEvent(1997, "ECMAScript standard is first published");
myTimeline.addEvent(2015, "ES6 (ECMAScript 2015) is released");
// Goal: Make the following code work
// for (const event of myTimeline) {
// console.log(`${event.year}: ${event.description}`);
// }
படிப்படியான செயலாக்கம்
நமது இலக்கை அடைய, நாம் இட்டரேட்டர் புரோட்டோகாலை செயல்படுத்த வேண்டும். இதன் பொருள், நமது Timeline கிளாஸில் [Symbol.iterator]() மெத்தடைச் சேர்ப்பது.
இந்த மெத்தட் ஒரு புதிய ஆப்ஜெக்ட்டைத் திரும்பத் தர வேண்டும்—அதுதான் இட்டரேட்டர்—அது next() மெத்தடைக் கொண்டிருக்கும் மற்றும் இடரேஷனின் நிலையை (எ.கா., நாம் தற்போது எந்த நிகழ்வில் இருக்கிறோம்) நிர்வகிக்கும். இடரேஷன் நிலை இடரேபில் ஆப்ஜெக்ட்டில் இல்லாமல், இட்டரேட்டரில் இருக்க வேண்டும் என்பது ஒரு முக்கியமான வடிவமைப்பு கொள்கையாகும். இது ஒரே நேரத்தில் ஒரே டைம்லைனில் பல, சுதந்திரமான இடரேஷன்களை அனுமதிக்கிறது.
class Timeline {
constructor() {
this.events = [];
}
addEvent(year, description) {
// We'll add a simple check to ensure data integrity
if (typeof year !== 'number' || typeof description !== 'string') {
throw new Error("Invalid event data");
}
this.events.push({ year, description });
}
// Step 1: Implement the Iterable Protocol
[Symbol.iterator]() {
// Sort the events chronologically for iteration.
// We create a copy to not mutate the original array's order.
const sortedEvents = [...this.events].sort((a, b) => a.year - b.year);
let currentIndex = 0;
// Step 2: Return the iterator object
return {
// Step 3: Implement the Iterator Protocol with the next() method
next: () => { // Using an arrow function to capture `sortedEvents` and `currentIndex`
if (currentIndex < sortedEvents.length) {
// There are more events to iterate over
const currentEvent = sortedEvents[currentIndex];
currentIndex++;
return { value: currentEvent, done: false };
} else {
// We have reached the end of the events
return { value: undefined, done: true };
}
}
};
}
}
மாயாஜாலத்தைக் காணுதல்: நமது தனிப்பயன் இடரேபிலைப் பயன்படுத்துதல்
புரோட்டோகால் சரியாகச் செயல்படுத்தப்பட்டதால், நமது Timeline ஆப்ஜெக்ட் இப்போது ஒரு முழுமையான இடரேபில் ஆகும். இது ஜாவாஸ்கிரிப்ட்டின் இடரேஷன் அடிப்படையிலான மொழி அம்சங்களுடன் தடையின்றி ஒருங்கிணைக்கிறது. அதைச் செயல்பாட்டில் பார்ப்போம்.
const myTimeline = new Timeline();
myTimeline.addEvent(1995, "JavaScript is created");
myTimeline.addEvent(2009, "Node.js is introduced");
myTimeline.addEvent(1997, "ECMAScript standard is first published");
myTimeline.addEvent(2015, "ES6 (ECMAScript 2015) is released");
console.log("--- Using for...of loop ---");
for (const event of myTimeline) {
console.log(`${event.year}: ${event.description}`);
}
// Output:
// 1995: JavaScript is created
// 1997: ECMAScript standard is first published
// 2009: Node.js is introduced
// 2015: ES6 (ECMAScript 2015) is released
console.log("\n--- Using spread syntax ---");
const eventsArray = [...myTimeline];
console.log(eventsArray);
// Output: An array of the event objects, sorted by year
console.log("\n--- Using Array.from() ---");
const eventsFrom = Array.from(myTimeline);
console.log(eventsFrom);
// Output: An array of the event objects, sorted by year
console.log("\n--- Using destructuring assignment ---");
const [firstEvent, secondEvent] = myTimeline;
console.log(firstEvent);
// Output: { year: 1995, description: 'JavaScript is created' }
console.log(secondEvent);
// Output: { year: 1997, description: 'ECMAScript standard is first published' }
இதுதான் புரோட்டோகாலின் உண்மையான சக்தி. ஒரு நிலையான ஒப்பந்தத்தைப் பின்பற்றுவதன் மூலம், நமது தனிப்பயன் ஆப்ஜெக்ட்டை, எந்தவொரு கூடுதல் வேலையும் இல்லாமல், ஏற்கனவே உள்ள மற்றும் எதிர்கால ஜாவாஸ்கிரிப்ட் அம்சங்களின் ஒரு பெரிய வரிசையுடன் இணக்கமானதாக மாற்றியுள்ளோம்.
உங்கள் இடரேஷன் திறன்களை மேம்படுத்துதல்
இப்போது நீங்கள் அடிப்படைகளில் தேர்ச்சி பெற்றுவிட்டீர்கள், உங்களுக்கு இன்னும் அதிக கட்டுப்பாடு மற்றும் நெகிழ்வுத்தன்மையை வழங்கும் சில மேம்பட்ட கருத்துக்களை ஆராய்வோம்.
நிலை மற்றும் சுதந்திரமான இட்டரேட்டர்களின் முக்கியத்துவம்
நமது Timeline எடுத்துக்காட்டில், இடரேஷனின் நிலையை (currentIndex மற்றும் sortedEvents நகல்) [Symbol.iterator]() ஆல் திரும்பத் தரப்பட்ட இட்டரேட்டர் ஆப்ஜெக்ட்டிற்குள் வைப்பதில் நாம் மிகவும் கவனமாக இருந்தோம். இது ஏன் இவ்வளவு முக்கியம்? ஏனென்றால், ஒவ்வொரு முறையும் நாம் ஒரு இடரேஷனைத் தொடங்கும்போது, நமக்கு ஒரு *புதிய, சுதந்திரமான இட்டரேட்டர்* கிடைப்பதை இது உறுதி செய்கிறது.
இது பல நுகர்வோர்கள் ஒருவருக்கொருவர் தலையிடாமல் ஒரே இடரேபில் ஆப்ஜெக்ட்டில் இடரேட் செய்ய அனுமதிக்கிறது. currentIndex என்பது Timeline இன்ஸ்டன்ஸின் ஒரு ப்ராப்பர்ட்டியாக இருந்திருந்தால் கற்பனை செய்து பாருங்கள்—அது குழப்பமாக இருந்திருக்கும்!
const sharedTimeline = new Timeline();
sharedTimeline.addEvent(1, 'Event A');
sharedTimeline.addEvent(2, 'Event B');
sharedTimeline.addEvent(3, 'Event C');
const iterator1 = sharedTimeline[Symbol.iterator]();
const iterator2 = sharedTimeline[Symbol.iterator]();
console.log(iterator1.next().value); // { year: 1, description: 'Event A' }
console.log(iterator2.next().value); // { year: 1, description: 'Event A' } (Starts its own iteration)
console.log(iterator1.next().value); // { year: 2, description: 'Event B' } (Unaffected by iterator2)
முடிவிலிக்குச் செல்லுதல்: முடிவற்ற வரிசைகளை உருவாக்குதல்
இட்டரேட்டர் புரோட்டோகால் ஒரு இடரேஷன் எப்போதாவது முடிவடைய வேண்டும் என்று கோரவில்லை. done ப்ராப்பர்ட்டி வெறுமனே என்றென்றும் false ஆக இருக்கலாம். இது தனித்துவமான ஐடிகளை உருவாக்குதல், சீரற்ற டேட்டாவின் ஸ்ட்ரீம்களை உருவாக்குதல் அல்லது கணித வரிசைகளை மாடலிங் செய்தல் போன்ற பணிகளுக்கு நம்பமுடியாத அளவிற்கு பயனுள்ளதாக இருக்கும் எல்லையற்ற வரிசைகளை மாதிரியாகக் கொள்ள அனுமதிக்கிறது.
ஃபைபோனச்சி வரிசையை காலவரையின்றி உருவாக்கும் ஒரு இட்டரேட்டரை உருவாக்குவோம்.
const fibonacciSequence = {
[Symbol.iterator]() {
let a = 0, b = 1;
return {
next() {
[a, b] = [b, a + b];
return { value: a, done: false };
}
};
}
};
// We can't use spread syntax or Array.from() here, as that would create an infinite loop and crash!
// const fibArray = [...fibonacciSequence]; // DANGER: Infinite loop!
// We must consume it carefully, providing our own termination condition.
console.log("First 10 Fibonacci numbers:");
let count = 0;
for (const number of fibonacciSequence) {
console.log(number);
count++;
if (count >= 10) {
break; // It's crucial to break out of the loop!
}
}
விருப்பத்தேர்வு இட்டரேட்டர் மெத்தட்கள்: `return()`
மேலும் மேம்பட்ட சூழ்நிலைகளுக்கு, குறிப்பாக வள மேலாண்மை (கோப்பு கைப்பிடிகள் அல்லது நெட்வொர்க் இணைப்புகள் போன்றவை) சம்பந்தப்பட்டவற்றிற்கு, ஒரு இட்டரேட்டர் விருப்பமாக ஒரு return() மெத்தடைக் கொண்டிருக்கலாம். இடரேஷன் முன்கூட்டியே நிறுத்தப்பட்டால், இந்த மெத்தட் ஜாவாஸ்கிரிப்ட் இன்ஜினால் தானாகவே அழைக்கப்படும். இது ஒரு `break`, `return`, `throw` அறிக்கை ஒரு `for...of` லூப் முடிவடைவதற்கு முன்பு வெளியேறினால் நிகழலாம்.
இது உங்கள் இட்டரேட்டருக்கு சுத்தப்படுத்தும் பணிகளைச் செய்ய ஒரு வாய்ப்பை வழங்குகிறது.
function createResourceIterator() {
let resourceIsOpen = true;
console.log("Resource opened.");
let i = 0;
return {
next() {
if (i < 3) {
return { value: ++i, done: false };
} else {
console.log("Iterator finished naturally.");
resourceIsOpen = false;
console.log("Resource closed.");
return { done: true };
}
},
return() {
if (resourceIsOpen) {
console.log("Iterator terminated early. Closing resource.");
resourceIsOpen = false;
}
return { done: true }; // Must return a valid iterator result
}
};
}
console.log("--- Early exit scenario ---");
const resourceIterable = { [Symbol.iterator]: createResourceIterator };
for (const value of resourceIterable) {
console.log(`Processing value: ${value}`);
if (value > 1) {
break; // This will trigger the return() method
}
}
குறிப்பு: பிழைப் பரவலுக்காக ஒரு throw() மெத்தடும் உள்ளது, ஆனால் அது முதன்மையாக ஜெனரேட்டர் ஃபங்ஷன்களின் சூழலில் பயன்படுத்தப்படுகிறது, அதை நாம் அடுத்து விவாதிப்போம்.
நவீன அணுகுமுறை: ஜெனரேட்டர் ஃபங்ஷன்களுடன் எளிமையாக்குதல்
நாம் பார்த்தது போல், இட்டரேட்டர் புரோட்டோகாலை கைமுறையாகச் செயல்படுத்துவதற்கு இட்டரேட்டர் ஆப்ஜெக்டை உருவாக்க மற்றும் { value, done } ஆப்ஜெக்ட்களைத் திரும்பத் தர கவனமான நிலை மேலாண்மை மற்றும் பாய்லர்பிளேட் குறியீடு தேவைப்படுகிறது. இந்த செயல்முறையைப் புரிந்துகொள்வது அவசியமானாலும், ES6 ஒரு மிகவும் நேர்த்தியான தீர்வை அறிமுகப்படுத்தியது: ஜெனரேட்டர் ஃபங்ஷன்கள் (generator functions).
ஒரு ஜெனரேட்டர் ஃபங்ஷன் என்பது ஒரு சிறப்பு வகையான ஃபங்ஷன் ஆகும், அதை இடைநிறுத்தி மீண்டும் இயக்க முடியும், இது காலப்போக்கில் மதிப்புகளின் வரிசையை உருவாக்க அனுமதிக்கிறது. இது இட்டரேட்டர்களை உருவாக்குவதை பெருமளவில் எளிதாக்குகிறது.
முக்கிய தொடரியல்:
function*: நட்சத்திரக்குறி ஒரு ஃபங்ஷனை ஒரு ஜெனரேட்டராக அறிவிக்கிறது.yield: இந்த கீவேர்ட் ஜெனரேட்டரின் செயல்பாட்டை இடைநிறுத்தி ஒரு மதிப்பை "yields" (வழங்குகிறது). இட்டரேட்டரின்next()மெத்தட் மீண்டும் அழைக்கப்படும்போது, ஃபங்ஷன் அது விட்ட இடத்திலிருந்து மீண்டும் தொடங்குகிறது.
நீங்கள் ஒரு ஜெனரேட்டர் ஃபங்ஷனை அழைக்கும்போது, அது உடனடியாக அதன் பாடியை இயக்காது. அதற்கு பதிலாக, அது புரோட்டோகாலுடன் முழுமையாக இணக்கமான ஒரு இட்டரேட்டர் ஆப்ஜெக்டைத் திரும்பத் தருகிறது. ஜாவாஸ்கிரிப்ட் இன்ஜின் ஸ்டேட் மெஷின், next() மெத்தட் மற்றும் { value, done } ஆப்ஜெக்ட்களை உருவாக்குவதை உங்களுக்காகத் தானாகவே கையாளுகிறது.
நமது `Timeline` எடுத்துக்காட்டை மறுசீரமைத்தல்
ஜெனரேட்டர் ஃபங்ஷன்கள் நமது Timeline செயலாக்கத்தை எவ்வளவு வியத்தகு முறையில் எளிதாக்க முடியும் என்று பார்ப்போம். லாஜிக் அப்படியே உள்ளது, ஆனால் குறியீடு மிகவும் படிக்கக்கூடியதாகவும், பிழை ஏற்பட வாய்ப்பு குறைந்ததாகவும் மாறுகிறது.
class Timeline {
constructor() {
this.events = [];
}
addEvent(year, description) {
this.events.push({ year, description });
}
// Refactored with a generator function!
*[Symbol.iterator]() { // The asterisk makes this a generator method
// Create a sorted copy
const sortedEvents = [...this.events].sort((a, b) => a.year - b.year);
// Loop through the sorted events
for (const event of sortedEvents) {
// yield pauses the function and returns the value
yield event;
}
// When the function finishes, the iterator is automatically marked as 'done'
}
}
// Usage is exactly the same, but the implementation is cleaner!
const myGenTimeline = new Timeline();
myGenTimeline.addEvent(2002, "The Euro currency is introduced");
myGenTimeline.addEvent(1998, "Google is founded");
for (const event of myGenTimeline) {
console.log(`${event.year}: ${event.description}`);
}
வித்தியாசத்தைப் பாருங்கள்! இட்டரேட்டர் ஆப்ஜெக்ட்டின் சிக்கலான கைமுறை உருவாக்கம் போய்விட்டது. நிலை (நாம் எந்த நிகழ்வில் இருக்கிறோம்) ஜெனரேட்டர் ஃபங்ஷனின் இடைநிறுத்தப்பட்ட நிலையால் மறைமுகமாக நிர்வகிக்கப்படுகிறது. இது இட்டரேட்டர் புரோட்டோகாலைச் செயல்படுத்த நவீன, விரும்பத்தக்க வழியாகும்.
`yield*` இன் சக்தி
ஜெனரேட்டர் ஃபங்ஷன்களுக்கு மற்றொரு சூப்பர் பவர் உள்ளது: yield* (yield star). இது ஒரு ஜெனரேட்டர் இடரேஷன் செயல்முறையை மற்றொரு இடரேபில் ஆப்ஜெக்ட்டிற்கு ஒப்படைக்க அனுமதிக்கிறது. இது பல மூலங்களிலிருந்து இட்டரேட்டர்களை உருவாக்குவதற்கான நம்பமுடியாத சக்திவாய்ந்த கருவியாகும்.
நம்மிடம் பல Timeline ஆப்ஜெக்ட்களைக் கொண்ட ஒரு `Project` கிளாஸ் இருப்பதாக கற்பனை செய்து பாருங்கள் (எ.கா., ஒன்று வடிவமைப்புக்கு, ஒன்று உருவாக்கத்திற்கு). நாம் `Project` ஐயே இடரேட் செய்யக்கூடியதாக மாற்றலாம், மேலும் அது அதன் அனைத்து டைம்லைன்களிலிருந்தும் அனைத்து நிகழ்வுகளையும் வரிசையாகத் தடையின்றி இடரேட் செய்யும்.
class Project {
constructor(name) {
this.name = name;
this.designTimeline = new Timeline();
this.devTimeline = new Timeline();
}
*[Symbol.iterator]() {
console.log(`Iterating through events for project: ${this.name}`);
console.log("--- Design Events ---");
yield* this.designTimeline; // Delegate to the design timeline's iterator
console.log("--- Development Events ---");
yield* this.devTimeline; // Then delegate to the dev timeline's iterator
}
}
const websiteProject = new Project("Global Website Relaunch");
websiteProject.designTimeline.addEvent(2023, "Initial wireframes created");
websiteProject.designTimeline.addEvent(2024, "Final brand guide approved");
websiteProject.devTimeline.addEvent(2024, "Backend API developed");
websiteProject.devTimeline.addEvent(2025, "Frontend deployment");
for (const event of websiteProject) {
console.log(` - ${event.year}: ${event.description}`);
}
பெரிய படம்: ஏன் இட்டரேட்டர் புரோட்டோகால் நவீன ஜாவாஸ்கிரிப்ட்டின் ஒரு மூலக்கல் ஆகும்
இட்டரேட்டர் புரோட்டோகால் ஒரு கல்வி சார்ந்த ஆர்வம் அல்லது நூலக ஆசிரியர்களுக்கான ஒரு அம்சம் என்பதை விட மிக அதிகம். இது இயங்குதன்மையை மற்றும் நேர்த்தியான குறியீட்டை ஊக்குவிக்கும் ஒரு அடிப்படை வடிவமைப்பு முறை. இதை ஒரு உலகளாவிய அடாப்டராக நினைத்துப் பாருங்கள். உங்கள் ஆப்ஜெக்ட்களை இந்த தரத்திற்கு இணங்க வைப்பதன் மூலம், எந்தவொரு டேட்டா வரிசையுடனும் வேலை செய்ய வடிவமைக்கப்பட்ட மொழி அம்சங்களின் ஒரு பெரிய சுற்றுச்சூழல் அமைப்பில் அவற்றை இணைக்கிறீர்கள்.
இடரேபில் புரோட்டோகாலைச் சார்ந்திருக்கும் அம்சங்களின் பட்டியல் விரிவானது மற்றும் வளர்ந்து வருகிறது:
- லூப்கள்:
for...of - அரே உருவாக்கம்/இணைப்பு: ஸ்ப்ரெட் சிண்டாக்ஸ் (
[...iterable]) மற்றும்Array.from(iterable) - டேட்டா கட்டமைப்புகள்:
new Map(iterable),new Set(iterable),new WeakMap(iterable), மற்றும்new WeakSet(iterable)ஆகியவற்றின் கன்ஸ்ட்ரக்டர்கள் அனைத்தும் இடரேபில்களை ஏற்றுக்கொள்கின்றன. - சமகாலமில்லா செயல்பாடுகள்:
Promise.all(iterable),Promise.race(iterable), மற்றும்Promise.any(iterable)ஆகியவை ப்ராமிஸ்களின் ஒரு இடரேபில் மீது செயல்படுகின்றன. - டீஸ்ட்ரக்சரிங்: நீங்கள் எந்த இடரேபிலுடனும் டீஸ்ட்ரக்சரிங் அசைன்மென்டைப் பயன்படுத்தலாம்:
const [first, second] = myIterable; - புதிய API-கள்: உரை பிரிப்பிற்கான
Intl.Segmenterபோன்ற நவீன API-களும் இடரேபில் ஆப்ஜெக்ட்களைத் திரும்பத் தருகின்றன.
உங்கள் தனிப்பயன் டேட்டா கட்டமைப்புகளை இடரேபில் ஆக மாற்றும்போது, நீங்கள் ஒரு `for...of` லூப்பை மட்டும் இயக்குவதில்லை; நீங்கள் அவற்றை இந்த முழு சக்திவாய்ந்த கருவிகளின் தொகுப்புடன் இணக்கமானதாக மாற்றுகிறீர்கள், உங்கள் குறியீடு முன்னோக்கி-இணக்கமானது மற்றும் மற்ற டெவலப்பர்கள் பயன்படுத்த மற்றும் புரிந்துகொள்ள எளிதானது என்பதை உறுதிசெய்கிறீர்கள்.
முடிவுரை: இடரேஷனில் உங்கள் அடுத்த படிகள்
நாம் இடரேபில் மற்றும் இட்டரேட்டர் புரோட்டோகால்களின் அடிப்படைக் விதிகளிலிருந்து நமது சொந்த தனிப்பயன் இட்டரேட்டர்களை உருவாக்குவது வரை, இறுதியாக ஜெனரேட்டர் ஃபங்ஷன்களின் சுத்தமான, நவீன தொடரியல் வரை பயணம் செய்துள்ளோம். நீங்கள் கற்பனை செய்யக்கூடிய எந்தவொரு டேட்டா கட்டமைப்பையும் எப்படி கடந்து செல்வது என்று ஜாவாஸ்கிரிப்டுக்குக் கற்பிக்கும் அறிவு இப்போது உங்களிடம் உள்ளது.
இந்த புரோட்டோகாலில் தேர்ச்சி பெறுவது ஒரு ஜாவாஸ்கிரிப்ட் டெவலப்பராக உங்கள் பயணத்தில் ஒரு குறிப்பிடத்தக்க படியாகும். இது உங்களை மொழியின் அம்சங்களின் நுகர்வோராக இருந்து, உங்கள் குறிப்பிட்ட தேவைகளுக்குப் பொருந்தும் வகையில் மொழியின் முக்கிய திறன்களை நீட்டிக்கக்கூடிய ஒரு படைப்பாளராக மாற்றுகிறது.
உலகளாவிய டெவலப்பர்களுக்கான செயல் நுண்ணறிவுகள்
- உங்கள் குறியீட்டைத் தணிக்கை செய்யுங்கள்: உங்கள் தற்போதைய ப்ராஜெக்ட்களில் ஒரு டேட்டா வரிசையைக் குறிக்கும் ஆப்ஜெக்ட்களைத் தேடுங்கள். நீங்கள் அவற்றை
.forEachItem()அல்லது.getItems()போன்ற தனிப்பயன், தரமற்ற மெத்தட்கள் மூலம் இடரேட் செய்கிறீர்களா? சிறந்த இயங்குதன்மைக்காக அவற்றை நிலையான இட்டரேட்டர் புரோட்டோகாலைச் செயல்படுத்த மறுசீரமைப்பதைக் கருத்தில் கொள்ளுங்கள். - சோம்பேறித்தனத்தை ஏற்றுக்கொள்ளுங்கள்: பெரிய அல்லது எல்லையற்ற டேட்டாசெட்களைக் குறிக்க இட்டரேட்டர்களையும், குறிப்பாக ஜெனரேட்டர்களையும் பயன்படுத்தவும். இது தேவைக்கேற்ப டேட்டாவைச் செயல்படுத்த உங்களை அனுமதிக்கிறது, இது நினைவகத் திறன் மற்றும் செயல்திறனில் குறிப்பிடத்தக்க மேம்பாடுகளுக்கு வழிவகுக்கிறது. உங்களுக்குத் தேவையானதை, உங்களுக்குத் தேவைப்படும்போது மட்டுமே நீங்கள் கணக்கிடுகிறீர்கள்.
- ஜெனரேட்டர்களுக்கு முன்னுரிமை கொடுங்கள்: நீங்கள் உருவாக்கும் எந்தவொரு புதிய ஆப்ஜெக்ட்டும் இடரேபில் ஆக இருக்க வேண்டுமானால், ஜெனரேட்டர் ஃபங்ஷன்களை (
function*) உங்கள் இயல்புநிலை தேர்வாக ஆக்குங்கள். அவை ஒரு கைமுறை செயலாக்கத்தை விட சுருக்கமானவை, நிலை மேலாண்மைப் பிழைகளுக்கு வாய்ப்பு குறைந்தவை மற்றும் படிக்கக்கூடியவை. - வரிசைகளில் சிந்தியுங்கள்: புரோகிராமிங் சிக்கல்களை வரிசைகளின் கண்ணோட்டத்தில் பார்க்கத் தொடங்குங்கள். ஒரு சிக்கலான வணிக செயல்முறை, ஒரு டேட்டா உருமாற்ற பைப்லைன் அல்லது ஒரு UI நிலை மாற்றம் ஆகியவற்றை படிகளின் வரிசையாக மாதிரியாகக் கொள்ள முடியுமா? அப்படியானால், ஒரு இட்டரேட்டர் அந்த வேலைக்கு சரியான, நேர்த்தியான கருவியாக இருக்கலாம்.
இட்டரேட்டர் புரோட்டோகாலை உங்கள் மேம்பாட்டுக் கருவித்தொகுப்பில் ஒருங்கிணைப்பதன் மூலம், நீங்கள் சுத்தமான, சக்திவாய்ந்த மற்றும் மிகவும் இயல்பான ஜாவாஸ்கிரிப்ட்டை எழுதுவீர்கள், அது உலகில் எங்கும் உள்ள டெவலப்பர்களால் புரிந்து கொள்ளப்பட்டு பாராட்டப்படும்.