2008-11-17 21 views
147

का संदर्भ देते समय एक जावास्क्रिप्ट फ़ंक्शन को ओवरराइड करना मेरे पास एक फ़ंक्शन, a() है, जिसे मैं ओवरराइड करना चाहता हूं, लेकिन संदर्भ के आधार पर मूल a() भी क्रम में किया जाना चाहिए। उदाहरण के लिए, कभी कभी जब मैं एक पेज पैदा कर रहा हूँ मैं इस तरह ओवरराइड करने के लिए चाहता हूँ:मूल

function a() { 
    new_code(); 
    original_a(); 
} 

और कभी कभी इस तरह: मैं कैसे मिलता है

function a() { 
    original_a(); 
    other_new_code(); 
} 

कि original_a() खत्म भीतर से सवारी a()? क्या यह भी संभव है?

कृपया इस तरह से सवारी करने के विकल्पों का सुझाव न दें, मुझे कई लोगों के बारे में पता है। मैं विशेष रूप से इस तरह से पूछ रहा हूँ।

उत्तर

172

आप कुछ इस तरह कर सकता है:

var a = (function() { 
    var original_a = a; 

    if (condition) { 
     return function() { 
      new_code(); 
      original_a(); 
     } 
    } else { 
     return function() { 
      original_a(); 
      other_new_code(); 
     } 
    } 
})(); 

एक गुमनाम समारोह के अंदर की घोषणा original_a ग्लोबल नेम स्पेस को अव्यवस्थित होने से रहता है, लेकिन यह आंतरिक कार्यों में उपलब्ध है।

टिप्पणियों में उल्लिखित नेरडमास्टर की तरह, अंत में () शामिल करना सुनिश्चित करें। आप बाहरी समारोह को कॉल करना चाहते हैं और में a में परिणाम (दो आंतरिक कार्यों में से एक) को स्टोर करना चाहते हैं, बाहरी फ़ंक्शन को a में संग्रहीत न करें।

+0

धन्यवाद! यह बहुत उपयोगी है। – Kev

+1

वाह। अल्ट्रा कूल – naveen

+21

मेरे जैसे किसी भी बेवकूफों के लिए - अंत में "()" पर ध्यान दें - इसके बिना, यह बाहरी फ़ंक्शन देता है, आंतरिक कार्यों में नहीं :) – Nerdmaster

75

Proxy pattern आप मदद कर सकता है:

(function() { 
    // log all calls to setArray 
    var proxied = jQuery.fn.setArray; 
    jQuery.fn.setArray = function() { 
     console.log(this, arguments); 
     return proxied.apply(this, arguments); 
    }; 
})(); 

ऊपर एक समारोह "प्रॉक्सी" -variable को छिपाने के लिए अपने कोड गिर्द घूमती है। यह बंद करने में jQuery की सेटअरे-विधि बचाता है और इसे ओवरराइट करता है। प्रॉक्सी तब विधि को सभी कॉल लॉग करता है और कॉल को मूल पर प्रतिनिधि करता है। आवेदन (यह, तर्क) का उपयोग करने की गारंटी है कि कॉलर मूल और प्रॉक्सी विधि के बीच का अंतर नहीं देख पाएगा।

+7

वास्तव में। 'लागू' और 'तर्क' का उपयोग अन्य उत्तरों की तुलना में कहीं अधिक मजबूत बनाता है –

+3

आपको पता नहीं है कि मैंने उस लिंक से कितना सीखा है।धन्यवाद सर –

+0

एक आकर्षण की तरह काम किया। बहुत धन्यवाद। – kevin11

26

धन्यवाद लोग प्रॉक्सी पैटर्न वास्तव में मदद की ..... असल में मैं एक वैश्विक समारोह foo .. कुछ पन्नों मैं कुछ जांच करने के लिए क्या जरूरत में कॉल करने के लिए चाहता था। तो मैंने निम्नलिखित किया।

//Saving the original func 
var org_foo = window.foo; 

//Assigning proxy fucnc 
window.foo = function(args){ 
    //Performing checks 
    if(checkCondition(args)){ 
     //Calling original funcs 
     org_foo(args); 
    } 
}; 

Thnx यह वास्तव में मुझे बाहर मदद की

+1

[प्रॉक्सी पैटर्न] (http://api.jquery.com/Types/#Proxy_Pattern) का पालन करते समय, कुछ मामलों में यह विवरण लागू करना महत्वपूर्ण होगा जो इस उत्तर के कोड में मौजूद नहीं है: 'org_foo (तर्क) ', कॉल करें' org_foo.call (यह, args) '। यह 'इस' को बनाए रखता है क्योंकि यह तब होता जब window.foo सामान्य रूप से कॉल करता है (प्रॉक्सी नहीं)। [यह उत्तर] देखें (http://stackoverflow.com/a/915618/1357094) – cellepo

8

आप एक निर्माण की तरह उपयोग करते हुए एक समारोह ओवरराइड कर सकते हैं:

function override(f, g) { 
    return function() { 
     return g(f); 
    }: 
} 

उदाहरण के लिए:

a = override(a, function(original_a) { 
     if (condition) { new_code(); original_a(); } 
     else { original_a(); other_new_code(); } 
}); 
+0

+1 यह अन्य प्रॉक्सी पैटर्न उदाहरणों की तुलना में बहुत अधिक पठनीय है! –

+1

... लेकिन अगर मुझे गलत नहीं लगता है, तो यह शून्य-तर्क कार्यों तक सीमित है, या कम से कम तर्कों की पूर्व निर्धारित संख्या तक सीमित है। क्या पठनीयता खोने के बिना तर्कों की मनमानी संख्याओं को सामान्यीकृत करने का कोई तरीका है? –

+0

@MuMind: हाँ, लेकिन प्रॉक्सी पैटर्न का सही ढंग से उपयोग करना - देखें [मेरा जवाब] (http://stackoverflow.com/a/296713/1269037)। –

4

पासिंग मनमाना तर्क:

a = override(a, function(original_a) { 
    if (condition) { new_code(); original_a.apply(this, arguments) ; } 
    else { original_a.apply(this, arguments); other_new_code(); } 
}); 
+1

वांछित तर्क 'original_a' का उल्लेख करते हैं? –

1

ऊपर दिए गए उदाहरण this सही ढंग से लागू नहीं होते हैं या arguments सही ढंग से कार्य ओवरराइड पर पास करते हैं। Underscore _.wrap() मौजूदा कार्यों को लपेटता है, this लागू करता है और arguments सही ढंग से पास करता है।देखें: http://underscorejs.org/#wrap

0

मेरे पास किसी अन्य व्यक्ति द्वारा लिखित कुछ कोड था और एक फ़ंक्शन में एक पंक्ति जोड़ना चाहता था जिसे मैं कोड में नहीं मिला। तो एक कामकाज के रूप में मैं इसे ओवरराइड करना चाहता था।

हालांकि मेरे लिए कोई भी समाधान काम नहीं करता है।

यहाँ मेरे मामले में काम किया है:

if (typeof originalFunction === "undefined") { 
    originalFunction = targetFunction; 
    targetFunction = function(x, y) { 
     //Your code 
     originalFunction(a, b); 
     //Your Code 
    }; 
} 
0

मैं एक ऐसी ही परिदृश्य के लिए एक छोटा सा सहायक बना लिया है क्योंकि मैं अक्सर कई पुस्तकालयों से कार्यों ओवरराइड करने के लिए की जरूरत है। यह सहायक एक "नेमस्पेस" (फ़ंक्शन कंटेनर), फ़ंक्शन का नाम, और ओवरराइडिंग फ़ंक्शन स्वीकार करता है। यह मूल कार्य को संदर्भित नामस्थान में नए के साथ बदल देगा।

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

function overrideFunction(namespace, baseFuncName, func) { 
    var originalFn = namespace[baseFuncName]; 
    namespace[baseFuncName] = function() { 
     return func.apply(this, [originalFn.bind(this)].concat(Array.prototype.slice.call(arguments, 0))); 
    }; 
} 

उपयोग:

overrideFunction($.fn.popover.Constructor.prototype, 'leave', function(baseFn, obj) { 
    // ... do stuff before base call 
    baseFn(obj); 
    // ... do stuff after base call 
}); 

मैं किसी भी प्रदर्शन परीक्षणों हालांकि निर्माण नहीं किया। यह संभवतः कुछ अनचाहे ओवरहेड जोड़ सकता है जो परिदृश्यों के आधार पर एक बड़ा सौदा हो सकता है या नहीं।

0

मेरी राय में शीर्ष उत्तरों पठनीय/रखरखाव योग्य नहीं हैं, और अन्य उत्तरों संदर्भ को ठीक से बाध्य नहीं करते हैं। इन दोनों समस्याओं को हल करने के लिए ES6 वाक्यविन्यास का उपयोग करके एक पठनीय समाधान यहां दिया गया है।

const orginial = someObject.foo; 
someObject.foo = function() { 
    if (condition) orginial.bind(this)(...arguments); 
}; 
+0

लेकिन ईएस 6 सिंटैक्स का उपयोग करके इसे उपयोग में प्रतिबंधित कर दिया जाता है। क्या आपके पास एक संस्करण है जो ईएस 5 में काम करता है? – eitch

0

जवाब यह है कि @Matthew Crumley प्रदान करता है तुरंत लागू समारोह भाव का इस्तेमाल कर रही है, वापस आ समारोह के निष्पादन के संदर्भ में बड़े 'एक' समारोह बंद हुआ। मुझे लगता है कि यह सबसे अच्छा जवाब था, लेकिन व्यक्तिगत रूप से, मैं 'ए' को आईआईएफई के तर्क के रूप में गुजरना पसंद करूंगा। मुझे लगता है कि यह अधिक समझ में आता है।

var a = (function(original_a) { 
     if (condition) { 
      return function() { 
       new_code(); 
       original_a(); 
      } 
     } else { 
      return function() { 
       original_a(); 
       other_new_code(); 
      } 
     } 
    })(a); 
संबंधित मुद्दे