जावास्क्रिप्ट फॉरएच विधि का क्या उपयोग है (वह नक्शा नहीं कर सकता है)?


90

केवल एक अंतर जो मैं मानचित्र और फ़ॉरच में देखता हूं, वह mapयह है कि एक सरणी लौटा रहा है और forEachनहीं है। हालाँकि, मैं भी forEachविधि " func.call(scope, this[i], i, this);" की अंतिम पंक्ति को नहीं समझता । उदाहरण के लिए, " this" और " scope" एक ही वस्तु this[i]का iसंदर्भ नहीं है और लूप में वर्तमान मूल्य का उल्लेख नहीं है ?

मैंने किसी अन्य पोस्ट पर ध्यान दिया "किसी ने कहा" forEachजब आप सूची के प्रत्येक तत्व के आधार पर कुछ करना चाहते हैं, तो आप उदाहरण के लिए, पृष्ठ में कुछ चीजें जोड़ सकते हैं। अनिवार्य रूप से, यह बहुत अच्छा है जब आप "साइड इफेक्ट्स" चाहते हैं। मैं नहीं जानता कि साइड इफेक्ट्स का क्या मतलब है।

Array.prototype.map = function(fnc) {
    var a = new Array(this.length);
    for (var i = 0; i < this.length; i++) {
        a[i] = fnc(this[i]);
    }
    return a;
}

Array.prototype.forEach = function(func, scope) { 
    scope = scope || this; 
    for (var i = 0, l = this.length; i < l; i++) {
        func.call(scope, this[i], i, this); 
    } 
}

अंत में, जावास्क्रिप्ट में इन विधियों के लिए कोई वास्तविक उपयोग हैं (क्योंकि हम डेटाबेस को अपडेट नहीं कर रहे हैं) संख्याओं में हेरफेर करने के अलावा:

alert([1,2,3,4].map(function(x){ return x + 1})); //this is the only example I ever see of map in javascript.

किसी भी उत्तर के लिए धन्यवाद।


आप जिस तरह से साथ mapऔर जैसे देशी जावास्क्रिप्ट की एक फ़ंक्शन परिभाषा कैसे पा सकते हैं forEach? मुझे Google से प्राप्त होने वाले सभी उपयोग विनिर्देशों और ट्यूटोरियल हैं।
वुड्रोशिगरु

भाषा-अज्ञेयवादी भी देखें कि क्या फ़र्क और मानचित्र में अंतर है?
बरगी

जवाबों:


94

आपके उदाहरण में mapऔर उसके बीच आवश्यक अंतर यह forEachहै कि forEachमूल सरणी तत्वों पर काम करता है, जबकि mapपरिणामस्वरूप स्पष्ट रूप से एक नया सरणी देता है।

forEachआप के साथ कुछ कार्रवाई कर रहे हैं - और वैकल्पिक रूप से बदल - मूल सरणी में प्रत्येक तत्व। forEachविधि समारोह आप प्रत्येक तत्व के लिए प्रदान करते हैं चलाता है, लेकिन कुछ भी नहीं देता है ( undefined)। दूसरी ओर, mapसरणी के माध्यम से चलता है, प्रत्येक तत्व पर एक फ़ंक्शन लागू करता है , और परिणाम को एक नए सरणी के रूप में उत्सर्जित करता है

के साथ "साइड इफेक्ट" forEachयह है कि मूल सरणी को बदला जा रहा है। "कोई साइड इफेक्ट" का mapअर्थ है कि, मुहावरेदार उपयोग में, मूल सरणी तत्व नहीं बदले जाते हैं; नया सरणी मूल सरणी में प्रत्येक तत्व का एक-से-एक मानचित्रण है - मानचित्रण आपके प्रदान किए गए फ़ंक्शन को परिवर्तित करता है।

तथ्य यह है कि इसमें कोई डेटाबेस शामिल नहीं है इसका मतलब यह नहीं है कि आपको डेटा संरचनाओं पर काम नहीं करना होगा, जो कि आखिरकार, किसी भी भाषा में प्रोग्रामिंग के निबंधों में से एक है। आपके अंतिम प्रश्न के लिए, आपके सरणी में न केवल संख्याएं हो सकती हैं, बल्कि ऑब्जेक्ट्स, स्ट्रिंग्स, फ़ंक्शंस आदि भी हो सकते हैं।


4
भविष्य से ध्यान दें: यह उत्तर वास्तव में बकवास है; .mapकर सकते हैं सब कुछ .forEachकर सकते हैं (तत्वों को संशोधित करने सहित), यह सिर्फ इट्रेटर फ़ंक्शन से निर्मित एक नई सूची देता है।
ट्रैविस वेब

6
अतीत से प्रतिक्रिया: मैं सम्मानपूर्वक असहमत हूं। .map()एक नया सरणी बनाता है, और मूल को परिवर्तित नहीं करता है। आप उस सरणी को वास्तव में संशोधित कर सकते हैं जो स्वयं मैप किया जा रहा है, लेकिन यह बहुत कम से कम गैर-मुहावरेदार होगा, यदि निरर्थक नहीं। .forEach(), जबकि समान है, प्रत्येक तत्व पर अपना फ़ंक्शन लागू करता है, लेकिन हमेशा रिटर्न करता है undefined। उपरोक्त सभी के बावजूद, ओपी ऐरे प्रोटोटाइप में जोड़े गए अपने स्वयं के विशिष्ट कार्यों के बारे में भी पूछ रहा है; अतीत में यहाँ कोई ES5 नहीं था।
केन रेडलर

4
अभी भी ऐसा कुछ भी नहीं forEachहै जो आप नहीं कर सकते map। आप आसानी से वापसी मूल्य के बारे में परवाह नहीं कर सकते हैं mapऔर आपके पास एक होगा forEach। अंतर यह है कि यह mapउन कार्यों के लिए उपयोग करने के लिए अप्रभावी है जहां आप परिणामों के आधार पर एक नया सरणी नहीं बनाना चाहते हैं। तो उन लोगों के लिए, आप का उपयोग करें forEach
प्रहार करें

2
@ प्रहार: .. और इसी तरह, आप एक पुराने पुराने forलूप के साथ जो कुछ भी कर सकते हैं, वह कर सकते हैं । मैं इस बात से असहमत नहीं हूं कि "प्रभावशीलता" में कुछ अंतर है, लेकिन मैं यह भी नहीं सोचता कि किसी का तर्क है कि किसी के पास कुछ जादू है जो किसी भी तरह हासिल कर सकता है। हालाँकि, वास्तव में, एक काम जो mapनहीं कर सकता है: एक सरणी वापस नहीं। वहाँ जे एस की तरह कार्यात्मक पसंदीदा के व्यवहार के रूप में अन्य भाषाओं से अपेक्षाओं पर खरा उतरने होने में मूल्य है map, reduce, filter, आदि जैसे, आप को लागू कर सकता है reduceRightइसी तरह की इमारत ब्लॉकों का उपयोग कर, लेकिन क्यों बस का उपयोग नहीं reduceRight?
केन रेडलर

1
@ChinotoVokro, आपका उदाहरण स्पष्ट रूप से b.val = b.val**2 दिए गए ऑब्जेक्ट के अंदर असाइन करके मूल सरणी को बदल रहा है । यह सटीक बात है जो हम कह रहे हैं कि यह वास्तव में संभव है, लेकिन भ्रामक और गैर-मुहावरेदार है। आम तौर पर आप बस नया मान लौटाते हैं, इसे मूल सारणी में भी निर्दिष्ट नहीं करते हैं:a=[{val:1},{val:2},{val:3},{val:4}]; a.map((b)=>{b.val**2}); JSON.stringify(a);
केन रेडलर

66

दो तरीकों के बीच मुख्य अंतर यह वैचारिक और शैलीगत है: आप का उपयोग forEachजब आप कुछ करना चाहता हूँ करने के लिए या के साथ एक सरणी के प्रत्येक तत्व ( "के साथ" क्या आप जिस पोस्ट "दुष्प्रभाव" का मतलब उद्धृत करते हैं, मुझे लगता है कि है) , जबकि आप उपयोग mapकरते हैं जब आप किसी सरणी के प्रत्येक तत्व को कॉपी करना और बदलना चाहते हैं (मूल को बदले बिना)।

क्योंकि दोनों mapऔर forEachएक सरणी में प्रत्येक आइटम पर एक समारोह फोन, और कहा कि समारोह उपयोगकर्ता परिभाषित है, वहाँ लगभग कुछ भी नहीं आप एक और नहीं अन्य के साथ साथ कर सकते है। यह संभव है, हालांकि, mapकिसी सरणी में जगह को संशोधित करने और / या सरणी तत्वों के साथ कुछ करने के लिए उपयोग करना बदसूरत है :

var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.map(function(el) {
    el.val++; // modify element in-place
    alert(el.val); // do something with each element
});
// a now contains [{ val: 2 }, { val: 3 }, { val: 4 }]

लेकिन उपयोग करने के अपने इरादे के रूप में बहुत क्लीनर और अधिक स्पष्ट forEach:

var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.forEach(function(el) { 
    el.val++;
    alert(el.val);
});

खासकर यदि, जैसा कि आमतौर पर वास्तविक दुनिया में होता है, elएक उपयोगी मानव-पठनीय चर है:

cats.forEach(function(cat) { 
    cat.meow(); // nicer than cats[x].meow()
});

उसी तरह, आप आसानी से forEachएक नया सरणी बनाने के लिए उपयोग कर सकते हैं :

var a = [1,2,3],
    b = [];
a.forEach(function(el) { 
    b.push(el+1); 
});
// b is now [2,3,4], a is unchanged

लेकिन इसका उपयोग करने के लिए क्लीनर है map:

var a = [1,2,3],
    b = a.map(function(el) { 
        return el+1; 
    });

ध्यान दें कि, क्योंकि mapएक नया सरणी बनाता है, यह संभावना है कि कम से कम कुछ प्रदर्शन / मेमोरी हिट होता है जब आपको सभी आवश्यक पुनरावृत्तियों की आवश्यकता होती है, विशेष रूप से बड़े सरणियों के लिए - देखें http://jsperf.com/map-foreach

जैसा कि आप इन कार्यों का उपयोग क्यों करना चाहते हैं, वे किसी भी समय आपको जावास्क्रिप्ट में सरणी हेरफेर करने में मदद करने की आवश्यकता होती है, जो (भले ही हम सिर्फ एक ब्राउज़र वातावरण में जावास्क्रिप्ट के बारे में बात कर रहे हों) बहुत बार, लगभग किसी भी समय होता है आप एक ऐसे कोड तक पहुंच रहे हैं जिसे आप अपने कोड में हाथ से नहीं लिख रहे हैं। आप पृष्ठ पर DOM तत्वों की एक सरणी के साथ काम कर रहे हैं, या AJAX अनुरोध से खींचा गया डेटा, या उपयोगकर्ता द्वारा एक रूप में दर्ज किया गया डेटा हो सकता है। मेरे द्वारा चलाया जाने वाला एक सामान्य उदाहरण बाहरी API से डेटा खींच रहा है, जहाँ आप mapडेटा को अपने इच्छित प्रारूप में बदलने के लिए उपयोग करना चाहते हैं और फिर forEachअपने उपयोगकर्ता को प्रदर्शित करने के लिए अपने नए सरणी पर पुनरावृति करने के लिए उपयोग कर सकते हैं।


मैं .map()इनलाइन तत्वों को संशोधित करने के लिए हर समय उपयोग करने वाले लोगों को देखता हूं । मैं इस धारणा के अधीन था कि .map.forEach
6

1
@chovy मेरा मानना ​​है कि आपको इस आधार पर चयन करना चाहिए कि क्या आप परिणामों की एक सरणी बनाना चाहते हैं। .mapतत्वों को संशोधित कर सकते हैं, हाँ, लेकिन यह एक ऐसा सरणी बनाएगा जिसकी आपको आवश्यकता नहीं है। आपको यह भी विचार करना चाहिए कि एक या दूसरे को कैसे चुनना पाठक को यह अनुमान लगाने देता है कि आपके साइड-इफेक्ट्स हैं या नहीं
leewz

16

मतदान का जवाब (केन रेडर से) भ्रामक है।

कंप्यूटर विज्ञान में एक साइड इफेक्ट का मतलब है कि एक फ़ंक्शन / पद्धति की एक संपत्ति एक वैश्विक स्थिति [विकी] को बदल देती है । कुछ संकीर्ण अर्थों में, इसमें तर्कों के बजाय वैश्विक स्थिति से पढ़ना भी शामिल हो सकता है। अनिवार्य या OO प्रोग्रामिंग में, साइड इफेक्ट ज्यादातर समय दिखाई देते हैं। और आप बिना एहसास के शायद इसका उपयोग कर रहे हैं।

के बीच significiant अंतर forEachऔर mapवह यह है कि map, जबकि आबंटित स्मृति और दुकानों लौटने मूल्य forEachइसे फेंक देता है। अधिक जानकारी के लिए emca कल्पना देखें ।

इस कारण से कि लोग कहते हैं कि forEachजब आप साइड इफेक्ट चाहते हैं तो इसका उपयोग किया जाता forEachहै undefined। यदि इसका कोई साइड इफेक्ट नहीं है (वैश्विक स्थिति में बदलाव नहीं होता है), तो फ़ंक्शन केवल सीपीयू समय बर्बाद कर रहा है। एक अनुकूलन कंपाइलर इस कोड ब्लॉक को खत्म कर देगा और इसे अंतिम मूल्य ( undefined) के साथ बदल देगा ।

वैसे, यह ध्यान दिया जाना चाहिए कि जावास्क्रिप्ट का साइड इफेक्ट पर कोई प्रतिबंध नहीं है। आप अभी भी मूल सरणी को अंदर संशोधित कर सकते हैं map

var a = [1,2,3]; //original
var b = a.map( function(x,i){a[i] = 2*x; return x+1} );
console.log("modified=%j\nnew array=%j",a,b);
// output:
// modified=[2,4,6]
// new array=[2,3,4]

1
यह सवाल और इसके उत्तर और टिप्पणियां हमेशा हर दो साल में वापस सर्कल करने के लिए मजेदार हैं। स्मृति आवंटन के संदर्भ में जेएस में जिस तरह से नक्शा लागू किया गया है, वह एक और अच्छा कोण है।
केन रेडलर

6

यह एक अप्रत्याशित जवाब के साथ एक सुंदर सवाल है।

निम्नलिखित आधिकारिक विवरणArray.prototype.map() पर आधारित है

ऐसा कुछ भी नहीं है जो forEach()ऐसा map()नहीं कर सकता है। यानी, map()एक सख्त सुपर-सेट है forEach()

हालाँकि map()आमतौर पर एक नई सरणी बनाने के लिए उपयोग किया जाता है, लेकिन इसका उपयोग वर्तमान सरणी को बदलने के लिए भी किया जा सकता है। निम्न उदाहरण यह दिखाता है:

var a = [0, 1, 2, 3, 4], mapped = null;
mapped = a.map(function (x) { a[x] = x*x*x; return x*x; });
console.log(mapped); // logs [0, 1, 4, 9, 16]  As expected, these are squares.
console.log(a); // logs [0, 1, 8, 27, 64] These are cubes of the original array!!

उपरोक्त उदाहरण में, aआसानी से इस तरह के a[i] === iलिए निर्धारित किया गया था i < a.length। फिर भी, यह उस शक्ति को प्रदर्शित करता है map(), और विशेष रूप से इसकी सरणी को बदलने की क्षमता है, जिस पर इसे कहा जाता है।

नोट 1:
आधिकारिक विवरण का अर्थ है कि map()यह उस लंबाई को भी बदल सकता है जिस पर इसे कहा जाता है! हालाँकि, मैं ऐसा करने के लिए (एक अच्छा) कारण नहीं देख सकता।

नोट 2:
जबकि map()नक्शा एक सुपर-सेट है forEach(), forEach()फिर भी इसका उपयोग किया जाना चाहिए , जहां कोई एक दिए गए सरणी को बदलने की इच्छा रखता है। इससे आपके इरादे साफ होते हैं।

आशा है कि इससे मदद मिली।


8
वास्तव में वहाँ 1 बात यह है कि forAach कर सकता है कि नक्शा नहीं कर सकता है - एक सरणी वापस नहीं।
अंती हापाला

1
आप लक्षित सरणी को बदलने के लिए मैपिंग फ़ंक्शन के तीसरे तर्क का उपयोग कर सकते हैं, बजाय mapped = a.map(function (x, i, arr) { arr[i] = x * x * x; return x * x; });.
स्कूप किए गए

@ pdoherty926 सच है, लेकिन ऐसा हो सकता है a.forEach(function(x, i, arr) { ..., जो, फिर से, एक वैचारिक रूप से अधिक सही तरीका है, जब आप प्रत्येक मूल वस्तु को म्यूट करने का इरादा रखते हैं जैसा कि एक सरणी से दूसरे में मानचित्र मानों के विपरीत है
5:25

@conny: सहमत हैं। इसके अलावा, कृपया इस उत्तर को , एक समान प्रश्न पर देखें।
सुमुख बर्वे

3

आप का उपयोग कर सकते हैं mapजैसे कि यह थे forEach

हालाँकि, इससे अधिक करना होगा।

scopeएक मनमानी वस्तु हो सकती है; यह जरूरी नहीं है this

के लिए के रूप में वहाँ के लिए वास्तविक उपयोग कर रहे हैं mapऔर forEach, के रूप में अच्छी तरह से forया whileछोरों के लिए वास्तविक उपयोग कर रहे हैं पूछने के लिए ।


लेकिन "स्कोप" और "इस" दोनों को यहां क्यों बुलाया जा रहा है: func.call (स्कोप, यह [i], i, यह); क्या एक पैरामीटर नहीं है जो वर्तमान वस्तु के बराबर है, जो "यह" है?
जॉनमेरिनो

नहीं, यह वर्तमान वस्तु के बराबर हो सकता है। ऑब्जेक्ट स्वयं सरणी के तीसरे पैरामीटर के रूप में पारित किया गया है। scope = scope || thisका अर्थ है "यदि scopeमिथ्या है (अपरिभाषित, अशक्त, असत्य, आदि) thisइसके बजाय गुंजाइश निर्धारित करें और आगे बढ़ें"।
वुम्बलटन

क्या आप मुझे एक उदाहरण से जोड़ सकते हैं जब यह इसके बराबर नहीं है?
जॉनमेरलिनो

developer.mozilla.org/en/Core_JavaScript_1.5_Reference/... पास एक "वस्तु विधि के साथ एक सरणी की सामग्री को प्रिंट करना" है
wombleton

1

जबकि पिछले सभी प्रश्न सही हैं, मैं निश्चित रूप से एक अलग अंतर बनाऊंगा। के उपयोग mapऔर forEachइरादे का मतलब कर सकते हैं।

मैं mapतब उपयोग करना पसंद करता हूं जब मैं किसी तरह से मौजूदा डेटा को बदल रहा हूं (लेकिन यह सुनिश्चित करना चाहता हूं कि मूल डेटा अपरिवर्तित हो।

forEachजब मैं जगह में संग्रह को संशोधित कर रहा हूं तो मुझे उपयोग करना पसंद है।

उदाहरण के लिए,

var b = [{ val: 1 }, { val: 2 }, { val: 3 }];
var c = b.map(function(el) {
    return { val: el.val + 1 }; // modify element in-place
});
console.log(b);
//  [{ val: 1 }, { val: 2 }, { val: 3 }]
console.log(c);
//  [{ val: 3 }, { val: 4 }, { val: 5 }]

अंगूठे का मेरा नियम यह सुनिश्चित करता है कि जब आप mapहमेशा स्रोत सूची के प्रत्येक तत्व के लिए वापस जाने के लिए कुछ नया ऑब्जेक्ट / मान बना रहे हैं और प्रत्येक तत्व पर कुछ ऑपरेशन करने के बजाय इसे वापस कर रहे हैं।

जब तक आपको मौजूदा सूची को संशोधित करने की कोई वास्तविक आवश्यकता नहीं है, तब तक वास्तव में इसे जगह में संशोधित करने का कोई मतलब नहीं है, और कार्यात्मक / अपरिवर्तनीय प्रोग्रामिंग शैलियों में बेहतर फिट बैठता है।


1

टीएल; डीआर उत्तर -

नक्शा हमेशा एक और सरणी देता है।

forach नहीं है। यह आपको तय करना है कि वह क्या करता है। यदि आप चाहें तो एक सरणी लौटाएँ या कुछ और न करें।

लचीलापन वांछनीय है कुछ स्थितियों। यदि यह आपके साथ काम नहीं कर रहा है तो मानचित्र का उपयोग करें।


0

एक बार फिर, मैं एक नेक्रोमन्ट की तरह महसूस करता हूं, जो 5 साल पहले पूछे गए एक सवाल का जवाब देता है (खुशी से हाल ही में गतिविधि हुई है, इसलिए मैं केवल एक मृत व्यक्ति को परेशान नहीं कर रहा हूं :)।

अन्य लोगों ने पहले से ही कार्यों के बीच अंतर के बारे में आपके मुख्य प्रश्न के बारे में पोस्ट किया है। लेकिन के लिए...

जावास्क्रिप्ट में इन विधियों के लिए कोई वास्तविक उपयोग हैं (क्योंकि हम डेटाबेस को अपडेट नहीं कर रहे हैं) इस तरह की संख्याओं में हेरफेर करने के अलावा:

... यह मजेदार है जो आपको पूछना चाहिए। आज ही मैंने एक कोड ऑफ कोड लिखा है जो एक नियमित अभिव्यक्ति से कई रूपांतरणों के लिए मानचित्र का उपयोग करके कई चर के लिए कई मान प्रदान करता है। इसका उपयोग बहुत जटिल पाठ आधारित संरचना को दृश्यमान डेटा में परिवर्तित करने के लिए किया गया था ... लेकिन सादगी के लिए, मैं तारीख के तार का उपयोग करके एक उदाहरण पेश करूंगा, क्योंकि वे शायद सभी के लिए अधिक परिचित हैं (हालांकि, अगर मेरी समस्या वास्तव में तारीखों के साथ थी नक्शे के बजाय मैंने डेट-ऑब्जेक्ट का उपयोग किया होगा, जिसने अपने दम पर शानदार ढंग से काम किया होगा)।

const DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z$/;
const TEST_STRING = '2016-01-04T03:20:00.000Z';

var [
    iYear,
    iMonth,
    iDay,
    iHour,
    iMinute,
    iSecond,
    iMillisecond
    ] = DATE_REGEXP
        // We take our regular expression and...
        .exec(TEST_STRING)
        // ...execute it against our string (resulting in an array of matches)...
        .slice(1)
        // ...drop the 0th element from those (which is the "full string match")...
        .map(value => parseInt(value, 10));
        // ...and map the rest of the values to integers...

// ...which we now have as individual variables at our perusal
console.debug('RESULT =>', iYear, iMonth, iDay, iHour, iMinute, iSecond, iMillisecond);

तो ... जबकि यह सिर्फ एक उदाहरण था - और केवल डेटा के लिए एक बहुत ही बुनियादी परिवर्तन किया था (उदाहरण के लिए) ... बिना मानचित्र के ऐसा करने से यह बहुत अधिक कठिन काम हो सकता था।

दी, यह जावास्क्रिप्ट के एक संस्करण में लिखा गया है कि मुझे नहीं लगता कि बहुत सारे ब्राउज़र अभी तक (कम से कम पूरी तरह से) समर्थन करते हैं लेकिन हम वहां पहुंच रहे हैं। अगर मुझे इसे ब्राउज़र में चलाने की आवश्यकता है, तो मेरा मानना ​​है कि यह अच्छी तरह से ट्रांसपाइल होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.