JavaScript में call और apply: शीर्ष गलतियाँ और उनसे कैसे बचें
\n\nक्या आपने कभी JavaScript में किसी और का कोड देखा है और func.call(this, arg1, arg2) या func.apply(this, [arg1, arg2]) जैसी अजीब संरचनाएँ देखी हैं? और सोचा है: "वास्तव में, इसमें क्या अंतर है?" यदि हाँ — तो आप अकेले नहीं हैं। प्रश्न "call और apply में क्या अंतर है?" — Stack Overflow पर सैकड़ों हज़ारों व्यूज़ के साथ सबसे लोकप्रिय प्रश्नों में से एक है। और यह कोई संयोग नहीं है।
call और apply के बीच भ्रम — शुरुआती (और केवल उन्हीं के लिए नहीं) के लिए एक क्लासिक जाल है। इस लेख में हम केवल सिद्धांत नहीं बताएँगे। हम शीर्ष-5 वास्तविक गलतियों का विश्लेषण करेंगे, दिखाएँगे कि उन्हें कैसे ठीक किया जाए, और एक स्पष्ट एल्गोरिदम देंगे जो आपको हमेशा के लिए भ्रम से मुक्त कर देगा। चलिए शुरू करते हैं!
संक्षिप्त परिचय: call और apply क्या हैं?
\n\nगलतियों में गोता लगाने से पहले, आइए बुनियादी बातों को ताज़ा करें। call और apply विधियाँ JavaScript में फ़ंक्शन की अंतर्निहित विधियाँ हैं। उनका मुख्य कार्य फ़ंक्शन के लिए स्पष्ट रूप से कॉल संदर्भ (this) निर्दिष्ट करना है। दूसरे शब्दों में, वे यह कहने की अनुमति देते हैं: "अरे, फ़ंक्शन, कल्पना करो कि तुम इस ऑब्जेक्ट के साथ काम कर रहे हो"।
सिंटैक्स:
\n\nfunc.call(context, arg1, arg2, ...);\nfunc.apply(context, [arg1, arg2, ...]);\n\nमुख्य अंतर:
\n- \n
callआर्गुमेंट को अल्पविराम से अलग करके (सूची के रूप में) लेता है। \n applyआर्गुमेंट को एक सरणी (या सरणी-जैसी ऑब्जेक्ट) के रूप में लेता है। \n
बस इतना ही। यही एकमात्र अंतर है। लेकिन इसी "मामूली बात" के कारण अधिकांश गलतियाँ होती हैं। आइए उनका विश्लेषण करें।
\n\ncall और apply के साथ काम करते समय शीर्ष-5 गलतियाँ
\n\nगलती #1: आर्गुमेंट सूची में भ्रम (सबसे आम!)
\n\nयह सभी गलतियों का "राजा" है। आपने एक फ़ंक्शन लिखा है जो एक-एक करके आर्गुमेंट की अपेक्षा करता है, लेकिन आपने call के माध्यम से एक सरणी पास कर दी। या इसके विपरीत।
आपदा का उदाहरण:
\n\nfunction greet(greeting, punctuation) {\n console.log(greeting + ', ' + this.name + punctuation);\n}\n\nconst user = { name: 'अन्ना' };\n\n// गलती: सरणी पास कर रहे हैं, लेकिन call का उपयोग कर रहे हैं\ngreet.call(user, ['नमस्ते', '!']); \n// आउटपुट: "नमस्ते,! अन्ना,undefined" — पूरी तरह बकवास!\n\nऐसा क्यों? call एक-एक करके आर्गुमेंट की अपेक्षा करता है। इसे एक आर्गुमेंट मिला — एक पूरी सरणी — और इसे वेरिएबल greeting में रख दिया। punctuation undefined रह गया।
कैसे ठीक करें? यदि डेटा पहले से सरणी में है तो apply का उपयोग करें:
greet.apply(user, ['नमस्ते', '!']); \n// आउटपुट: "नमस्ते, अन्ना!" — सही!\n\nया स्प्रेड ऑपरेटर (आधुनिक तरीका) के माध्यम से सरणी को फैलाएँ:
\n\ngreet.call(user, ...['नमस्ते', '!']); \n// यह भी काम करता है!\n\nगलती #2: भूल जाना कि apply सरणी-जैसी ऑब्जेक्ट के साथ काम करता है
\n\nबहुत से लोग सोचते हैं कि apply केवल वास्तविक सरणी स्वीकार करता है। वास्तव में, यह किसी भी सरणी-जैसी ऑब्जेक्ट (array-like object) को स्वीकार करता है: इसमें एक length गुण और संख्यात्मक कुंजियाँ होनी चाहिए।
उदाहरण:
\n\nfunction sum() {\n let total = 0;\n for (let i = 0; i < arguments.length; i++) {\n total += arguments[i];\n }\n return total;\n}\n\n// सरणी नहीं, बल्कि length वाली ऑब्जेक्ट पास कर रहे हैं\nconst args = { 0: 5, 1: 10, 2: 15, length: 3 };\n\nconsole.log(sum.apply(null, args)); // आउटपुट: 30 — काम करता है!\n\nलेकिन सावधान रहें: यदि ऑब्जेक्ट में length नहीं है, तो apply इसे अनदेखा कर देगा। arguments (पुरानी ऑब्जेक्ट) या NodeList के साथ काम करते समय यह एक सामान्य गलती है।
गलती #3: call/apply का उपयोग वहाँ जहाँ सामान्य कॉल पर्याप्त हो
\n\nकभी-कभी शुरुआती लोग इसका दुरुपयोग करते हैं