क्या मैं एक जावास्क्रिप्ट फ़ंक्शन का नाम दे सकता हूं और इसे तुरंत निष्पादित कर सकता हूं?


90

मेरे पास इनमें से कुछ हैं:

function addEventsAndStuff() {
  // bla bla
}
addEventsAndStuff();

function sendStuffToServer() {
  // send stuff
  // get HTML in response
  // replace DOM
  // add events:
  addEventsAndStuff();
}

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

इस सेट अप (या वहाँ है?) के साथ कुछ भी गलत नहीं है, लेकिन क्या मैं इसे थोड़ा चिकना कर सकता हूं? मैं addEventsAndStuff()फंक्शन बनाना चाहूंगा और तुरंत कॉल करूंगा , इसलिए यह इतना शौकिया नहीं लगता।

दोनों सिंटैक्स त्रुटि के साथ निम्नलिखित उत्तर देते हैं:

function addEventsAndStuff() {
  alert('oele');
}();

(function addEventsAndStuff() {
  alert('oele');
})();

कोई लेने वाला?



2
नहीं, @CristianSanchez
मक्सिमा कोन्मेज़

Imho आपके दूसरे कोड ब्लॉक को पढ़ना मुश्किल है। पहले कोड ब्लॉक में यह प्रत्येक पाठक के लिए स्पष्ट है, कि आप इनिट के बाद फ़ंक्शन को कॉल करते हैं। पाठक अंत में समापन और अपठित कोष्ठकों की उपेक्षा करते हैं।
kaiser

जवाबों:


123

आपके प्रश्न में पोस्ट किए गए उदाहरण के साथ कुछ भी गलत नहीं है .. इसे करने का दूसरा तरीका अजीब लग सकता है, लेकिन:

var addEventsAndStuff;
(addEventsAndStuff = function(){
    // add events, and ... stuff
})();

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

function foo(){ ... }

और एक फ़ंक्शन अभिव्यक्ति, जो उपरोक्त के अलावा किसी फ़ंक्शन को परिभाषित करने का कोई तरीका है:

var foo = function(){};
(function(){})();
var foo = {bar : function(){}};

...आदि

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

(function foo(){
   foo(); // recursion for some reason
}());

लेकिन यह नहीं है:

(function foo(){
    ...
}());
foo(); // foo does not exist

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


1
"फंक्शन एक्सप्रेशन को नाम दिया जा सकता है" नामांकित फंक्शन एक्सप्रेशंस से सावधान रहें। वे चाहिए के रूप में आप का वर्णन काम करते हैं, लेकिन वे IE9 से पहले IE पर नहीं करते हैं - आप प्राप्त दो काम करता है, और समारोह नाम लीक। विवरण: kangax.github.com/nfe (यह अंततः IE9 में तय किया गया है।)
TJ Crowder

@ टीजे - संदर्भ के लिए धन्यवाद। मुझे एहसास नहीं था कि जैसा कि मैंने कभी भी IE का उपयोग अंतिम उत्पादों का परीक्षण करने के लिए नहीं किया है :) मैं मान रहा हूं कि IE9 ने IE7 / 8 मोड पर सेट करते समय इस बग का अनुकरण नहीं किया है? मुझे लगता है कि यह अभी भी IE9 JS इंजन का उपयोग करता है ... Meh
Mark Kahn

अगर, मेरी तरह, आप इस विधि के साथ jshint मुद्दों में भाग लेते हैं, तो आप call()यहाँ से विधि का उपयोग कर सकते हैं : stackoverflow.com/a/12359154/1231001
cfx

यह दृष्टिकोण कुछ परिस्थितियों में उपयोगी लग सकता है, लेकिन पढ़ने के लिए थोड़ा कठिन होने के अलावा, यह वस्तुतः पाठ की समान मात्रा है।
व्लादिमीर

16

इसके लिए एक अच्छा शॉर्टहैंड है (फ़ंक्शन के असाइनमेंट को किसी भी चर को घोषित करने की आवश्यकता नहीं है):

var func = (function f(a) { console.log(a); return f; })('Blammo')

कौन सा rफंक्शन वापस आएगा? function rया var r? बस उत्सुक। अच्छा समाधान। हालांकि एक स्थान नहीं होना चाहिए) =)
रुडी 18

मैंने इसे और अधिक स्पष्ट होने के लिए नाम दिया है, लेकिन return rयह function rवैसा ही होगा जैसा कि यह गुंजाइश है। इतने पर स्थायी रूप से कुछ पाने की कोशिश में स्काला को हरा दिया।
जेम्स गोरी

@JamesGorrie, ब्रिलिएंट शॉर्टहैंड, हालांकि, मैंने दो बार सांत्वना देने की कोशिश की, ऐसा लगता है कि func, func (), func () () सभी रिटर्न फंक्शन की घोषणा f () है, लेकिन क्या हम 'Blammo' को func () के रूप में आउटपुट कर सकते हैं। :)?
mike652638

@ mike652638 मैंने अपने कंसोल में चला दिया है और यह कंसोल ब्लोमो लॉग करता है?
जेम्स गोरी

5

इस सेट अप (या वहाँ है?) के साथ कुछ भी गलत नहीं है, लेकिन क्या मैं इसे थोड़ा चिकना कर सकता हूं?

इसके बजाय इवेंट डेलिगेशन का उपयोग करें। यही कारण है कि आप वास्तव में एक कंटेनर पर घटना के लिए देखते हैं जो दूर नहीं जाता है, और फिर यह पता लगाने के लिए event.target(या event.srcElementIE पर) का उपयोग करें जहां घटना वास्तव में हुई और इसे सही ढंग से संभालती है।

इस तरह, आप केवल एक बार हैंडलर (ओं) को संलग्न करते हैं, और वे तब भी काम करते रहते हैं जब आप सामग्री को स्वैप करते हैं।

यहां किसी भी सहायक काम का उपयोग किए बिना घटना प्रतिनिधिमंडल का एक उदाहरण है:

(function() {
  var handlers = {};

  if (document.body.addEventListener) {
    document.body.addEventListener('click', handleBodyClick, false);
  }
  else if (document.body.attachEvent) {
    document.body.attachEvent('onclick', handleBodyClick);
  }
  else {
    document.body.onclick = handleBodyClick;
  }

  handlers.button1 = function() {
    display("Button One clicked");
    return false;
  };
  handlers.button2 = function() {
    display("Button Two clicked");
    return false;
  };
  handlers.outerDiv = function() {
    display("Outer div clicked");
    return false;
  };
  handlers.innerDiv1 = function() {
    display("Inner div 1 clicked, not cancelling event");
  };
  handlers.innerDiv2 = function() {
    display("Inner div 2 clicked, cancelling event");
    return false;
  };

  function handleBodyClick(event) {
    var target, handler;

    event = event || window.event;
    target = event.target || event.srcElement;

    while (target && target !== this) {
      if (target.id) {
        handler = handlers[target.id];
        if (handler) {
          if (handler.call(this, event) === false) {
            if (event.preventDefault) {
              event.preventDefault();
            }
            return false;
          }
        }
      }
      else if (target.tagName === "P") {
        display("You clicked the message '" + target.innerHTML + "'");
      }
      target = target.parentNode;
    }
  }

  function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = msg;
    document.body.appendChild(p);
  }

})();

जीवंत उदाहरण

ध्यान दें कि यदि आप उन संदेशों पर क्लिक करते हैं जो गतिशील रूप से पृष्ठ पर जोड़े जाते हैं, तो आपका क्लिक पंजीकृत हो जाता है और संभाल लिया जाता है, भले ही नए पैराग्राफ में हुक घटनाओं को जोड़ने के लिए कोई कोड नहीं है। यह भी ध्यान दें कि कैसे आपके हैंडलर सिर्फ एक नक्शे में प्रविष्टियां हैं, और आपके पास एक हैंडलर है document.bodyजो सभी प्रेषण करता है। अब, आप संभवत: इससे अधिक लक्षित कुछ को जड़ देते हैं document.body, लेकिन आपको यह विचार मिलता है। इसके अलावा, ऊपर हम मूल रूप से प्रेषण कर रहे हैं id, लेकिन आप अपनी इच्छानुसार जटिल या सरल मिलान कर सकते हैं।

आधुनिक जावास्क्रिप्ट लाइब्रेरी जैसे jQuery , प्रोटोटाइप , YUI , क्लोजर या कई अन्य में से किसी को ब्राउज़र के मतभेदों को दूर करने और किनारे के मामलों को सफाई से संभालने के लिए इवेंट डेलिगेशन फीचर्स की पेशकश करनी चाहिए। jQuery निश्चित रूप से अपने दोनों liveऔर delegateकार्यों के साथ करता है, जो आपको CSS3 चयनकर्ताओं (और फिर कुछ) की पूरी श्रृंखला का उपयोग करके हैंडलर निर्दिष्ट करने की अनुमति देता है।

उदाहरण के लिए, यहाँ jQuery का उपयोग करते हुए समकक्ष कोड है (इसके अलावा मुझे यकीन है कि jQuery हैंडल किनारे के मामलों को बंद नहीं करता है)

(function($) {

  $("#button1").live('click', function() {
    display("Button One clicked");
    return false;
  });
  $("#button2").live('click', function() {
    display("Button Two clicked");
    return false;
  });
  $("#outerDiv").live('click', function() {
    display("Outer div clicked");
    return false;
  });
  $("#innerDiv1").live('click', function() {
    display("Inner div 1 clicked, not cancelling event");
  });
  $("#innerDiv2").live('click', function() {
    display("Inner div 2 clicked, cancelling event");
    return false;
  });
  $("p").live('click', function() {
    display("You clicked the message '" + this.innerHTML + "'");
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }

})(jQuery);

लाइव कॉपी


मैं उपयोग नहीं करना चाहता Event.target, क्योंकि यह सही लक्ष्य नहीं है। ये सही है। यदि आप एक IMGअंदर DIVऔर DIVघटना पर क्लिक करते हैं , तो Event.targetयह होगा IMGऔर DIVवस्तु को अच्छी तरह से प्राप्त करने का कोई तरीका नहीं है । संपादित Btw मैं jQuery के नफरत .live'घटना'
Rudie

@ रुडी: event.targetक्या ? रे : आप जो वर्णन करते हैं वह गलत नहीं है, यह सही है। यदि आप imgअंदर क्लिक divकरते हैं और आप देख रहे हैं div, event.targetतो img(और thisहै div)। ऊपर एक और नज़र डालें। आप उस तत्व के बीच श्रृंखला के किसी भी बिंदु पर एक हैंडलर संलग्न कर सकते हैं (जो img, उदाहरण के लिए) और जिस तत्व को आप देख रहे हैं (ऊपर, नीचे सभी तरह से document.body)। पुन live: मैं बहुत पसंद करते हैं delegate, के अधिक निहित संस्करण live। मैंने liveऊपर इस्तेमाल किया क्योंकि यह कच्चे उदाहरण में मैंने जो किया था, उसके सबसे करीब था। बेस्ट,
टीजे क्राउडर

4

आप इस तरह एक सहायक समारोह बनाना चाहते हो सकता है:

function defineAndRun(name, func) {
    window[name] = func;
    func();
}

defineAndRun('addEventsAndStuff', function() {
    alert('oele');
});

2
यह एक बुरा समाधान क्यों है? क्योंकि फ़ंक्शन वैश्विक नामस्थान में पंजीकृत हैं? इसके लिए किसे वोट दिया गया?
रुडी

महान विचार
:)

4

आपके कोड में एक टाइपो है:

(function addEventsAndStuff() {
  alert('oele');
)/*typo here, should be }*/)();

इसलिए

(function addEventsAndStuff() {
  alert('oele');
 })();

काम करता है। चीयर्स!

[ संपादित करें ] टिप्पणी पर आधारित: और इसे चलाना चाहिए और फ़ंक्शन को एक बार में वापस करना चाहिए:

var addEventsAndStuff = (
 function(){
  var addeventsandstuff =  function(){
    alert('oele');
  };
  addeventsandstuff();
  return addeventsandstuff;
 }()
);

मूर्ख कोष्ठक सभी एक जैसे दिखते हैं !! धन्यवाद! वास्तव में चीयर्स!
रूडी

हाँ ... तो एह ... वास्तव में यह काम नहीं करता है। फ़ंक्शन को तुरंत निष्पादित किया जाता है, हाँ, लेकिन यह कहीं भी पंजीकृत नहीं है, इसलिए इसे फिर से कॉल करना ->ReferenceError
रुडी

@Rudie: अभी पता चला है कि KomodoEdit अंत में वह सब कुछ करता है जो मैं हमेशा से चाहता था कि आप Aptana स्टूडियो (लेकिन हर समय टूट गया), और उसके शीर्ष पर यह बहुत उपयोगी, तेज़ और उपयोगी एडन के साथ पैक किया गया है। और यह मिलान करने वाले कोष्ठक पर प्रकाश डालता है: आप उन मिलान वाले कोष्ठकों को एक लाल चेतावनी रंग भी दे सकते हैं! इसे आज़माइए
KooiInc

यार ... (और जाहिर है कि मैंने इसे एसओ वेब एडिटर में टाइप किया था, डेस्कटॉप एडिटर में नहीं।)
रूडी

और यह बहुत कुछ अतिरिक्त टाइपिंग है और यह याद रखना कि क्या और कैसे टाइप करना है। मुझे मूल (काम नहीं) समाधान पसंद आया, लेकिन नया बहुत मुश्किल है =)
रुडी

2

ES6 के साथ और भी सरल:

var result = ((a, b) => `${a} ${b}`)('Hello','World')
// result = "Hello World"
var result2 = (a => a*2)(5)
// result2 = 10
var result3 = (concat_two = (a, b) => `${a} ${b}`)('Hello','World')
// result3 = "Hello World"
concat_two("My name", "is Foo")
// "My name is Foo"

तो मैं इसे फिर से कैसे कहूंगा? इसका नाम क्या है, इसके द्वारा कॉल करने के लिए? आप केवल परिणाम रख रहे हैं, फ़ंक्शन नहीं।
रूडी

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

1
मेरा प्रश्न नामकरण और इसे पुन: निर्देशित करने के बारे में था। concat_twoपूरी तरह से काम करता है, लेकिन यह हमेशा इसे वैश्विक दायरे में परिभाषित करता है, इसलिए यह काम नहीं करेगा "use strict"। यह मेरे लिए महत्वपूर्ण नहीं है, लेकिन यह एक नकारात्मक पहलू है।
रूडी

1

यदि आप कोई फंक्शन बनाना चाहते हैं और तुरंत निष्पादित करें -

// this will create as well as execute the function a()
(a=function a() {alert("test");})();

// this will execute the function a() i.e. alert("test")
a();

1
खबरदार, जब आप एक नामित फ़ंक्शन का उपयोग राइट-हैंड वैल्यू के रूप में करते हैं (जैसा कि आप ऊपर करते हैं), तो आप एक नामित फ़ंक्शन एक्सप्रेशन का उपयोग कर रहे हैं, जबकि यह दुर्भाग्यपूर्ण होना चाहिए कि विभिन्न कार्यान्वयन में समस्याएँ हैं (ज्यादातर - क्ले शॉक - IE )। विवरण: kangax.github.com/nfe
TJ Crowder

0

ऐसा करने का प्रयास करें:

var addEventsAndStuff = (function(){
    var func = function(){
        alert('ole!');
    };
    func();
    return func;
})();

1
यह करीब है, लेकिन var foo = (function() {...})();असाइनमेंट से पहले फ़ंक्शन को कॉल करता है। कोष्ठक को असाइनमेंट शामिल करना होगा। (आप फिर कॉल करना चाहते हैं ।)
डेविड

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