समझाया गया अनाम फ़ंक्शन सिंटैक्स समझाएं


372

सारांश

क्या आप जावास्क्रिप्ट में एन्कैप्सुलेटेड अनाम फ़ंक्शंस के लिए सिंटैक्स के पीछे तर्क को समझा सकते हैं? क्यों काम करता है: (function(){})();लेकिन यह नहीं करता है: function(){}();?


क्या मुझे पता है

जावास्क्रिप्ट में, एक इस तरह एक नामित समारोह बनाता है:

function twoPlusTwo(){
    alert(2 + 2);
}
twoPlusTwo();

आप एक अनाम फ़ंक्शन भी बना सकते हैं और इसे एक चर में असाइन कर सकते हैं:

var twoPlusTwo = function(){
    alert(2 + 2);
};
twoPlusTwo();

आप एक अनाम फ़ंक्शन बनाकर कोड के एक ब्लॉक को अलग कर सकते हैं, फिर इसे कोष्ठक में लपेटकर तुरंत निष्पादित कर सकते हैं:

(function(){
    alert(2 + 2);
})();

मॉड्युलराइज्ड स्क्रिप्ट्स बनाते समय यह उपयोगी है, वर्तमान स्कोप या ग्लोबल स्कोप को अव्यवस्थित करने से बचने के लिए, संभावित परस्पर विरोधी चर के साथ - जैसे कि ग्रीसेमनीक स्क्रिप्ट, jQuery प्लगइन्स, आदि के मामले में।

अब, मैं समझता हूं कि यह क्यों काम करता है। कोष्ठक सामग्री को संलग्न करते हैं और केवल परिणाम को उजागर करते हैं (मुझे यकीन है कि इसका वर्णन करने का एक बेहतर तरीका है), जैसे कि (2 + 2) === 4


जो मुझे समझ नहीं आ रहा है

लेकिन मुझे समझ में नहीं आता है कि यह समान रूप से क्यों काम नहीं करता है:

function(){
    alert(2 + 2);
}();

क्या तुम मुझे समझा सकते हो?


39
मुझे लगता है कि इन सभी विविध संकेतन और कार्यों को परिभाषित / स्थापित करने / कॉल करने के तरीके शुरू में जावास्क्रिप्ट के साथ काम करने का सबसे भ्रामक हिस्सा है। लोग उनके बारे में बात नहीं करते हैं। यह गाइड या ब्लॉग में जोर देने वाला बिंदु नहीं है। यह मेरे दिमाग को उड़ा देता है क्योंकि यह ज्यादातर लोगों के लिए कुछ भ्रामक है, और js में धाराप्रवाह लोग इसके माध्यम से भी गए होंगे। यह इस खाली वर्जित वास्तविकता की तरह है जिसके बारे में कभी बात नहीं होती।
एहनबिजद

1
इस निर्माण के उद्देश्य के बारे में भी पढ़ें , या ( तकनीकी ) स्पष्टीकरण की जाँच करें ( यहाँ भी )। कोष्ठक की नियुक्ति के लिए, उनके स्थान के बारे में यह प्रश्न देखें ।
बरगी

OT: जो पता करने के लिए जहां इन अनाम प्रक्रियाएं एक बहुत उपयोग किया जाता है चाहता हूँ के लिए, कृपया पढ़ adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
एलिरेज़ा Fattahi

यह तुरंत लागू समारोह अभिव्यक्तियों (IIFE) का एक विशिष्ट मामला है।
अमीनू कानो

जवाबों:


410

यह काम नहीं करता है क्योंकि इसे एक के रूप में पार्स किया जा रहा है FunctionDeclaration, और फ़ंक्शन घोषणाओं का नाम पहचानकर्ता अनिवार्य है

जब आप इसे कोष्ठक के साथ घेरते हैं, तो इसका मूल्यांकन ए के रूप में किया जाता है FunctionExpression, और फ़ंक्शन अभिव्यक्तियों को नाम दिया जा सकता है या नहीं।

इस FunctionDeclarationतरह दिखता है का व्याकरण :

function Identifier ( FormalParameterListopt ) { FunctionBody }

और FunctionExpressionएस:

function Identifieropt ( FormalParameterListopt ) { FunctionBody }

जैसा कि आप देख सकते हैं Identifier(आइडेंटिफ़ायर ऑप्ट ) टोकन FunctionExpressionवैकल्पिक है, इसलिए हम बिना परिभाषित नाम के एक फ़ंक्शन अभिव्यक्ति कर सकते हैं:

(function () {
    alert(2 + 2);
}());

या नामित समारोह अभिव्यक्ति:

(function foo() {
    alert(2 + 2);
}());

कोष्ठक (औपचारिक रूप से ग्रुपिंग ऑपरेटर कहा जाता है ) केवल अभिव्यक्तियों को घेर सकता है, और एक फ़ंक्शन अभिव्यक्ति का मूल्यांकन किया जाता है।

दो व्याकरण निर्माण अस्पष्ट हो सकते हैं, और वे उदाहरण के लिए बिल्कुल एक जैसे दिख सकते हैं:

function foo () {} // FunctionDeclaration

0,function foo () {} // FunctionExpression

पार्सर जानता है कि यह एक FunctionDeclarationया एक है FunctionExpression, संदर्भ के आधार पर जहां यह प्रकट होता है।

उपरोक्त उदाहरण में, दूसरा एक अभिव्यक्ति है क्योंकि कॉमा ऑपरेटर केवल अभिव्यक्तियों को भी संभाल सकता है।

दूसरी ओर, FunctionDeclarationवास्तव में केवल वही दिखाई दे सकता है जिसे " Program" कोड कहा जाता है , जिसका अर्थ है वैश्विक दायरे में बाहर कोड, और FunctionBodyअन्य कार्यों के अंदर ।

ब्लॉक के अंदर के कार्यों से बचा जाना चाहिए, क्योंकि वे अप्रत्याशित व्यवहार का नेतृत्व कर सकते हैं, उदाहरण के लिए:

if (true) {
  function foo() {
    alert('true');
  }
} else {
  function foo() {
    alert('false!');
  }
}

foo(); // true? false? why?

उपरोक्त कोड वास्तव में एक का उत्पादन करना चाहिए SyntaxError, क्योंकि Blockइसमें केवल कथन हो सकते हैं (और ECMAScript विनिर्देश किसी फ़ंक्शन स्टेटमेंट को परिभाषित नहीं करता है), लेकिन अधिकांश कार्यान्वयन सहिष्णु हैं, और बस दूसरा फ़ंक्शन लेगा, जो अलर्ट करता है 'false!'

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


कार्य विभिन्न तरीकों से घोषित किए जा सकते हैं, निम्नलिखित की तुलना करें :

1- एक समारोह के साथ परिभाषित समारोह चर करने के लिए सौंपा निर्माता गुणा :

var multiply = new Function("x", "y", "return x * y;");

2- एक फ़ंक्शन की घोषणा एक फ़ंक्शन का नाम गुणा :

function multiply(x, y) {
    return x * y;
}

3 एक समारोह अभिव्यक्ति चर करने के लिए सौंपा गुणा :

var multiply = function (x, y) {
    return x * y;
};

4- एक नामित समारोह अभिव्यक्ति FUNC_NAME , चर करने के लिए सौंपा गुणा :

var multiply = function func_name(x, y) {
    return x * y;
};

2
सीएमएस का जवाब सही है। फ़ंक्शन घोषणाओं और अभिव्यक्तियों की एक उत्कृष्ट गहराई से व्याख्या के लिए, इस लेख को कंगैक्स द्वारा देखें
टिम डाउन

यह एक बेहतरीन जवाब है। ऐसा लगता है कि स्रोत पाठ कैसे पार्स किया गया है और बीएनएफ की संरचना के साथ अंतरंग रूप से जुड़ा हुआ है। आपके उदाहरण 3 में, क्या मुझे यह कहना चाहिए कि यह एक फ़ंक्शन एक्सप्रेशन है क्योंकि यह एक समान चिन्ह का अनुसरण करता है, जो कि फॉर्म एक फ़ंक्शन डिक्लेरेशन / स्टेटमेंट है जब वह स्वयं एक लाइन पर दिखाई देता है? मुझे आश्चर्य है कि इसका उद्देश्य क्या होगा- क्या इसकी व्याख्या केवल नामांकित घोषणा के रूप में की जाती है, लेकिन बिना नाम के? यदि आप इसे एक चर में निर्दिष्ट नहीं कर रहे हैं, तो इसका नामकरण, या इसे कॉल करने से क्या प्रयोजन है?
ब्रेटन

1
अहा। बहुत उपयोगी। धन्यवाद, सीएमएस। मोज़िला डॉक्स का यह हिस्सा जो आप से जुड़ा है, विशेष रूप से ज्ञानवर्धक है: developer.mozilla.org/En/Core_JavaScript_1.5_Reference/…
प्रेमसागर

1
+1, हालाँकि आपको फ़ंक्शन अभिव्यक्ति में गलत स्थिति में समापन ब्रैकेट था :-)
NickFitz

1
@ गोविंदराय, सं। फ़ंक्शन की घोषणाओं को संकलन के समय पर नियंत्रित किया जाता है और एक डुप्लिकेट फ़ंक्शन घोषणा पिछले घोषणा को ओवरराइड करती है। रनटाइम के दौरान, फ़ंक्शन घोषणा पहले से ही उपलब्ध है और इस मामले में, जो उपलब्ध है वह वही है जो "झूठे" को अलर्ट करता है। अधिक जानकारी के लिए, आप जेएस
सौरभ मिश्रा

50

भले ही यह एक पुराना सवाल और जवाब हो, लेकिन यह एक ऐसे विषय पर चर्चा करता है जो आज तक कई डेवलपर्स को लूप के लिए फेंक देता है। मेरे द्वारा साक्षात्कार किए गए जावास्क्रिप्ट डेवलपर उम्मीदवारों की संख्या की गणना मैं नहीं कर सकता, जो मुझे एक फ़ंक्शन घोषणा और एक फ़ंक्शन अभिव्यक्ति के बीच का अंतर नहीं बता सकते थे और जिनके पास कोई संकेत नहीं था कि तुरंत लागू फ़ंक्शन अभिव्यक्ति क्या है।

मैं उल्लेख करना चाहूंगा, हालांकि, एक बहुत महत्वपूर्ण बात यह है कि प्रेमसागर का कोड स्निपेट काम नहीं करेगा भले ही उसने इसे एक पहचानकर्ता दिया हो।

function someName() {
    alert(2 + 2);
}();

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

function someName() {
    alert(2 + 2);
}

();

एक और बात मैं यह बताना चाहूंगा कि कुछ लोगों के लिए कुछ उपयोग की बात हो सकती है कि फ़ंक्शन एक्सप्रेशन के अलावा कोई भी नाम पहचानकर्ता जो आपको फ़ंक्शन अभिव्यक्ति के लिए प्रदान करता है, कोड के संदर्भ में बहुत बेकार है।

var a = function b() {
    // do something
};
a(); // works
b(); // doesn't work

var c = function d() {
    window.setTimeout(d, 1000); // works
};

बेशक, आपके फ़ंक्शन परिभाषाओं के साथ नाम पहचानकर्ताओं का उपयोग करना हमेशा डिबगिंग कोड की बात करते समय सहायक होता है, लेकिन यह पूरी तरह से कुछ और है: :-)


17

शानदार उत्तर पहले से ही पोस्ट किए जा रहे हैं। लेकिन मैं यह नोट करना चाहता हूं कि फ़ंक्शन घोषणाएं एक खाली पूरा रिकॉर्ड लौटाती हैं:

14.1.20 - रनटाइम शब्दार्थ: मूल्यांकन

FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody }

  1. नॉर्मलकंप्लीमेंट (खाली) लौटें ।

यह तथ्य निरीक्षण करना आसान नहीं है, क्योंकि लौटाए गए मूल्य को प्राप्त करने के प्रयास के अधिकांश तरीके फ़ंक्शन घोषणा को फ़ंक्शन अभिव्यक्ति में बदल देंगे। हालाँकि, evalयह दिखाता है:

var r = eval("function f(){}");
console.log(r); // undefined

खाली पूरा रिकॉर्ड कॉल करने का कोई मतलब नहीं है। इसलिए function f(){}()काम नहीं कर सकता। वास्तव में जेएस इंजन इसे कॉल करने का प्रयास भी नहीं करता है, कोष्ठक एक और कथन का हिस्सा माना जाता है।

लेकिन यदि आप फ़ंक्शन को कोष्ठक में लपेटते हैं, तो यह एक फ़ंक्शन एक्सप्रेशन बन जाता है:

var r = eval("(function f(){})");
console.log(r); // function f(){}

फ़ंक्शन अभिव्यक्तियाँ एक फ़ंक्शन ऑब्जेक्ट वापस करती हैं। और इसलिए आप इसे कॉल कर सकते हैं (function f(){})():।


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

10

जावास्क्रिप्ट में, इसे तत्काल-इनवॉल्ड फंक्शन एक्सप्रेशन (IIFE) कहा जाता है

इसे एक कार्य अभिव्यक्ति बनाने के लिए:

  1. () का उपयोग करके इसे संलग्न करें

  2. इससे पहले एक शून्य ऑपरेटर रखें

  3. इसे किसी वैरिएबल पर असाइन करें।

अन्यथा इसे फ़ंक्शन परिभाषा के रूप में माना जाएगा और फिर आप निम्नलिखित तरीके से इसे एक ही समय में कॉल / इनवोक नहीं कर पाएंगे:

 function (arg1) { console.log(arg1) }(); 

उपरोक्त आपको त्रुटि देगा। क्योंकि आप केवल एक फ़ंक्शन अभिव्यक्ति को तुरंत लागू कर सकते हैं।

इसे कुछ तरीकों से हासिल किया जा सकता है: तरीका 1:

(function(arg1, arg2){
//some code
})(var1, var2);

रास्ता 2:

(function(arg1, arg2){
//some code
}(var1, var2));

रास्ता 3:

void function(arg1, arg2){
//some code
}(var1, var2);

रास्ता 4:

  var ll = function (arg1, arg2) {
      console.log(arg1, arg2);
  }(var1, var2);

उपरोक्त सभी फ़ंक्शन अभिव्यक्ति को तुरंत लागू करेंगे।


3

मेरी एक और छोटी टिप्पणी है। आपका कोड एक छोटे से बदलाव के साथ काम करेगा:

var x = function(){
    alert(2 + 2);
}();

मैं अधिक व्यापक रूप से फैले हुए संस्करण के बजाय उपरोक्त सिंटैक्स का उपयोग करता हूं:

var module = (function(){
    alert(2 + 2);
})();

क्योंकि मैं जावास्क्रिप्ट फ़ाइलों को ठीक से काम करने के लिए इंडेंटेशन प्राप्त करने का प्रबंधन नहीं करता था। ऐसा लगता है कि विम खुले कोष्ठक के अंदर घुंघराले ब्रेसिज़ को पसंद नहीं करता है।


तो जब आप एक चर के लिए निष्पादित परिणाम असाइन करते हैं तो यह सिंटैक्स क्यों काम करता है, लेकिन स्टैंडअलोन नहीं?
२०:०४

1
@paislee - क्योंकि जावास्क्रिप्ट इंजन functionकीवर्ड के साथ शुरू होने वाले किसी भी मान्य जावास्क्रिप्ट स्टेटमेंट को एक फ़ंक्शन डिक्लेरेशन के() रूप में व्याख्या करता है , जिसके मामले में ट्रेलिंग को एक ग्रुपिंग ऑपरेटर के रूप में व्याख्या की जाती है, जो जावास्क्रिप्ट सिंटैक्स नियमों के अनुसार, केवल और एक जावास्क्रिप्ट एक्सप्रेशन होना चाहिए
natlee75

1
@bosonix - आपका पसंदीदा सिंटैक्स अच्छी तरह से काम करता है, लेकिन आपके द्वारा संदर्भित "अधिक व्यापक रूप से फैले हुए संस्करण" का उपयोग करने के लिए एक अच्छा विचार है, या वह संस्करण जहां ()समूह के ऑपरेटर के भीतर संलग्न है (एक है कि डगलस क्रॉकफोर्ड दृढ़ता से स्थिरता के लिए सिफारिश करते हैं: यह है IIFE का उपयोग उन्हें एक चर में असाइन किए बिना करना, और यदि आप उन्हें लगातार उपयोग नहीं करते हैं, तो उन रैपिड कोष्ठकों को शामिल करना भूल जाना आसान है।
natlee75

0

शायद इसका छोटा जवाब यही होगा

function() { alert( 2 + 2 ); }

एक फ़ंक्शन शाब्दिक है जो एक (अनाम) फ़ंक्शन को परिभाषित करता है। एक अतिरिक्त () -पेयर, जिसे एक अभिव्यक्ति के रूप में व्याख्यायित किया जाता है, केवल शाब्दिक रूप से टॉपवेल पर अपेक्षित नहीं है।

(function() { alert( 2 + 2 ); })();

एक अभिव्यक्ति कथन में है जो एक अनाम फ़ंक्शन को आमंत्रित करता है।


0
(function(){
     alert(2 + 2);
 })();

ऊपर मान्य सिंटैक्स है क्योंकि कोष्ठक के अंदर पारित कुछ भी फ़ंक्शन अभिव्यक्ति के रूप में माना जाता है।

function(){
    alert(2 + 2);
}();

ऊपर सिंटैक्स मान्य नहीं है। क्योंकि जावा स्क्रिप्ट सिंटैक्स पार्सर फ़ंक्शन कीवर्ड के बाद फ़ंक्शन नाम की तलाश करता है क्योंकि यह कुछ भी नहीं पाता है यह एक त्रुटि फेंकता है।


2
हालांकि आपका उत्तर गलत नहीं है, लेकिन पहले से स्वीकार किए गए उत्तर को इस विभाग में शामिल नहीं किया गया है।
अर्नोल्ड

0

आप इसका उपयोग भी कर सकते हैं जैसे:

! function() { console.log('yeah') }()

या

!! function() { console.log('yeah') }()

!- नकार ऑप fn परिभाषा को fn अभिव्यक्ति में रूपांतरित करता है, इसलिए, आप इसे तुरंत लागू कर सकते हैं ()। का उपयोग करते हुए 0,fn defया के रूप में हीvoid fn def


-1

उनका उपयोग मापदंडों-तर्कों जैसे किया जा सकता है

var x = 3; 
var y = 4;

(function(a,b){alert(a + b)})(x,y)

7 के रूप में परिणाम होगा


-1

वे अतिरिक्त कोष्ठक वैश्विक नाम स्थान और अनाम फ़ंक्शन के बीच अतिरिक्त अनाम फ़ंक्शंस बनाते हैं जिनमें कोड होता है। और अन्य कार्यों के अंदर घोषित किए गए जावास्क्रिप्ट फ़ंक्शंस में केवल मूल फ़ंक्शन के नेमस्पेस तक पहुंच हो सकती है, जिसमें वे शामिल हैं। चूँकि वैश्विक दायरे और वास्तविक कोड स्कोपिंग के बीच अतिरिक्त ऑब्जेक्ट (एनोनिमस फंक्शन) नहीं है।

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