2008-11-28 11 views
20

मैं अपने अनुप्रयोगों में से एक के लिए "मॉड्यूल" को संभालने में एक वैश्विक त्रुटि लिख रहा हूं।मैं जावास्क्रिप्ट में फ़ंक्शन कैसे लपेटूं?

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

हालांकि, यह जावास्क्रिप्ट, .call और .apply विधियों, और "यह" कीवर्ड के निम्न-स्तरीय कार्यप्रणाली की मेरी समझ से थोड़ा सा है।

Object.extend(Function.prototype, { 
    TryCatchWrap: function() { 
    var __method = this; 
    return function() { 
      try { __method.apply(this, arguments) } catch(ex) { ErrorHandler.Exception(ex); } 
    } 
    } 
}); 

कौन इस तरह प्रयोग किया जाता है:

function DoSomething(a, b, c, d) { 
     document.write(a + b + c) 
     alert(1/e); 
    } 

    var fn2 = DoSomething.TryCatchWrap(); 
    fn2(1, 2, 3, 4); 

कि कोड पूरी तरह से काम करता है

मैं इस कोड, प्रोटोटाइप के Function.wrap पद्धति पर आधारित लिखा था। यह 6 प्रिंट करता है, और फिर मेरे वैश्विक त्रुटि हैंडलर को कॉल करता है।

मेरा प्रश्न है ... क्या यह कुछ तोड़ देगा जब मैं जिस फ़ंक्शन को लपेट रहा हूं वह किसी ऑब्जेक्ट के भीतर है, और यह "यह" ऑपरेटर का उपयोग करता है? मैं थोड़ी चिंतित हूं क्योंकि मैं फोन कर रहा हूं। ठीक है, वहां कुछ गुजर रहा है, मुझे डर है कि यह कुछ तोड़ सकता है।

उत्तर

41

निजी तौर पर प्रदूषण builtin वस्तुओं मैं एक डेकोरेटर तकनीक के साथ जाना होगा के बजाय:

var makeSafe = function(fn){ 
    return function(){ 
    try{ 
     return fn.apply(this, arguments); 
    }catch(ex){ 
     ErrorHandler.Exception(ex); 
    } 
    }; 
}; 

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

function fnOriginal(a){ 
    console.log(1/a); 
}; 

var fn2 = makeSafe(fnOriginal); 
fn2(1); 
fn2(0); 
fn2("abracadabra!"); 

var obj = { 
    method1: function(x){ /* do something */ }, 
    method2: function(x){ /* do something */ } 
}; 

obj.safeMethod1 = makeSafe(obj.method1); 
obj.method1(42);  // the original method 
obj.safeMethod1(42); // the "safe" method 

// let's override a method completely 
obj.method2 = makeSafe(obj.method2); 

लेकिन अगर आप प्रोटोटाइप को संशोधित करने की तरह लग रहा है, आप कर सकते हैं इसे लिखो:

Function.prototype.TryCatchWrap = function(){ 
    var fn = this; // because we call it on the function itself 
    // let's copy the rest from makeSafe() 
    return function(){ 
    try{ 
     return fn.apply(this, arguments); 
    }catch(ex){ 
     ErrorHandler.Exception(ex); 
    } 
    }; 
}; 

स्पष्ट सुधार निर्माता को पैरामीटर बनाना होगा eSafe() ताकि आप निर्दिष्ट कर सकें कि कैच ब्लॉक में कौन सा फ़ंक्शन कॉल करना है।

+0

ठीक है, इसलिए प्रदूषण की प्राथमिकता के अलावा या नहीं ... आपका अंतिम कोड स्निपेट मेरा जैसा दिखता है। क्या मुझे इस से समझना चाहिए कि मेरा कोड ऑब्जेक्ट्स और "यह" कीवर्ड के साथ काम करता है? धन्यवाद! –

+2

हां: आप लपेटकर विधि में "यह" और मूल तर्क दोनों पास करते हैं। लेकिन आप अपना परिणाम वापस नहीं करते हैं, अपूर्ण लपेटते हैं। लेकिन इससे कोई फर्क नहीं पड़ता कि आप एक ऐसा फ़ंक्शन लपेटते हैं जो मूल्य वापस नहीं करता है। –

0

जहां तक ​​नामस्थानों को प्रदूषित किया जाता है, मैं वास्तव में उन्हें और अधिक प्रदूषित करने जा रहा हूं ... चूंकि जेएस में जो कुछ भी होता है उसे किसी प्रकार की घटना से शुरू किया जाता है, मैं अपने जादुई रैपर फ़ंक्शन को कॉल करने की योजना बना रहा हूं प्रोटोटाइप Event.observe() विधि के भीतर से, इसलिए मुझे इसे हर जगह कॉल करने की आवश्यकता नहीं है।

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

आपके उत्तर के लिए धन्यवाद!

+0

अनपेक्षित नाम संघर्ष के अलावा, अंतर्निर्मित निर्मित वस्तुओं को भाषा स्तर पर अजीब त्रुटियों का कारण बन सकता है। यही कारण है कि नए जावास्क्रिप्ट मानक पर काम करना संशोधित करने के लिए "बंद" अंतर्निहित वस्तुओं के बारे में चर्चाओं को पुनर्जीवित किया गया => भविष्य-सबूत कोड को इस तकनीक से बचना चाहिए। –

2

Object.extend (Function.prototype, { गूगल क्रोम कंसोल में Object.extend देता है मुझे 'अनिर्धारित' खैर यहाँ कुछ काम कर उदाहरण है:

Boolean.prototype.XOR = 
// ^- Note that it's a captial 'B' and so 
//  you'll work on the Class and not the >b<oolean object 
     function(bool2) { 

      var bool1 = this.valueOf(); 
      //   'this' refers to the actual object - and not to 'XOR' 

      return (bool1 == true && bool2 == false) 
       || (bool1 == false && bool2 == true); 
     } 

alert ("true.XOR(false) => " true.XOR(false)); 

तो बजाय Object.extend (Function.prototype, {...}) यह पसंद है: Function.prototype.extend = {}

6

2017 जवाब: सिर्फ ES6 का उपयोग करें।

var wrap = function(someFunction){ 
    var wrappedFunction = function(){ 
    var args = [...arguments].splice(0) 
    console.log(`You're about to run a function with these arguments: \n  ${args}`) 
    return someFunction(args) 
    } 
    return wrappedFunction 
} 

उपयोग में::

doThing = wrap(doThing) 

doThing('one', {two:'two'}, 3) 

2016 जवाब: wrap का उपयोग बाहरी पुस्तकालयों की जरूरत के बिना

var doThing = function(){ 
    console.log(...arguments) 
} 

आप अपनी खुद की आवरण समारोह बना सकते हैं: निम्नलिखित डेमो समारोह को देखते हुए मॉड्यूल:

नीचे दिए गए उदाहरण में मैं process.exit() लपेट रहा हूं, लेकिन यह किसी भी अन्य फ़ंक्शन (ब्राउज़र जेएस सहित) के साथ खुशी से काम करता है।

var wrap = require('lodash.wrap'); 

var log = console.log.bind(console) 

var RESTART_FLUSH_DELAY = 3 * 1000 

process.exit = wrap(process.exit, function(originalFunction) { 
    log('Waiting', RESTART_FLUSH_DELAY, 'for buffers to flush before restarting') 
    setTimeout(originalFunction, RESTART_FLUSH_DELAY) 
}); 

process.exit(1); 
संबंधित मुद्दे