2010-10-26 23 views
5

माना कि की मैं इन दोनों कार्यों:जावास्क्रिप्ट: पुनः बताए एक और समारोह के साथ एक समारोह

function fnChanger(fn) { 
    fn = function() { sys.print('Changed!'); } 
} 
function foo() { 
    sys.print('Unchanged'); 
} 

अब, अगर मैं foo() कहते हैं, मैं Unchanged देखते हैं, के रूप में उम्मीद। हालांकि, अगर मैं fnChanger पहले फोन, मैं अभी भी Unchanged देखें:

fnChanger(foo); 
foo(); //Unchanged 

अब, मुझे लगता है इस वजह से foo संदर्भ द्वारा fnChanger को पास नहीं किया जा रहा है, लेकिन मैं गलत हो सकता है।

fooChanged! प्रिंट करने के लिए क्यों नहीं बदलता है?
इसके अलावा, मैं को बहुत अधिक गन्दा वाक्यविन्यास के बिना fnChanger कैसे प्राप्त कर सकता हूं?

पीएस: मैं इन सभी चीजों का परीक्षण करने के लिए node.js का उपयोग कर रहा हूं, इसलिए sys.print से आता है।

उत्तर

5

fn तर्क के लिए असाइनमेंट सिर्फ उस पहचानकर्ता को अज्ञात फ़ंक्शन को इंगित करने के लिए बनाता है, foo बाहरी दायरे में प्रभावित नहीं होता है।

जब आप किसी ऑब्जेक्ट को तर्क के रूप में पास करते हैं, तो कोई कह सकता है "संदर्भ मूल्य से पारित होते हैं"। असाइनमेंट केवल उस स्थान को प्रतिस्थापित करता है जहां fn पहचानकर्ता संदर्भित करता है।

इस प्रकार evaluation strategy जावास्क्रिप्ट में काम करता है।

से ठीक पहले fnChanger काम करता है, दो पहचानकर्ता वैश्विक foo और fn तर्क में काम, एक ही समारोह वस्तु के लिए बिंदु:

 
       --------------------------------------------- 
    foo -----> |function foo { sys.print('Un changed!'); } | 
       --------------------------------------------- 
       ^
        | 
    fn ------------- 

काम करने के बाद, fn बस नया को इंगित करेगा समारोह:

 
       --------------------------------------------- 
    foo -----> | function foo { sys.print('Unchanged!'); } | 
       --------------------------------------------- 

       --------------------------------------- 
    fn ------> | function { sys.print('Changed!'); } | 
       --------------------------------------- 

आप इसे कैसे बदल सकते हैं?

ठीक है, यह सोचते हैं कि foo वैश्विक क्षेत्र में एक समारोह है, तो आप कुछ इस तरह कर सकता है:

function fnChanger(obj, name) { 
    obj[name] = function() { sys.print('Changed!'); }; 
} 

function foo() { 
    sys.print('Unchanged'); 
} 

fnChanger(this, 'foo'); 
foo(); // Changed! 

ऊपर fnChanger समारोह में क्योंकि काम करेंगे, हम एक आधार वस्तु और एक की आवश्यकता होती है संपत्ति का नाम, वैश्विक निष्पादन संदर्भ में घोषित फ़ंक्शंस वैश्विक वस्तु के गुणों के रूप में बंधे हैं, इसलिए हम इस तरह अपना मान फिर से असाइन कर सकते हैं।

लाइन fnChanger(this, 'foo'); वैश्विक दायरे में भी मार डाला जाना चाहिए, यह this मूल्य (जो इस दायरे में वैश्विक वस्तु को संदर्भित करता है) और एक संपत्ति नाम गुजरती हैं, आप GlobalObject.foo पहचानकर्ता के लिए एक काम बनाने के लिए अनुमति देता है जाएगा।

हैं कि कोड एक समारोह के अंदर थे, वहाँ क्योंकि यह "फंक्शन कोड निष्पादन प्रसंग" में, समारोह घोषणाओं (चर घोषणाओं और समारोह औपचारिक भी पैरामीटर) कोई रास्ता नहीं हम एक आधार वस्तु प्राप्त कर सकते है, गुण के रूप में बाध्य कर रहे हैं एक गैर सुलभ वस्तु की, चर ऑब्जेक्ट (इन चर वस्तुओं की एक श्रृंखला, स्कोप चेन रूपों) कहा जाता है, और अगर यह मामला थे, केवल वैकल्पिक हल eval उपयोग करने के लिए किया जाएगा।

और जानकारी:

+0

हाँ, मुझे लगता है कि क्या हो रहा है है पर शक करने लगा था। स्पष्टीकरण के लिए धन्यवाद, और लिंक - मुझे कभी पता नहीं था कि उसे क्या कहना है या यह कैसे काम करता है। मैं इसके पास कैसे आ सकता हूं? –

+0

ठीक है, मुझे वह दृष्टिकोण पसंद है। जैसा कि मैं करने की सोच रहा था, उतना गन्दा नहीं: कार्य को बदलने वाली वस्तु को पास करना। –

2

@CMS के रूप में बताया आप गुंजाइश की वजह से समारोह के भीतर यह नहीं सौंप सकते। लेकिन अगर आप इसे इस तरह पुन: असाइन कर सकते हैं:

var fnChanger = function() { 
    return function() { 
     alert('changed!'); 
    } 
} 

var foo = function() { 
    alert('Unchanged'); 
} 

foo = fnChanger(); 
foo(); 

example

+0

हाँ, इसके बारे में सोचा। हालांकि, असली कोड में वापसी करके मुझे ऐसा करने में संकोच नहीं है। एक तरफ, यह क्लीनर है, लेकिन दूसरी तरफ, यह वास्तव में काम करता है के साथ मेल नहीं खाता है। –

संबंधित मुद्दे