ജാവാസ്ക്രിപ്റ്റ് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ മനസ്സിലാക്കുന്നതിനും നടപ്പിലാക്കുന്നതിനുമുള്ള ഒരു സമ്പൂർണ്ണ ഗൈഡ്. മികച്ച ഡാറ്റാ കൈകാര്യത്തിനായി കസ്റ്റം ഇറ്ററേറ്ററുകൾ നിർമ്മിക്കാൻ ഇത് നിങ്ങളെ സഹായിക്കും.
ജാവാസ്ക്രിപ്റ്റ് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിൻ്റെയും കസ്റ്റം ഇറ്ററേറ്ററുകളുടെയും രഹസ്യം ചുരുളഴിക്കുന്നു
ജാവാസ്ക്രിപ്റ്റിൻ്റെ ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ, ഡാറ്റാ സ്ട്രക്ച്ചറുകളിലൂടെ കടന്നുപോകുന്നതിന് ഒരു ഏകീകൃത മാർഗ്ഗം നൽകുന്നു. ഈ പ്രോട്ടോക്കോൾ മനസ്സിലാക്കുന്നത്, അറേകളും സ്ട്രിംഗുകളും പോലുള്ള ബിൽറ്റ്-ഇൻ ഇറ്ററബിൾസുമായി കാര്യക്ഷമമായി പ്രവർത്തിക്കാനും, നിർദ്ദിഷ്ട ഡാറ്റാ സ്ട്രക്ച്ചറുകൾക്കും ആപ്ലിക്കേഷൻ ആവശ്യകതകൾക്കും അനുസൃതമായി സ്വന്തമായി കസ്റ്റം ഇറ്ററബിൾസ് നിർമ്മിക്കാനും ഡെവലപ്പർമാരെ പ്രാപ്തരാക്കുന്നു. ഈ ഗൈഡ് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിനെയും കസ്റ്റം ഇറ്ററേറ്ററുകൾ എങ്ങനെ നടപ്പിലാക്കാം എന്നതിനെയും കുറിച്ച് സമഗ്രമായ ഒരു പര്യവേക്ഷണം നൽകുന്നു.
എന്താണ് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ?
ഒരു ഒബ്ജക്റ്റിനെ എങ്ങനെ ഇറ്ററേറ്റ് ചെയ്യാം, അതായത് അതിലെ ഘടകങ്ങളെ എങ്ങനെ ക്രമമായി ആക്സസ് ചെയ്യാം എന്ന് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ നിർവചിക്കുന്നു. ഇതിന് രണ്ട് ഭാഗങ്ങളുണ്ട്: ഇറ്ററബിൾ പ്രോട്ടോക്കോളും ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളും.
ഇറ്ററബിൾ പ്രോട്ടോക്കോൾ
ഒരു ഒബ്ജക്റ്റിന് Symbol.iterator
എന്ന കീയിൽ ഒരു മെത്തേഡ് ഉണ്ടെങ്കിൽ അത് ഇറ്ററബിൾ ആയി കണക്കാക്കപ്പെടുന്നു. ഈ മെത്തേഡ് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിന് അനുസൃതമായ ഒരു ഒബ്ജക്റ്റ് നൽകണം.
ചുരുക്കത്തിൽ, ഒരു ഇറ്ററബിൾ ഒബ്ജക്റ്റിന് തനിക്കുവേണ്ടി ഒരു ഇറ്ററേറ്റർ എങ്ങനെ നിർമ്മിക്കണമെന്ന് അറിയാം.
ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ
ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ ഒരു ശ്രേണിയിൽ നിന്ന് എങ്ങനെ മൂല്യങ്ങൾ വീണ്ടെടുക്കാമെന്ന് നിർവചിക്കുന്നു. ഒരു ഒബ്ജക്റ്റിന് രണ്ട് പ്രോപ്പർട്ടികളുള്ള ഒരു ഒബ്ജക്റ്റ് നൽകുന്ന next()
എന്ന മെത്തേഡ് ഉണ്ടെങ്കിൽ അത് ഒരു ഇറ്ററേറ്റർ ആയി കണക്കാക്കപ്പെടുന്നു:
value
: ശ്രേണിയിലെ അടുത്ത മൂല്യം.done
: ഇറ്ററേറ്റർ ശ്രേണിയുടെ അവസാനത്തിൽ എത്തിയോ എന്ന് സൂചിപ്പിക്കുന്ന ഒരു ബൂളിയൻ മൂല്യം.done
true
ആണെങ്കിൽ,value
പ്രോപ്പർട്ടി ഒഴിവാക്കാവുന്നതാണ്.
ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിൻ്റെ പ്രധാന ഭാഗം next()
മെത്തേഡാണ്. next()
-ലേക്കുള്ള ഓരോ കോളും ഇറ്ററേറ്ററിനെ മുന്നോട്ട് കൊണ്ടുപോകുകയും ശ്രേണിയിലെ അടുത്ത മൂല്യം നൽകുകയും ചെയ്യുന്നു. എല്ലാ മൂല്യങ്ങളും നൽകിക്കഴിയുമ്പോൾ, next()
done
true
ആയി സജ്ജീകരിച്ച ഒരു ഒബ്ജക്റ്റ് നൽകുന്നു.
ബിൽറ്റ്-ഇൻ ഇറ്ററബിൾസ്
ജാവാസ്ക്രിപ്റ്റ് സഹജമായി ഇറ്ററേറ്റ് ചെയ്യാവുന്ന നിരവധി ബിൽറ്റ്-ഇൻ ഡാറ്റാ സ്ട്രക്ച്ചറുകൾ നൽകുന്നു. അവയിൽ ചിലത്:
- അറേകൾ (Arrays)
- സ്ട്രിംഗുകൾ (Strings)
- മാപ്പുകൾ (Maps)
- സെറ്റുകൾ (Sets)
- ഒരു ഫംഗ്ഷൻ്റെ ആർഗ്യുമെൻ്റ്സ് ഒബ്ജക്റ്റ് (Arguments object)
- ടൈപ്പ്ഡ് അറേകൾ (TypedArrays)
ഈ ഇറ്ററബിൾസ് for...of
ലൂപ്പ്, സ്പ്രെഡ് സിൻ്റാക്സ് (...
), കൂടാതെ ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിനെ ആശ്രയിക്കുന്ന മറ്റ് ഘടനകളിലും നേരിട്ട് ഉപയോഗിക്കാൻ കഴിയും.
അറേകൾ ഉപയോഗിച്ചുള്ള ഉദാഹരണം:
const myArray = ["apple", "banana", "cherry"];
for (const item of myArray) {
console.log(item); // Output: apple, banana, cherry
}
സ്ട്രിംഗുകൾ ഉപയോഗിച്ചുള്ള ഉദാഹരണം:
const myString = "Hello";
for (const char of myString) {
console.log(char); // Output: H, e, l, l, o
}
for...of
ലൂപ്പ്
ഇറ്ററബിൾ ഒബ്ജക്റ്റുകളിലൂടെ ഇറ്ററേറ്റ് ചെയ്യുന്നതിനുള്ള ശക്തമായ ഒരു നിർമ്മിതിയാണ് for...of
ലൂപ്പ്. ഇത് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിൻ്റെ സങ്കീർണ്ണതകൾ സ്വയമേവ കൈകാര്യം ചെയ്യുന്നു, ഇത് ഒരു ശ്രേണിയിലെ മൂല്യങ്ങൾ ആക്സസ് ചെയ്യുന്നത് എളുപ്പമാക്കുന്നു.
for...of
ലൂപ്പിൻ്റെ സിൻ്റാക്സ് ഇതാണ്:
for (const element of iterable) {
// ഓരോ എലമെൻ്റിനും വേണ്ടി എക്സിക്യൂട്ട് ചെയ്യേണ്ട കോഡ്
}
for...of
ലൂപ്പ് ഇറ്ററബിൾ ഒബ്ജക്റ്റിൽ നിന്ന് ഇറ്ററേറ്റർ വീണ്ടെടുക്കുകയും (Symbol.iterator
ഉപയോഗിച്ച്), done
true
ആകുന്നതുവരെ ഇറ്ററേറ്ററിൻ്റെ next()
മെത്തേഡ് ആവർത്തിച്ച് വിളിക്കുകയും ചെയ്യുന്നു. ഓരോ ഇറ്ററേഷനിലും, next()
നൽകുന്ന value
പ്രോപ്പർട്ടി element
വേരിയബിളിന് നൽകുന്നു.
കസ്റ്റം ഇറ്ററേറ്ററുകൾ നിർമ്മിക്കുന്നു
ജാവാസ്ക്രിപ്റ്റ് ബിൽറ്റ്-ഇൻ ഇറ്ററബിൾസ് നൽകുന്നുണ്ടെങ്കിലും, ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിൻ്റെ യഥാർത്ഥ ശക്തി നിങ്ങളുടെ സ്വന്തം ഡാറ്റാ സ്ട്രക്ച്ചറുകൾക്കായി കസ്റ്റം ഇറ്ററേറ്ററുകൾ നിർവചിക്കാനുള്ള അതിൻ്റെ കഴിവിലാണ്. ഇത് നിങ്ങളുടെ ഡാറ്റ എങ്ങനെ കടന്നുപോകുന്നുവെന്നും ആക്സസ് ചെയ്യുന്നുവെന്നും നിയന്ത്രിക്കാൻ നിങ്ങളെ അനുവദിക്കുന്നു.
ഒരു കസ്റ്റം ഇറ്ററേറ്റർ എങ്ങനെ നിർമ്മിക്കാം എന്നത് താഴെ നൽകുന്നു:
- നിങ്ങളുടെ കസ്റ്റം ഡാറ്റാ സ്ട്രക്ച്ചറിനെ പ്രതിനിധീകരിക്കുന്ന ഒരു ക്ലാസ് അല്ലെങ്കിൽ ഒബ്ജക്റ്റ് നിർവചിക്കുക.
- നിങ്ങളുടെ ക്ലാസിലോ ഒബ്ജക്റ്റിലോ
Symbol.iterator
മെത്തേഡ് നടപ്പിലാക്കുക. ഈ മെത്തേഡ് ഒരു ഇറ്ററേറ്റർ ഒബ്ജക്റ്റ് നൽകണം. - ഇറ്ററേറ്റർ ഒബ്ജക്റ്റിന്
value
,done
പ്രോപ്പർട്ടികളുള്ള ഒരു ഒബ്ജക്റ്റ് നൽകുന്നnext()
മെത്തേഡ് ഉണ്ടായിരിക്കണം.
ഉദാഹരണം: ഒരു ലളിതമായ റേഞ്ചിനായി ഒരു ഇറ്ററേറ്റർ നിർമ്മിക്കുന്നു
നമുക്ക് ഒരു സംഖ്യകളുടെ ശ്രേണിയെ പ്രതിനിധീകരിക്കുന്ന Range
എന്നൊരു ക്ലാസ് ഉണ്ടാക്കാം. ഈ ശ്രേണിയിലെ സംഖ്യകളിലൂടെ ഇറ്ററേറ്റ് ചെയ്യാൻ നമ്മൾ ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ നടപ്പിലാക്കും.
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let currentValue = this.start;
const that = this; // Capture 'this' for use inside the iterator object
return {
next() {
if (currentValue <= that.end) {
return {
value: currentValue++,
done: false,
};
} else {
return {
value: undefined,
done: true,
};
}
},
};
}
}
const myRange = new Range(1, 5);
for (const number of myRange) {
console.log(number); // Output: 1, 2, 3, 4, 5
}
വിശദീകരണം:
Range
ക്ലാസ് അതിൻ്റെ കൺസ്ട്രക്റ്ററിൽstart
,end
മൂല്യങ്ങൾ എടുക്കുന്നു.Symbol.iterator
മെത്തേഡ് ഒരു ഇറ്ററേറ്റർ ഒബ്ജക്റ്റ് നൽകുന്നു. ഈ ഇറ്ററേറ്റർ ഒബ്ജക്റ്റിന് അതിൻ്റേതായ സ്റ്റേറ്റ് (currentValue
) കൂടാതെ ഒരുnext()
മെത്തേഡും ഉണ്ട്.next()
മെത്തേഡ്currentValue
റേഞ്ചിനുള്ളിലാണോ എന്ന് പരിശോധിക്കുന്നു. ആണെങ്കിൽ, അത് നിലവിലെ മൂല്യവുംdone
false
ആയി സജ്ജീകരിച്ച ഒരു ഒബ്ജക്റ്റ് നൽകുന്നു. അടുത്ത ഇറ്ററേഷനായി ഇത്currentValue
വർദ്ധിപ്പിക്കുകയും ചെയ്യുന്നു.currentValue
end
മൂല്യത്തേക്കാൾ കൂടുമ്പോൾ,next()
മെത്തേഡ്done
true
ആയി സജ്ജീകരിച്ച ഒരു ഒബ്ജക്റ്റ് നൽകുന്നു.that = this
എന്ന ഉപയോഗം ശ്രദ്ധിക്കുക. `next()` മെത്തേഡ് മറ്റൊരു സ്കോപ്പിൽ (`for...of` ലൂപ്പ് വഴി) വിളിക്കപ്പെടുന്നതിനാൽ, `next()`-നുള്ളിലെ `this` `Range` ഇൻസ്റ്റൻസിനെ സൂചിപ്പിക്കില്ല. ഇത് പരിഹരിക്കാൻ, `next()`-ൻ്റെ സ്കോപ്പിന് പുറത്ത് `this` മൂല്യത്തെ (`Range` ഇൻസ്റ്റൻസ്) `that`-ൽ സൂക്ഷിക്കുകയും തുടർന്ന് `next()`-നുള്ളിൽ `that` ഉപയോഗിക്കുകയും ചെയ്യുന്നു.
ഉദാഹരണം: ഒരു ലിങ്ക്ഡ് ലിസ്റ്റിനായി ഒരു ഇറ്ററേറ്റർ നിർമ്മിക്കുന്നു
നമുക്ക് മറ്റൊരു ഉദാഹരണം പരിഗണിക്കാം: ഒരു ലിങ്ക്ഡ് ലിസ്റ്റ് ഡാറ്റാ സ്ട്രക്ച്ചറിനായി ഒരു ഇറ്ററേറ്റർ നിർമ്മിക്കുന്നത്. ഒരു ലിങ്ക്ഡ് ലിസ്റ്റ് എന്നത് നോഡുകളുടെ ഒരു ശ്രേണിയാണ്, ഇവിടെ ഓരോ നോഡിലും ഒരു മൂല്യവും ലിസ്റ്റിലെ അടുത്ത നോഡിലേക്കുള്ള ഒരു റെഫറൻസും (പോയിൻ്റർ) അടങ്ങിയിരിക്കുന്നു. ലിസ്റ്റിലെ അവസാന നോഡിന് null (അല്ലെങ്കിൽ undefined) ലേക്ക് ഒരു റെഫറൻസുണ്ടായിരിക്കും.
class LinkedListNode {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
constructor() {
this.head = null;
}
append(value) {
const newNode = new LinkedListNode(value);
if (!this.head) {
this.head = newNode;
return;
}
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
[Symbol.iterator]() {
let current = this.head;
return {
next() {
if (current) {
const value = current.value;
current = current.next;
return {
value: value,
done: false
};
} else {
return {
value: undefined,
done: true
};
}
}
};
}
}
// Example Usage:
const myList = new LinkedList();
myList.append("London");
myList.append("Paris");
myList.append("Tokyo");
for (const city of myList) {
console.log(city); // Output: London, Paris, Tokyo
}
വിശദീകരണം:
LinkedListNode
ക്ലാസ് ലിങ്ക്ഡ് ലിസ്റ്റിലെ ഒരൊറ്റ നോഡിനെ പ്രതിനിധീകരിക്കുന്നു, അത് ഒരുvalue
-യും അടുത്ത നോഡിലേക്കുള്ള ഒരു റെഫറൻസും (next
) സംഭരിക്കുന്നു.LinkedList
ക്ലാസ് ലിങ്ക്ഡ് ലിസ്റ്റിനെ തന്നെ പ്രതിനിധീകരിക്കുന്നു. ഇതിന്head
എന്ന ഒരു പ്രോപ്പർട്ടി ഉണ്ട്, അത് ലിസ്റ്റിലെ ആദ്യത്തെ നോഡിലേക്ക് വിരൽ ചൂണ്ടുന്നു.append()
മെത്തേഡ് ലിസ്റ്റിൻ്റെ അവസാനത്തിലേക്ക് പുതിയ നോഡുകൾ ചേർക്കുന്നു.Symbol.iterator
മെത്തേഡ് ഒരു ഇറ്ററേറ്റർ ഒബ്ജക്റ്റ് ഉണ്ടാക്കി നൽകുന്നു. ഈ ഇറ്ററേറ്റർ സന്ദർശിക്കുന്ന നിലവിലെ നോഡിൻ്റെ (current
) ട്രാക്ക് സൂക്ഷിക്കുന്നു.next()
മെത്തേഡ് ഒരു നിലവിലെ നോഡ് ഉണ്ടോയെന്ന് പരിശോധിക്കുന്നു (current
null അല്ല). ഉണ്ടെങ്കിൽ, അത് നിലവിലെ നോഡിൽ നിന്ന് മൂല്യം വീണ്ടെടുക്കുന്നു,current
പോയിൻ്റർ അടുത്ത നോഡിലേക്ക് മുന്നോട്ട് നീക്കുന്നു, തുടർന്ന് മൂല്യവുംdone: false
ഉം ഉള്ള ഒരു ഒബ്ജക്റ്റ് നൽകുന്നു.current
null ആകുമ്പോൾ (അതായത് നമ്മൾ ലിസ്റ്റിൻ്റെ അവസാനത്തിൽ എത്തി),next()
മെത്തേഡ്done: true
ഉള്ള ഒരു ഒബ്ജക്റ്റ് നൽകുന്നു.
ജനറേറ്റർ ഫംഗ്ഷനുകൾ
ജനറേറ്റർ ഫംഗ്ഷനുകൾ ഇറ്ററേറ്ററുകൾ നിർമ്മിക്കുന്നതിന് കൂടുതൽ സംക്ഷിപ്തവും ലളിതവുമായ ഒരു മാർഗ്ഗം നൽകുന്നു. ആവശ്യാനുസരണം മൂല്യങ്ങൾ ഉത്പാദിപ്പിക്കാൻ അവ yield
കീവേഡ് ഉപയോഗിക്കുന്നു.
function*
സിൻ്റാക്സ് ഉപയോഗിച്ചാണ് ഒരു ജനറേറ്റർ ഫംഗ്ഷൻ നിർവചിക്കുന്നത്.
ഉദാഹരണം: ഒരു ജനറേറ്റർ ഫംഗ്ഷൻ ഉപയോഗിച്ച് ഒരു ഇറ്ററേറ്റർ നിർമ്മിക്കുന്നു
നമുക്ക് Range
ഇറ്ററേറ്റർ ഒരു ജനറേറ്റർ ഫംഗ്ഷൻ ഉപയോഗിച്ച് മാറ്റിയെഴുതാം:
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
const myRange = new Range(1, 5);
for (const number of myRange) {
console.log(number); // Output: 1, 2, 3, 4, 5
}
വിശദീകരണം:
- ഇപ്പോൾ
Symbol.iterator
മെത്തേഡ് ഒരു ജനറേറ്റർ ഫംഗ്ഷനാണ് (*
ശ്രദ്ധിക്കുക). - ജനറേറ്റർ ഫംഗ്ഷനുള്ളിൽ, സംഖ്യകളുടെ ശ്രേണിയിലൂടെ ഇറ്ററേറ്റ് ചെയ്യാൻ നമ്മൾ ഒരു
for
ലൂപ്പ് ഉപയോഗിക്കുന്നു. yield
കീവേഡ് ജനറേറ്റർ ഫംഗ്ഷൻ്റെ പ്രവർത്തനം താൽക്കാലികമായി നിർത്തി നിലവിലെ മൂല്യം (i
) നൽകുന്നു. അടുത്ത തവണ ഇറ്ററേറ്ററിൻ്റെnext()
മെത്തേഡ് വിളിക്കുമ്പോൾ, നിർത്തിയിടത്ത് നിന്ന് (yield
സ്റ്റേറ്റ്മെൻ്റിന് ശേഷം) പ്രവർത്തനം പുനരാരംഭിക്കുന്നു.- ലൂപ്പ് പൂർത്തിയാകുമ്പോൾ, ജനറേറ്റർ ഫംഗ്ഷൻ പരോക്ഷമായി
{ value: undefined, done: true }
നൽകുന്നു, ഇത് ഇറ്ററേഷൻ്റെ അവസാനത്തെ സൂചിപ്പിക്കുന്നു.
ജനറേറ്റർ ഫംഗ്ഷനുകൾ next()
മെത്തേഡും done
ഫ്ലാഗും സ്വയമേവ കൈകാര്യം ചെയ്യുന്നതിലൂടെ ഇറ്ററേറ്റർ നിർമ്മാണം ലളിതമാക്കുന്നു.
ഉദാഹരണം: ഫിബൊനാച്ചി സീക്വൻസ് ജനറേറ്റർ
ജനറേറ്റർ ഫംഗ്ഷനുകൾ ഉപയോഗിക്കുന്നതിൻ്റെ മറ്റൊരു മികച്ച ഉദാഹരണമാണ് ഫിബൊനാച്ചി സീക്വൻസ് ഉണ്ടാക്കുന്നത്:
function* fibonacciSequence() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b]; // Destructuring assignment for simultaneous update
}
}
const fibonacci = fibonacciSequence();
for (let i = 0; i < 10; i++) {
console.log(fibonacci.next().value); // Output: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
}
വിശദീകരണം:
fibonacciSequence
ഫംഗ്ഷൻ ഒരു ജനറേറ്റർ ഫംഗ്ഷനാണ്.- ഇത് ഫിബൊനാച്ചി സീക്വൻസിലെ ആദ്യത്തെ രണ്ട് സംഖ്യകളിലേക്ക് (0, 1)
a
,b
എന്നിങ്ങനെ രണ്ട് വേരിയബിളുകൾ ഇനീഷ്യലൈസ് ചെയ്യുന്നു. while (true)
ലൂപ്പ് ഒരു അനന്തമായ ശ്രേണി സൃഷ്ടിക്കുന്നു.yield a
സ്റ്റേറ്റ്മെൻ്റ്a
-യുടെ നിലവിലെ മൂല്യം ഉത്പാദിപ്പിക്കുന്നു.[a, b] = [b, a + b]
എന്ന സ്റ്റേറ്റ്മെൻ്റ്, ഡീസ്ട്രക്ചറിംഗ് അസൈൻമെൻ്റ് ഉപയോഗിച്ച് ഒരേസമയംa
,b
എന്നിവയെ സീക്വൻസിലെ അടുത്ത രണ്ട് സംഖ്യകളിലേക്ക് അപ്ഡേറ്റ് ചെയ്യുന്നു.fibonacci.next().value
എന്ന എക്സ്പ്രഷൻ ജനറേറ്ററിൽ നിന്ന് അടുത്ത മൂല്യം വീണ്ടെടുക്കുന്നു. ജനറേറ്റർ അനന്തമായതിനാൽ, അതിൽ നിന്ന് എത്ര മൂല്യങ്ങൾ വേണമെന്ന് നിങ്ങൾ നിയന്ത്രിക്കേണ്ടതുണ്ട്. ഈ ഉദാഹരണത്തിൽ, നമ്മൾ ആദ്യത്തെ 10 മൂല്യങ്ങൾ എടുക്കുന്നു.
ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ ഉപയോഗിക്കുന്നതിൻ്റെ പ്രയോജനങ്ങൾ
- ഏകീകരണം: ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ വ്യത്യസ്ത ഡാറ്റാ സ്ട്രക്ച്ചറുകളിലൂടെ ഇറ്ററേറ്റ് ചെയ്യുന്നതിന് ഒരു സ്ഥിരമായ മാർഗ്ഗം നൽകുന്നു.
- വഴക്കം: നിങ്ങളുടെ നിർദ്ദിഷ്ട ആവശ്യങ്ങൾക്കനുസരിച്ച് കസ്റ്റം ഇറ്ററേറ്ററുകൾ നിർവചിക്കാൻ നിങ്ങൾക്ക് കഴിയും.
- വായനാക്ഷമത:
for...of
ലൂപ്പ് ഇറ്ററേഷൻ കോഡിനെ കൂടുതൽ വായനാക്ഷമവും സംക്ഷിപ്തവുമാക്കുന്നു. - കാര്യക്ഷമത: ഇറ്ററേറ്ററുകൾക്ക് അലസമായി പ്രവർത്തിക്കാൻ കഴിയും, അതായത് ആവശ്യമുള്ളപ്പോൾ മാത്രം മൂല്യങ്ങൾ സൃഷ്ടിക്കുന്നു, ഇത് വലിയ ഡാറ്റാ സെറ്റുകളുടെ പ്രകടനം മെച്ചപ്പെടുത്താൻ സഹായിക്കും. ഉദാഹരണത്തിന്, മുകളിലുള്ള ഫിബൊനാച്ചി സീക്വൻസ് ജനറേറ്റർ `next()` വിളിക്കുമ്പോൾ മാത്രമേ അടുത്ത മൂല്യം കണക്കാക്കുന്നുള്ളൂ.
- അനുയോജ്യത: ഇറ്ററേറ്ററുകൾ സ്പ്രെഡ് സിൻ്റാക്സ്, ഡീസ്ട്രക്ചറിംഗ് പോലുള്ള മറ്റ് ജാവാസ്ക്രിപ്റ്റ് ഫീച്ചറുകളുമായി തടസ്സങ്ങളില്ലാതെ പ്രവർത്തിക്കുന്നു.
അഡ്വാൻസ്ഡ് ഇറ്ററേറ്റർ ടെക്നിക്കുകൾ
ഇറ്ററേറ്ററുകൾ സംയോജിപ്പിക്കുന്നു
നിങ്ങൾക്ക് ഒന്നിലധികം ഇറ്ററേറ്ററുകളെ ഒരൊറ്റ ഇറ്ററേറ്ററിലേക്ക് സംയോജിപ്പിക്കാൻ കഴിയും. ഒന്നിലധികം ഉറവിടങ്ങളിൽ നിന്നുള്ള ഡാറ്റ ഏകീകൃതമായി പ്രോസസ്സ് ചെയ്യേണ്ടിവരുമ്പോൾ ഇത് ഉപയോഗപ്രദമാണ്.
function* combineIterators(...iterables) {
for (const iterable of iterables) {
for (const item of iterable) {
yield item;
}
}
}
const array1 = [1, 2, 3];
const array2 = ["a", "b", "c"];
const string1 = "XYZ";
const combined = combineIterators(array1, array2, string1);
for (const value of combined) {
console.log(value); // Output: 1, 2, 3, a, b, c, X, Y, Z
}
ഈ ഉദാഹരണത്തിൽ, `combineIterators` ഫംഗ്ഷൻ എത്ര ഇറ്ററബിൾസിനെയും ആർഗ്യുമെൻ്റായി എടുക്കുന്നു. ഇത് ഓരോ ഇറ്ററബിളിലൂടെയും കടന്നുപോകുകയും ഓരോ ഐറ്റവും യീൽഡ് ചെയ്യുകയും ചെയ്യുന്നു. ഇൻപുട്ട് ഇറ്ററബിൾസിലെ എല്ലാ മൂല്യങ്ങളും നൽകുന്ന ഒരൊറ്റ ഇറ്ററേറ്ററാണ് ഫലം.
ഇറ്ററേറ്ററുകൾ ഫിൽട്ടർ ചെയ്യലും രൂപാന്തരപ്പെടുത്തലും
മറ്റൊരു ഇറ്ററേറ്റർ ഉത്പാദിപ്പിക്കുന്ന മൂല്യങ്ങളെ ഫിൽട്ടർ ചെയ്യുകയോ രൂപാന്തരപ്പെടുത്തുകയോ ചെയ്യുന്ന ഇറ്ററേറ്ററുകളും നിങ്ങൾക്ക് സൃഷ്ടിക്കാൻ കഴിയും. ഇത് ഒരു പൈപ്പ്ലൈനിൽ ഡാറ്റ പ്രോസസ്സ് ചെയ്യാനും, ഓരോ മൂല്യവും ഉത്പാദിപ്പിക്കപ്പെടുമ്പോൾ അതിൽ വ്യത്യസ്ത ഓപ്പറേഷനുകൾ പ്രയോഗിക്കാനും നിങ്ങളെ അനുവദിക്കുന്നു.
function* filterIterator(iterable, predicate) {
for (const item of iterable) {
if (predicate(item)) {
yield item;
}
}
}
function* mapIterator(iterable, transform) {
for (const item of iterable) {
yield transform(item);
}
}
const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = filterIterator(numbers, (x) => x % 2 === 0);
const squaredEvenNumbers = mapIterator(evenNumbers, (x) => x * x);
for (const value of squaredEvenNumbers) {
console.log(value); // Output: 4, 16, 36
}
ഇവിടെ, `filterIterator` ഒരു ഇറ്ററബിളും ഒരു പ്രെഡിക്കേറ്റ് ഫംഗ്ഷനും എടുക്കുന്നു. പ്രെഡിക്കേറ്റ് `true` നൽകുന്ന ഐറ്റംസ് മാത്രമേ ഇത് യീൽഡ് ചെയ്യുകയുള്ളൂ. `mapIterator` ഒരു ഇറ്ററബിളും ഒരു ട്രാൻസ്ഫോം ഫംഗ്ഷനും എടുക്കുന്നു. ഓരോ ഐറ്റത്തിലും ട്രാൻസ്ഫോം ഫംഗ്ഷൻ പ്രയോഗിച്ചതിൻ്റെ ഫലം ഇത് യീൽഡ് ചെയ്യുന്നു.
യഥാർത്ഥ ലോകത്തിലെ പ്രയോഗങ്ങൾ
ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ ജാവാസ്ക്രിപ്റ്റ് ലൈബ്രറികളിലും ഫ്രെയിംവർക്കുകളിലും വ്യാപകമായി ഉപയോഗിക്കപ്പെടുന്നു, കൂടാതെ വിവിധ യഥാർത്ഥ ലോക പ്രയോഗങ്ങളിലും ഇത് വിലപ്പെട്ടതാണ്, പ്രത്യേകിച്ചും വലിയ ഡാറ്റാസെറ്റുകളുമായോ അസിൻക്രണസ് ഓപ്പറേഷനുകളുമായോ ഇടപെടുമ്പോൾ.
- ഡാറ്റാ പ്രോസസ്സിംഗ്: വലിയ ഡാറ്റാസെറ്റുകൾ കാര്യക്ഷമമായി പ്രോസസ്സ് ചെയ്യാൻ ഇറ്ററേറ്ററുകൾ ഉപയോഗപ്രദമാണ്, കാരണം മുഴുവൻ ഡാറ്റാസെറ്റും മെമ്മറിയിലേക്ക് ലോഡ് ചെയ്യാതെ ഡാറ്റയെ ഭാഗങ്ങളായി കൈകാര്യം ചെയ്യാൻ അവ നിങ്ങളെ അനുവദിക്കുന്നു. ഉപഭോക്തൃ ഡാറ്റ അടങ്ങുന്ന ഒരു വലിയ CSV ഫയൽ പാഴ്സ് ചെയ്യുന്നത് സങ്കൽപ്പിക്കുക. മുഴുവൻ ഫയലും മെമ്മറിയിലേക്ക് ലോഡ് ചെയ്യാതെ ഓരോ വരിയും പ്രോസസ്സ് ചെയ്യാൻ ഒരു ഇറ്ററേറ്റർ നിങ്ങളെ അനുവദിക്കും.
- അസിൻക്രണസ് ഓപ്പറേഷനുകൾ: ഒരു API-ൽ നിന്ന് ഡാറ്റ ലഭ്യമാക്കുന്നത് പോലുള്ള അസിൻക്രണസ് ഓപ്പറേഷനുകൾ കൈകാര്യം ചെയ്യാൻ ഇറ്ററേറ്ററുകൾ ഉപയോഗിക്കാം. ഡാറ്റ ലഭ്യമാകുന്നതുവരെ എക്സിക്യൂഷൻ താൽക്കാലികമായി നിർത്താനും തുടർന്ന് അടുത്ത മൂല്യവുമായി പുനരാരംഭിക്കാനും നിങ്ങൾക്ക് ജനറേറ്റർ ഫംഗ്ഷനുകൾ ഉപയോഗിക്കാം.
- കസ്റ്റം ഡാറ്റാ സ്ട്രക്ച്ചറുകൾ: നിർദ്ദിഷ്ട ട്രാവെർസൽ ആവശ്യകതകളുള്ള കസ്റ്റം ഡാറ്റാ സ്ട്രക്ച്ചറുകൾ നിർമ്മിക്കുന്നതിന് ഇറ്ററേറ്ററുകൾ അത്യാവശ്യമാണ്. ഒരു ട്രീ ഡാറ്റാ സ്ട്രക്ച്ചർ പരിഗണിക്കുക. ഒരു നിർദ്ദിഷ്ട ക്രമത്തിൽ (ഉദാഹരണത്തിന്, ഡെപ്ത്-ഫസ്റ്റ് അല്ലെങ്കിൽ ബ്രെഡ്ത്ത്-ഫസ്റ്റ്) ട്രീയിലൂടെ കടന്നുപോകാൻ നിങ്ങൾക്ക് ഒരു കസ്റ്റം ഇറ്ററേറ്റർ നടപ്പിലാക്കാൻ കഴിയും.
- ഗെയിം ഡെവലപ്മെൻ്റ്: ഗെയിം ഡെവലപ്മെൻ്റിൽ, ഗെയിം ഒബ്ജക്റ്റുകൾ, പാർട്ടിക്കിൾ ഇഫക്റ്റുകൾ, മറ്റ് ഡൈനാമിക് ഘടകങ്ങൾ എന്നിവ കൈകാര്യം ചെയ്യാൻ ഇറ്ററേറ്ററുകൾ ഉപയോഗിക്കാം.
- യൂസർ ഇൻ്റർഫേസ് ലൈബ്രറികൾ: പല UI ലൈബ്രറികളും അടിസ്ഥാന ഡാറ്റാ മാറ്റങ്ങളെ അടിസ്ഥാനമാക്കി ഘടകങ്ങളെ കാര്യക്ഷമമായി അപ്ഡേറ്റ് ചെയ്യാനും റെൻഡർ ചെയ്യാനും ഇറ്ററേറ്ററുകൾ ഉപയോഗിക്കുന്നു.
മികച്ച രീതികൾ
Symbol.iterator
ശരിയായി നടപ്പിലാക്കുക: നിങ്ങളുടെSymbol.iterator
മെത്തേഡ് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളിന് അനുസൃതമായ ഒരു ഇറ്ററേറ്റർ ഒബ്ജക്റ്റ് നൽകുന്നുവെന്ന് ഉറപ്പാക്കുക.done
ഫ്ലാഗ് കൃത്യമായി കൈകാര്യം ചെയ്യുക: ഇറ്ററേഷൻ്റെ അവസാനം സൂചിപ്പിക്കുന്നതിന്done
ഫ്ലാഗ് നിർണായകമാണ്. നിങ്ങളുടെnext()
മെത്തേഡിൽ ഇത് ശരിയായി സജ്ജീകരിച്ചിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക.- ജനറേറ്റർ ഫംഗ്ഷനുകൾ ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക: ജനറേറ്റർ ഫംഗ്ഷനുകൾ ഇറ്ററേറ്ററുകൾ നിർമ്മിക്കുന്നതിന് കൂടുതൽ സംക്ഷിപ്തവും വായിക്കാൻ എളുപ്പമുള്ളതുമായ മാർഗ്ഗം നൽകുന്നു.
next()
-ലെ സൈഡ് എഫക്റ്റുകൾ ഒഴിവാക്കുക:next()
മെത്തേഡ് പ്രധാനമായും അടുത്ത മൂല്യം വീണ്ടെടുക്കുന്നതിലും ഇറ്ററേറ്ററിൻ്റെ സ്റ്റേറ്റ് അപ്ഡേറ്റ് ചെയ്യുന്നതിലും ശ്രദ്ധ കേന്ദ്രീകരിക്കണം.next()
-നുള്ളിൽ സങ്കീർണ്ണമായ പ്രവർത്തനങ്ങളോ സൈഡ് എഫക്റ്റുകളോ ചെയ്യുന്നത് ഒഴിവാക്കുക.- നിങ്ങളുടെ ഇറ്ററേറ്ററുകൾ നന്നായി പരിശോധിക്കുക: നിങ്ങളുടെ കസ്റ്റം ഇറ്ററേറ്ററുകൾ ശരിയായി പ്രവർത്തിക്കുന്നുവെന്ന് ഉറപ്പാക്കാൻ വ്യത്യസ്ത ഡാറ്റാ സെറ്റുകളും സാഹചര്യങ്ങളും ഉപയോഗിച്ച് പരീക്ഷിക്കുക.
ഉപസംഹാരം
ജാവാസ്ക്രിപ്റ്റ് ഇറ്ററേറ്റർ പ്രോട്ടോക്കോൾ ഡാറ്റാ സ്ട്രക്ച്ചറുകളിലൂടെ കടന്നുപോകാൻ ശക്തവും വഴക്കമുള്ളതുമായ ഒരു മാർഗ്ഗം നൽകുന്നു. ഇറ്ററബിൾ, ഇറ്ററേറ്റർ പ്രോട്ടോക്കോളുകൾ മനസ്സിലാക്കുന്നതിലൂടെയും ജനറേറ്റർ ഫംഗ്ഷനുകൾ പ്രയോജനപ്പെടുത്തുന്നതിലൂടെയും നിങ്ങളുടെ നിർദ്ദിഷ്ട ആവശ്യങ്ങൾക്കനുസരിച്ച് കസ്റ്റം ഇറ്ററേറ്ററുകൾ നിർമ്മിക്കാൻ നിങ്ങൾക്ക് കഴിയും. ഇത് ഡാറ്റയുമായി കാര്യക്ഷമമായി പ്രവർത്തിക്കാനും കോഡിൻ്റെ വായനാക്ഷമത മെച്ചപ്പെടുത്താനും നിങ്ങളുടെ ആപ്ലിക്കേഷനുകളുടെ പ്രകടനം വർദ്ധിപ്പിക്കാനും നിങ്ങളെ അനുവദിക്കുന്നു. ഇറ്ററേറ്ററുകളിൽ വൈദഗ്ദ്ധ്യം നേടുന്നത് ജാവാസ്ക്രിപ്റ്റിൻ്റെ കഴിവുകളെക്കുറിച്ചുള്ള ആഴത്തിലുള്ള ധാരണ നൽകുകയും കൂടുതൽ ലളിതവും കാര്യക്ഷമവുമായ കോഡ് എഴുതാൻ നിങ്ങളെ പ്രാപ്തരാക്കുകയും ചെയ്യുന്നു.