फ़ंक्शन फ़ंक्शन नाम का उपयोग क्यों करें?


92

जावास्क्रिप्ट में फ़ंक्शन अभिव्यक्ति करने के लिए हमारे पास दो अलग-अलग तरीके हैं:

नामित फ़ंक्शन अभिव्यक्ति (NFE) :

var boo = function boo () {
  alert(1);
};

अनाम फ़ंक्शन अभिव्यक्ति :

var boo = function () {
  alert(1);
};

और दोनों को साथ बुलाया जा सकता है boo();। मैं वास्तव में यह नहीं देख सकता कि मुझे अनाम फ़ंक्शन का उपयोग क्यों करना चाहिए / और जब मुझे नामांकित फ़ंक्शन अभिव्यक्तियों का उपयोग करना चाहिए। उनमें क्या अंतर है?


जवाबों:


85

अनाम फ़ंक्शन अभिव्यक्ति के मामले में, फ़ंक्शन अनाम है  - शाब्दिक रूप से, इसका कोई नाम नहीं है। जिस वेरिएबल पर आप इसे असाइन कर रहे हैं उसका नाम है, लेकिन फ़ंक्शन नहीं करता है। (अपडेट: यह ES5 के माध्यम से सच था। ES2015 [उर्फ ES6] के रूप में, अक्सर एक अनाम अभिव्यक्ति के साथ बनाए गए एक फ़ंक्शन को एक सही नाम मिलता है [लेकिन एक स्वचालित पहचानकर्ता नहीं]], पढ़ें ...)

नाम उपयोगी हैं। नामों को स्टैक के निशान, कॉल स्टैक्स, ब्रेकप्वाइंट की सूची आदि में देखा जा सकता है। नाम एक अच्छा चीज है।

(आपको IE [IE8 और उससे नीचे] के पुराने संस्करणों में नामित फ़ंक्शन अभिव्यक्तियों से सावधान रहना पड़ता था, क्योंकि उन्होंने गलती से दो पूरी तरह से अलग-अलग फ़ंक्शन ऑब्जेक्ट दो पूरी तरह से अलग-अलग समय पर बनाए थे [मेरे ब्लॉग के लेख में डबल ले ]। IE8 [!!] का समर्थन करें, यह संभवतः अनाम फ़ंक्शन एक्सप्रेशन या फ़ंक्शन घोषणाओं के साथ चिपकना सबसे अच्छा है , लेकिन फ़ंक्शन फ़ंक्शन नाम से बचें।)

नामित फ़ंक्शन अभिव्यक्ति के बारे में एक महत्वपूर्ण बात यह है कि यह फंक्शनलन बॉडी के भीतर फ़ंक्शन के लिए उस नाम के साथ एक इन-स्कोप पहचानकर्ता बनाता है:

var x = function example() {
    console.log(typeof example); // "function"
};
x();
console.log(typeof example);     // "undefined"

ES2015 के अनुसार, हालांकि, बहुत सारे "अनाम" फ़ंक्शन एक्सप्रेशन नाम के साथ फ़ंक्शन करते हैं, और यह विभिन्न आधुनिक जावास्क्रिप्ट इंजनों द्वारा पूर्वनिर्धारित किया गया था जो संदर्भ से नामों का उल्लेख करने के बारे में काफी स्मार्ट थे। ES2015 में, आपकी अनाम फ़ंक्शन अभिव्यक्ति का नाम के साथ एक फ़ंक्शन होता है boo। हालाँकि, ES2015 + शब्दार्थ के साथ भी, स्वचालित पहचानकर्ता नहीं बनाया गया है:

var obj = {
    x: function() {
       console.log(typeof x);   // "undefined"
       console.log(obj.x.name); // "x"
    },
    y: function y() {
       console.log(typeof y);   // "function"
       console.log(obj.y.name); // "y"
    }
};
obj.x();
obj.y();

फ़ंक्शन के नाम के लिए असाइनमेंट सेटफ़ंक्शननाम एब्स्ट्रैक्ट ऑपरेशन के साथ किया जाता है जिसका उपयोग कल्पना में विभिन्न कार्यों में किया जाता है।

लघु संस्करण मूल रूप से किसी भी समय एक अनाम फ़ंक्शन एक्सप्रेशन है जो किसी असाइनमेंट या इनिशियलाइज़ेशन जैसी किसी चीज़ के दाईं ओर दिखाई देता है, जैसे:

var boo = function() { /*...*/ };

(या यह हो सकता है letया के constबजाय var) , या

var obj = {
    boo: function() { /*...*/ }
};

या

doSomething({
    boo: function() { /*...*/ }
});

(वे अंतिम दो वास्तव में एक ही बात हैं) , परिणामी फ़ंक्शन का एक नाम होगा ( booउदाहरणों में)।

एक महत्वपूर्ण, और जानबूझकर, अपवाद है: एक मौजूदा वस्तु पर एक संपत्ति को सौंपना:

obj.boo = function() { /*...*/ }; // <== Does not get a name

इसकी वजह यह थी कि जब नया फीचर जोड़ा जाने की प्रक्रिया से गुजर रहा था, तब सूचना लीक की चिंता बढ़ गई थी; एक और सवाल करने के लिए अपने जवाब में विवरण यहाँ


1
यह ध्यान देने योग्य है कि कम से कम दो जगहें हैं जिनमें एनएफई का उपयोग करना अभी भी ठोस लाभ देता है: सबसे पहले, newऑपरेटर के माध्यम से कंस्ट्रक्टर के रूप में उपयोग किए जाने वाले कार्यों के लिए, ऐसे सभी कार्यों को नाम देना .constructorसंपत्ति के डीबगिंग के दौरान संपत्ति को अधिक उपयोगी बनाता है जो कि बिल्ली को लगाते हैं। कुछ ऑब्जेक्ट का एक उदाहरण है), और फ़ंक्शन के लिए शाब्दिक सीधे एक फ़ंक्शन में पारित हो जाते हैं, पहली बार किसी संपत्ति या चर (जैसे setTimeout(function () {/*do stuff*/});) को सौंपे बिना । यहां तक ​​कि क्रोम इन्हें (anonymous function)तब तक दिखाता है जब तक आप इसका नामकरण करके इसकी मदद नहीं करते हैं।
मार्क अमेरी

4
@MarkAmery: "क्या यह अभी भी सही है? मैंने ... इन नियमों के लिए CTRL-F की कोशिश की और उन्हें" ओह हाँ नहीं मिला :-) यह नियमों के एक सेट को परिभाषित करने के स्थान पर पूरे युक्ति में बिखरा हुआ है, बस "setFunctionName" खोजें। मैंने ऊपर दिए गए लिंक का एक छोटा सबसेट जोड़ा है, लेकिन यह वर्तमान में ~ 29 विभिन्न स्थानों पर दिखाई देता है। अगर आपके setTimeoutउदाहरण के लिए घोषित औपचारिक तर्क से नाम नहीं पकड़ा गया तो मुझे केवल हल्का आश्चर्य होगा setTimeout। :-) लेकिन हाँ, NFE निश्चित रूप से उपयोगी हैं यदि आप जानते हैं कि आप पुराने ब्राउज़रों के साथ काम नहीं करेंगे जो उनमें से एक हैश बनाते हैं।
टीजे क्राउडर

24

यदि वे स्वयं को संदर्भित करना चाहते हैं, तो नामकरण कार्य उपयोगी है (उदाहरण के लिए पुनरावर्ती कॉल)। वास्तव में, यदि आप किसी दूसरे फ़ंक्शन के तर्क के रूप में शाब्दिक फ़ंक्शन एक्सप्रेशन पास कर रहे हैं, तो वह फ़ंक्शन एक्सप्रेशन सीधे ES5 सख्त मोड में स्वयं का संदर्भ नहीं दे सकता है जब तक कि उसका नाम न हो।

उदाहरण के लिए, इस कोड पर विचार करें:

setTimeout(function sayMoo() {
    alert('MOO');
    setTimeout(sayMoo, 1000);
}, 1000);

यदि फ़ंक्शन अभिव्यक्ति setTimeoutअनाम हो गई थी, तो इस कोड को काफी सफाई से लिखना असंभव होगा ; हमें setTimeoutकॉल करने से पहले इसे एक वैरिएबल पर असाइन करना होगा । एक नामित फ़ंक्शन अभिव्यक्ति के साथ यह तरीका थोड़ा कम और नटकार है।

ऐतिहासिक समारोह अभिव्यक्ति का उपयोग करके इस तरह से कोड लिखना ऐतिहासिक रूप से संभव था, शोषण से arguments.callee...

setTimeout(function () {
    alert('MOO');
    setTimeout(arguments.callee, 1000);
}, 1000);

... लेकिन arguments.calleeपदावनत है, और ES5 सख्त मोड में एकमुश्त निषिद्ध है। इसलिए MDN सलाह देता है:

फ़ंक्शन अभिव्यक्तियों को नाम देने से उपयोग करने arguments.callee()से बचें या फ़ंक्शन घोषणा का उपयोग करें जहां फ़ंक्शन को स्वयं कॉल करना होगा।

(जोर मेरा)


3

यदि फ़ंक्शन फ़ंक्शन अभिव्यक्ति के रूप में निर्दिष्ट किया जाता है, तो इसे एक नाम दिया जा सकता है।

यह केवल फ़ंक्शन (IE8- को छोड़कर) के अंदर उपलब्ध होगा।

var f = function sayHi(name) {
  alert( sayHi ); // Inside the function you can see the function code
};

alert( sayHi ); // (Error: undefined variable 'sayHi')

यह नाम एक विश्वसनीय पुनरावर्ती फ़ंक्शन कॉल के लिए अभिप्रेत है, भले ही वह किसी अन्य चर के लिए लिखा गया हो।

इसके अलावा, NFE (नामांकित फ़ंक्शन अभिव्यक्ति) का नाम Object.defineProperty(...)इस प्रकार से विधि के साथ ओवरराइट किया जा सकता है:

var test = function sayHi(name) {
  Object.defineProperty(test, 'name', { value: 'foo', configurable: true });
  alert( test.name ); // foo
};

test();

नोट: कि फ़ंक्शन घोषणा के साथ ऐसा नहीं किया जा सकता है। यह "विशेष" आंतरिक फ़ंक्शन नाम केवल फ़ंक्शन एक्सप्रेशन सिंटैक्स में निर्दिष्ट है।


2

आपको हमेशा फ़ंक्शन फ़ंक्शन नाम का उपयोग करना चाहिए , इसीलिए:

  1. पुनरावृत्ति की आवश्यकता होने पर आप उस फ़ंक्शन के नाम का उपयोग कर सकते हैं।

  2. जब आप फ़ंक्शन के नाम को समस्या का कारण नहीं देख सकते हैं, तो अनाम फ़ंक्शंस मदद नहीं करते हैं।

  3. जब आप एक फ़ंक्शन का नाम नहीं देते हैं, तो बाद में यह समझने के लिए कि यह क्या कर रहा है, कठिन है। इसे एक नाम देने से समझने में आसानी होती है।

var foo = function bar() {
    //some code...
};

foo();
bar(); // Error!

यहां, उदाहरण के लिए, क्योंकि नाम पट्टी का उपयोग एक फ़ंक्शन अभिव्यक्ति के भीतर किया जाता है, यह बाहरी दायरे में घोषित नहीं किया जाता है। फंक्शन एक्सप्रेशन के साथ, फंक्शन एक्सप्रेशन का नाम अपने स्वयं के दायरे में संलग्न है।


1

नामित फ़ंक्शन अभिव्यक्तियों का उपयोग करना बेहतर होता है, जब आप इस तरह के पदावनत सुविधाओं पर भरोसा किए बिना फ़ंक्शन को संदर्भ में सक्षम करना चाहते हैं arguments.callee


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