జావాస్క్రిప్ట్ జెనరేటర్ ఫంక్షన్స్ మరియు ఇటరేటర్ ప్రోటోకాల్కు సమగ్ర మార్గదర్శి. కస్టమ్ ఇటరేటర్లను సృష్టించడం మరియు మీ జావాస్క్రిప్ట్ అప్లికేషన్లను మెరుగుపరచడం నేర్చుకోండి.
జావాస్క్రిప్ట్ జెనరేటర్ ఫంక్షన్స్: ఇటరేటర్ ప్రోటోకాల్పై పట్టు సాధించడం
జావాస్క్రిప్ట్ జెనరేటర్ ఫంక్షన్స్, ECMAScript 6 (ES6) లో ప్రవేశపెట్టబడ్డాయి, ఇవి మరింత సంక్షిప్త మరియు చదవగలిగే పద్ధతిలో ఇటరేటర్లను సృష్టించడానికి ఒక శక్తివంతమైన యంత్రాంగాన్ని అందిస్తాయి. అవి ఇటరేటర్ ప్రోటోకాల్తో సజావుగా అనుసంధానించబడతాయి, సంక్లిష్ట డేటా నిర్మాణాలను మరియు అసమకాలిక కార్యకలాపాలను సులభంగా నిర్వహించగల కస్టమ్ ఇటరేటర్లను రూపొందించడానికి మిమ్మల్ని అనుమతిస్తాయి. ఈ వ్యాసం జెనరేటర్ ఫంక్షన్స్, ఇటరేటర్ ప్రోటోకాల్ యొక్క చిక్కులను మరియు వాటి అనువర్తనాన్ని వివరించడానికి ఆచరణాత్మక ఉదాహరణలను లోతుగా పరిశీలిస్తుంది.
ఇటరేటర్ ప్రోటోకాల్ను అర్థం చేసుకోవడం
జెనరేటర్ ఫంక్షన్లలోకి వెళ్ళే ముందు, ఇటరేటర్ ప్రోటోకాల్ను అర్థం చేసుకోవడం చాలా ముఖ్యం, ఇది జావాస్క్రిప్ట్లో పునరావృతమయ్యే డేటా నిర్మాణాలకు పునాదిని ఏర్పరుస్తుంది. ఇటరేటర్ ప్రోటోకాల్ ఒక ఆబ్జెక్ట్ను ఎలా పునరావృతం చేయవచ్చో నిర్వచిస్తుంది, అంటే దాని మూలకాలను వరుసగా యాక్సెస్ చేయవచ్చు.
ఇటరబుల్ ప్రోటోకాల్
ఒక ఆబ్జెక్ట్ ఇటరబుల్ (పునరావృతం చేయగలది)గా పరిగణించబడుతుంది, అది @@iterator పద్ధతిని (Symbol.iterator) అమలు చేస్తే. ఈ పద్ధతి తప్పనిసరిగా ఒక ఇటరేటర్ ఆబ్జెక్ట్ను తిరిగి ఇవ్వాలి.
ఒక సాధారణ ఇటరబుల్ ఆబ్జెక్ట్ ఉదాహరణ:
const myIterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next() {
if (index < myIterable.data.length) {
return { value: myIterable.data[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
};
for (const item of myIterable) {
console.log(item); // Output: 1, 2, 3
}
ఇటరేటర్ ప్రోటోకాల్
ఒక ఇటరేటర్ ఆబ్జెక్ట్ తప్పనిసరిగా next() పద్ధతిని కలిగి ఉండాలి. next() పద్ధతి రెండు లక్షణాలతో కూడిన ఆబ్జెక్ట్ను తిరిగి ఇస్తుంది:
value: క్రమంలో తదుపరి విలువ.done: ఇటరేటర్ క్రమం చివరకు చేరుకుందో లేదో సూచించే బూలియన్.trueముగింపును సూచిస్తుంది;falseఅంటే ఇంకా మరిన్ని విలువలు పొందవలసి ఉందని అర్థం.
ఇటరేటర్ ప్రోటోకాల్, for...of లూప్లు మరియు స్ప్రెడ్ ఆపరేటర్ (...) వంటి అంతర్నిర్మిత జావాస్క్రిప్ట్ లక్షణాలను కస్టమ్ డేటా నిర్మాణాలతో సజావుగా పని చేయడానికి అనుమతిస్తుంది.
జెనరేటర్ ఫంక్షన్ల పరిచయం
జెనరేటర్ ఫంక్షన్లు ఇటరేటర్లను సృష్టించడానికి మరింత సొగసైన మరియు సంక్షిప్త మార్గాన్ని అందిస్తాయి. అవి function* సింటాక్స్ని ఉపయోగించి ప్రకటించబడతాయి.
జెనరేటర్ ఫంక్షన్ల సింటాక్స్
జెనరేటర్ ఫంక్షన్ యొక్క ప్రాథమిక సింటాక్స్ ఈ క్రింది విధంగా ఉంటుంది:
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const iterator = myGenerator();
console.log(iterator.next()); // Output: { value: 1, done: false }
console.log(iterator.next()); // Output: { value: 2, done: false }
console.log(iterator.next()); // Output: { value: 3, done: false }
console.log(iterator.next()); // Output: { value: undefined, done: true }
జెనరేటర్ ఫంక్షన్ల యొక్క ముఖ్య లక్షణాలు:
- అవి
functionబదులుగాfunction*తో ప్రకటించబడతాయి. - అవి ఎగ్జిక్యూషన్ను పాజ్ చేయడానికి మరియు ఒక విలువను తిరిగి ఇవ్వడానికి
yieldకీవర్డ్ను ఉపయోగిస్తాయి. - ఇటరేటర్పై
next()పిలిచిన ప్రతిసారీ, జెనరేటర్ ఫంక్షన్ తదుపరిyieldస్టేట్మెంట్ ఎదురయ్యే వరకు లేదా ఫంక్షన్ తిరిగి వచ్చే వరకు అది ఆగిపోయిన చోట నుండి ఎగ్జిక్యూషన్ను పునఃప్రారంభిస్తుంది. - జెనరేటర్ ఫంక్షన్ ఎగ్జిక్యూషన్ పూర్తి చేసినప్పుడు (చివరికి చేరుకోవడం ద్వారా లేదా
returnస్టేట్మెంట్ను ఎదుర్కోవడం ద్వారా), తిరిగి వచ్చిన ఆబ్జెక్ట్ యొక్కdoneప్రాపర్టీtrueఅవుతుంది.
జెనరేటర్ ఫంక్షన్లు ఇటరేటర్ ప్రోటోకాల్ను ఎలా అమలు చేస్తాయి
మీరు ఒక జెనరేటర్ ఫంక్షన్ను పిలిచినప్పుడు, అది వెంటనే అమలు కాదు. బదులుగా, అది ఒక ఇటరేటర్ ఆబ్జెక్ట్ను తిరిగి ఇస్తుంది. ఈ ఇటరేటర్ ఆబ్జెక్ట్ స్వయంచాలకంగా ఇటరేటర్ ప్రోటోకాల్ను అమలు చేస్తుంది. ప్రతి yield స్టేట్మెంట్ ఇటరేటర్ యొక్క next() పద్ధతి కోసం ఒక విలువను ఉత్పత్తి చేస్తుంది. జెనరేటర్ ఫంక్షన్ అంతర్గత స్థితిని నిర్వహిస్తుంది మరియు దాని పురోగతిని ట్రాక్ చేస్తుంది, కస్టమ్ ఇటరేటర్ల సృష్టిని సులభతరం చేస్తుంది.
జెనరేటర్ ఫంక్షన్ల యొక్క ఆచరణాత్మక ఉదాహరణలు
జెనరేటర్ ఫంక్షన్ల యొక్క శక్తి మరియు బహుముఖ ప్రజ్ఞను ప్రదర్శించే కొన్ని ఆచరణాత్మక ఉదాహరణలను అన్వేషిద్దాం.
1. సంఖ్యల క్రమాన్ని ఉత్పత్తి చేయడం
ఈ ఉదాహరణ ఒక నిర్దిష్ట పరిధిలో సంఖ్యల క్రమాన్ని ఉత్పత్తి చేసే జెనరేటర్ ఫంక్షన్ను ఎలా సృష్టించాలో చూపిస్తుంది.
function* numberSequence(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
const sequence = numberSequence(10, 15);
for (const num of sequence) {
console.log(num); // Output: 10, 11, 12, 13, 14, 15
}
2. ట్రీ నిర్మాణంపై పునరావృతం చేయడం
చెట్ల వంటి సంక్లిష్ట డేటా నిర్మాణాలను దాటడానికి జెనరేటర్ ఫంక్షన్లు ముఖ్యంగా ఉపయోగపడతాయి. ఈ ఉదాహరణ బైనరీ ట్రీ యొక్క నోడ్స్పై ఎలా పునరావృతం చేయాలో చూపిస్తుంది.
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
function* treeTraversal(node) {
if (node) {
yield* treeTraversal(node.left); // Recursive call for left subtree
yield node.value; // Yield the current node's value
yield* treeTraversal(node.right); // Recursive call for right subtree
}
}
// Create a sample binary tree
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
// Iterate over the tree using the generator function
const treeIterator = treeTraversal(root);
for (const value of treeIterator) {
console.log(value); // Output: 4, 2, 5, 1, 3 (In-order traversal)
}
ఈ ఉదాహరణలో, మరొక ఇటరేటర్కు అప్పగించడానికి yield* ఉపయోగించబడింది. ఇది పునరావృత ఇటరేషన్ కోసం చాలా ముఖ్యమైనది, జెనరేటర్ మొత్తం ట్రీ నిర్మాణాన్ని దాటడానికి అనుమతిస్తుంది.
3. అసమకాలిక కార్యకలాపాలను నిర్వహించడం
అసమకాలిక కార్యకలాపాలను మరింత వరుసగా మరియు చదవగలిగే పద్ధతిలో నిర్వహించడానికి జెనరేటర్ ఫంక్షన్లను ప్రామిసెస్తో కలపవచ్చు. API నుండి డేటాను పొందడం వంటి పనులకు ఇది ప్రత్యేకంగా ఉపయోగపడుతుంది.
async function fetchData(url) {
const response = await fetch(url);
const data = await response.json();
return data;
}
function* dataFetcher(urls) {
for (const url of urls) {
try {
const data = yield fetchData(url);
yield data;
} catch (error) {
console.error("Error fetching data from", url, error);
yield null; // Or handle the error as needed
}
}
}
async function runDataFetcher() {
const urls = [
"https://jsonplaceholder.typicode.com/todos/1",
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/users/1"
];
const dataIterator = dataFetcher(urls);
for (const promise of dataIterator) {
const data = await promise; // Await the promise returned by yield
if (data) {
console.log("Fetched data:", data);
} else {
console.log("Failed to fetch data.");
}
}
}
runDataFetcher();
ఈ ఉదాహరణ అసమకాలిక పునరావృత్తిని ప్రదర్శిస్తుంది. dataFetcher జెనరేటర్ ఫంక్షన్ పొందిన డేటాకు పరిష్కారమయ్యే ప్రామిసెస్ను యీల్డ్ చేస్తుంది. runDataFetcher ఫంక్షన్ ఈ ప్రామిసెస్ల ద్వారా పునరావృతం చేస్తుంది, డేటాను ప్రాసెస్ చేయడానికి ముందు ప్రతి ఒక్కదాని కోసం వేచి ఉంటుంది. ఈ విధానం అసమకాలిక కోడ్ను మరింత సింక్రోనస్గా కనిపించేలా చేయడం ద్వారా దానిని సులభతరం చేస్తుంది.
4. అనంతమైన క్రమాలు
అనంతమైన క్రమాలను సూచించడానికి జెనరేటర్లు ఖచ్చితంగా సరిపోతాయి, ఇవి ఎప్పటికీ అంతం కాని క్రమాలు. అవి అభ్యర్థించినప్పుడు మాత్రమే విలువలను ఉత్పత్తి చేస్తాయి కాబట్టి, అవి అధిక మెమరీని వినియోగించకుండా అనంతమైన పొడవైన క్రమాలను నిర్వహించగలవు.
function* fibonacciSequence() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fibonacci = fibonacciSequence();
// Get the first 10 Fibonacci numbers
for (let i = 0; i < 10; i++) {
console.log(fibonacci.next().value); // Output: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
}
ఈ ఉదాహరణ అనంతమైన ఫైబొనాక్సీ క్రమాన్ని ఎలా సృష్టించాలో చూపిస్తుంది. జెనరేటర్ ఫంక్షన్ నిరవధికంగా ఫైబొనాక్సీ సంఖ్యలను యీల్డ్ చేస్తూనే ఉంటుంది. ఆచరణలో, మీరు అనంతమైన లూప్ లేదా మెమరీ అలసటను నివారించడానికి సాధారణంగా పొందిన విలువల సంఖ్యను పరిమితం చేస్తారు.
5. కస్టమ్ రేంజ్ ఫంక్షన్ను అమలు చేయడం
జెనరేటర్లను ఉపయోగించి పైథాన్ యొక్క అంతర్నిర్మిత రేంజ్ ఫంక్షన్కు సమానమైన కస్టమ్ రేంజ్ ఫంక్షన్ను సృష్టించండి.
function* range(start, end, step = 1) {
if (step > 0) {
for (let i = start; i < end; i += step) {
yield i;
}
} else if (step < 0) {
for (let i = start; i > end; i += step) {
yield i;
}
}
}
// Generate numbers from 0 to 5 (exclusive)
for (const num of range(0, 5)) {
console.log(num); // Output: 0, 1, 2, 3, 4
}
// Generate numbers from 10 to 0 (exclusive) in reverse order
for (const num of range(10, 0, -2)) {
console.log(num); // Output: 10, 8, 6, 4, 2
}
అధునాతన జెనరేటర్ ఫంక్షన్ పద్ధతులు
1. జెనరేటర్ ఫంక్షన్లలో return ఉపయోగించడం
ఒక జెనరేటర్ ఫంక్షన్లోని return స్టేట్మెంట్ పునరావృత్తి ముగింపును సూచిస్తుంది. ఒక return స్టేట్మెంట్ ఎదురైనప్పుడు, ఇటరేటర్ యొక్క next() పద్ధతి యొక్క done ప్రాపర్టీ trueకి సెట్ చేయబడుతుంది, మరియు value ప్రాపర్టీ return స్టేట్మెంట్ ద్వారా తిరిగి ఇవ్వబడిన విలువకు సెట్ చేయబడుతుంది (ఏదైనా ఉంటే).
function* myGenerator() {
yield 1;
yield 2;
return 3; // End of iteration
yield 4; // This will not be executed
}
const iterator = myGenerator();
console.log(iterator.next()); // Output: { value: 1, done: false }
console.log(iterator.next()); // Output: { value: 2, done: false }
console.log(iterator.next()); // Output: { value: 3, done: true }
console.log(iterator.next()); // Output: { value: undefined, done: true }
2. జెనరేటర్ ఫంక్షన్లలో throw ఉపయోగించడం
ఇటరేటర్ ఆబ్జెక్ట్పై ఉన్న throw పద్ధతి జెనరేటర్ ఫంక్షన్లోకి ఒక మినహాయింపును ఇంజెక్ట్ చేయడానికి మిమ్మల్ని అనుమతిస్తుంది. జెనరేటర్లో లోపాలను నిర్వహించడానికి లేదా నిర్దిష్ట పరిస్థితులను సూచించడానికి ఇది ఉపయోగపడుతుంది.
function* myGenerator() {
try {
yield 1;
yield 2;
} catch (error) {
console.error("Caught an error:", error);
}
yield 3;
}
const iterator = myGenerator();
console.log(iterator.next()); // Output: { value: 1, done: false }
iterator.throw(new Error("Something went wrong!")); // Inject an error
console.log(iterator.next()); // Output: { value: 3, done: false }
console.log(iterator.next()); // Output: { value: undefined, done: true }
3. yield*తో మరొక ఇటరబుల్కు అప్పగించడం
ట్రీ ట్రావర్సల్ ఉదాహరణలో చూసినట్లుగా, yield* సింటాక్స్ మరొక ఇటరబుల్ (లేదా మరొక జెనరేటర్ ఫంక్షన్) కు అప్పగించడానికి మిమ్మల్ని అనుమతిస్తుంది. ఇది ఇటరేటర్లను కంపోజ్ చేయడానికి మరియు సంక్లిష్టమైన పునరావృత తర్కాన్ని సులభతరం చేయడానికి ఒక శక్తివంతమైన లక్షణం.
function* generator1() {
yield 1;
yield 2;
}
function* generator2() {
yield* generator1(); // Delegate to generator1
yield 3;
yield 4;
}
const iterator = generator2();
for (const value of iterator) {
console.log(value); // Output: 1, 2, 3, 4
}
జెనరేటర్ ఫంక్షన్లను ఉపయోగించడం వల్ల కలిగే ప్రయోజనాలు
- మెరుగైన పఠనీయత: మాన్యువల్ ఇటరేటర్ అమలులతో పోలిస్తే జెనరేటర్ ఫంక్షన్లు ఇటరేటర్ కోడ్ను మరింత సంక్షిప్తంగా మరియు సులభంగా అర్థం చేసుకునేలా చేస్తాయి.
- సరళీకృత అసమకాలిక ప్రోగ్రామింగ్: అవి అసమకాలిక కార్యకలాపాలను మరింత సింక్రోనస్ శైలిలో వ్రాయడానికి మిమ్మల్ని అనుమతించడం ద్వారా అసమకాలిక కోడ్ను క్రమబద్ధీకరిస్తాయి.
- మెమరీ సామర్థ్యం: జెనరేటర్ ఫంక్షన్లు డిమాండ్పై విలువలను ఉత్పత్తి చేస్తాయి, ఇది పెద్ద డేటాసెట్లు లేదా అనంతమైన క్రమాలకు ప్రత్యేకంగా ప్రయోజనకరంగా ఉంటుంది. అవి మొత్తం డేటాసెట్ను ఒకేసారి మెమరీలోకి లోడ్ చేయడాన్ని నివారిస్తాయి.
- కోడ్ పునర్వినియోగం: మీరు మీ అప్లికేషన్లోని వివిధ భాగాలలో ఉపయోగించగల పునర్వినియోగ జెనరేటర్ ఫంక్షన్లను సృష్టించవచ్చు.
- వశ్యత: జెనరేటర్ ఫంక్షన్లు వివిధ డేటా నిర్మాణాలను మరియు పునరావృత నమూనాలను నిర్వహించగల కస్టమ్ ఇటరేటర్లను సృష్టించడానికి ఒక సౌకర్యవంతమైన మార్గాన్ని అందిస్తాయి.
జెనరేటర్ ఫంక్షన్లను ఉపయోగించడానికి ఉత్తమ పద్ధతులు
- వివరణాత్మక పేర్లను ఉపయోగించండి: కోడ్ పఠనీయతను మెరుగుపరచడానికి మీ జెనరేటర్ ఫంక్షన్లు మరియు వేరియబుల్స్కు అర్థవంతమైన పేర్లను ఎంచుకోండి.
- లోపాలను సునాయాసంగా నిర్వహించండి: ఊహించని ప్రవర్తనను నివారించడానికి మీ జెనరేటర్ ఫంక్షన్లలో లోపం నిర్వహణను అమలు చేయండి.
- అనంతమైన క్రమాలను పరిమితం చేయండి: అనంతమైన క్రమాలతో పనిచేసేటప్పుడు, అనంతమైన లూప్లు లేదా మెమరీ అలసటను నివారించడానికి పొందిన విలువల సంఖ్యను పరిమితం చేసే యంత్రాంగం ఉందని నిర్ధారించుకోండి.
- పనితీరును పరిగణించండి: జెనరేటర్ ఫంక్షన్లు సాధారణంగా సమర్థవంతంగా ఉన్నప్పటికీ, ముఖ్యంగా గణనపరంగా తీవ్రమైన కార్యకలాపాలతో వ్యవహరించేటప్పుడు పనితీరు ప్రభావాల గురించి గుర్తుంచుకోండి.
- మీ కోడ్ను డాక్యుమెంట్ చేయండి: ఇతర డెవలపర్లు వాటిని ఎలా ఉపయోగించాలో అర్థం చేసుకోవడంలో సహాయపడటానికి మీ జెనరేటర్ ఫంక్షన్ల కోసం స్పష్టమైన మరియు సంక్షిప్త డాక్యుమెంటేషన్ను అందించండి.
జావాస్క్రిప్ట్ దాటిన వినియోగ సందర్భాలు
జెనరేటర్లు మరియు ఇటరేటర్ల భావన జావాస్క్రిప్ట్ దాటి విస్తరించి, వివిధ ప్రోగ్రామింగ్ భాషలు మరియు దృశ్యాలలో అనువర్తనాలను కనుగొంటుంది. ఉదాహరణకు:
- పైథాన్: పైథాన్లో జావాస్క్రిప్ట్కు చాలా పోలి ఉండే
yieldకీవర్డ్ని ఉపయోగించి జెనరేటర్లకు అంతర్నిర్మిత మద్దతు ఉంది. అవి సమర్థవంతమైన డేటా ప్రాసెసింగ్ మరియు మెమరీ నిర్వహణ కోసం విస్తృతంగా ఉపయోగించబడతాయి. - C#: C# కస్టమ్ కలెక్షన్ ఇటరేషన్ను అమలు చేయడానికి ఇటరేటర్లు మరియు
yield returnస్టేట్మెంట్ను ఉపయోగిస్తుంది. - డేటా స్ట్రీమింగ్: డేటా ప్రాసెసింగ్ పైప్లైన్లలో, పెద్ద డేటా స్ట్రీమ్లను ముక్కలుగా ప్రాసెస్ చేయడానికి జెనరేటర్లను ఉపయోగించవచ్చు, ఇది సామర్థ్యాన్ని మెరుగుపరుస్తుంది మరియు మెమరీ వినియోగాన్ని తగ్గిస్తుంది. సెన్సార్లు, ఆర్థిక మార్కెట్లు లేదా సోషల్ మీడియా నుండి నిజ-సమయ డేటాతో వ్యవహరించేటప్పుడు ఇది ప్రత్యేకంగా ముఖ్యం.
- గేమ్ డెవలప్మెంట్: భూభాగం ఉత్పత్తి లేదా యానిమేషన్ సీక్వెన్సులు వంటి ప్రొసీజరల్ కంటెంట్ను సృష్టించడానికి జెనరేటర్లను ఉపయోగించవచ్చు, మొత్తం కంటెంట్ను ముందుగా లెక్కించి మెమరీలో నిల్వ చేయకుండా.
ముగింపు
జావాస్క్రిప్ట్ జెనరేటర్ ఫంక్షన్లు ఇటరేటర్లను సృష్టించడానికి మరియు అసమకాలిక కార్యకలాపాలను మరింత సొగసైన మరియు సమర్థవంతమైన పద్ధతిలో నిర్వహించడానికి ఒక శక్తివంతమైన సాధనం. ఇటరేటర్ ప్రోటోకాల్ను అర్థం చేసుకోవడం మరియు yield కీవర్డ్పై పట్టు సాధించడం ద్వారా, మీరు మరింత చదవగలిగే, నిర్వహించగలిగే మరియు పనితీరు గల జావాస్క్రిప్ట్ అప్లికేషన్లను రూపొందించడానికి జెనరేటర్ ఫంక్షన్లను ఉపయోగించుకోవచ్చు. సంఖ్యల క్రమాలను ఉత్పత్తి చేయడం నుండి సంక్లిష్ట డేటా నిర్మాణాలను దాటడం మరియు అసమకాలిక పనులను నిర్వహించడం వరకు, జెనరేటర్ ఫంక్షన్లు విస్తృత శ్రేణి ప్రోగ్రామింగ్ సవాళ్లకు బహుముఖ పరిష్కారాన్ని అందిస్తాయి. మీ జావాస్క్రిప్ట్ డెవలప్మెంట్ వర్క్ఫ్లోలో కొత్త అవకాశాలను అన్లాక్ చేయడానికి జెనరేటర్ ఫంక్షన్లను స్వీకరించండి.