जावास्क्रिप्ट: एक समारोह का विस्तार


94

मुख्य कारण जो मैं चाहता हूं कि यह है कि मैं अपने इनिशियल फंक्शन को बढ़ाना चाहता हूं।

कुछ इस तरह:

// main.js

window.onload = init();
function init(){
     doSomething();
}

// extend.js

function extends init(){
    doSomethingHereToo();
}

इसलिए मैं एक फ़ंक्शन का विस्तार करना चाहता हूं जैसे कि मैं PHP में एक वर्ग का विस्तार करता हूं।

और मैं इसे अन्य फ़ाइलों से भी विस्तारित करना चाहूंगा, इसलिए उदाहरण के लिए मेरे पास मूल इनिट फ़ंक्शन main.jsऔर विस्तारित फ़ंक्शन है extended.js



जवाबों:


103

आप वास्तव में क्या करने की कोशिश कर रहे हैं और जिस संदर्भ में आप यह कर रहे हैं, उसके व्यापक दृष्टिकोण के साथ, मुझे यकीन है कि हम आपको आपके प्रश्न के शाब्दिक उत्तर से बेहतर उत्तर दे सकते हैं ।

लेकिन यहाँ एक शाब्दिक जवाब है:

यदि आप इन कार्यों को कुछ संपत्ति के लिए सौंप रहे हैं, तो आप मूल फ़ंक्शन को लपेट सकते हैं और इसके स्थान पर अपना प्रतिस्थापन डाल सकते हैं:

// Original code in main.js
var theProperty = init;

function init(){
     doSomething();
}

// Extending it by replacing and wrapping, in extended.js
theProperty = (function(old) {
    function extendsInit() {
        old();
        doSomething();
    }

    return extendsInit;
})(theProperty);

यदि आपके कार्य पहले से ही किसी वस्तु पर नहीं हैं, तो आप उन्हें ऊपर की सुविधा के लिए रखना चाहते हैं। उदाहरण के लिए:

// In main.js
var MyLibrary = (function() {
    var publicSymbols = {};

    publicSymbols.init = init;
    function init() {
    }

    return publicSymbols;
})();

// In extended.js
(function() {
    var oldInit = MyLibrary.init;
    MyLibrary.init = extendedInit;
    function extendedInit() {
        oldInit.apply(MyLibrary); // Use #apply in case `init` uses `this`
        doSomething();
    }
})();

लेकिन देखते हैं इस तरह के बेहतर तरीके है कि क्या करना है। उदाहरण के लिए, पंजीकरण initकार्यों के साधन उपलब्ध कराना ।

// In main.js
var MyLibrary = (function() {
    var publicSymbols = {},
        initfunctions = [];

    publicSymbols.init = init;
    function init() {
        var funcs = initFunctions;

        initFunctions = undefined;

        for (index = 0; index < funcs.length; ++index) {
            try { funcs[index](); } catch (e) { }
        }
    }

    publicSymbols.addInitFunction = addInitFunction;
    function addInitFunction(f) {
        if (initFunctions) {
            // Init hasn't run yet, rememeber it
            initFunctions.push(f);
        }
        else {
            // `init` has already run, call it almost immediately
            // but *asynchronously* (so the caller never sees the
            // call synchronously)
            setTimeout(f, 0);
        }
    }

    return publicSymbols;
})();

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


एक महान जवाब के लिए धन्यवाद। दूसरे उदाहरण के साथ मेरी समस्या यह है कि मुझे जिस फ़ंक्शन का विस्तार हो रहा है, उसके परिणाम की आवश्यकता हो सकती है।
गेरहार्ड डेविड्स

64

इसके बारे में जाने के कई तरीके हैं, यह इस बात पर निर्भर करता है कि आपका उद्देश्य क्या है, यदि आप केवल फ़ंक्शन को निष्पादित करना चाहते हैं और उसी संदर्भ में, आप इसका उपयोग कर सकते हैं .apply():

function init(){
  doSomething();
}
function myFunc(){
  init.apply(this, arguments);
  doSomethingHereToo();
}

यदि आप इसे एक नए के साथ बदलना चाहते हैं init, तो यह इस तरह दिखेगा:

function init(){
  doSomething();
}
//anytime later
var old_init = init;
init = function() {
  old_init.apply(this, arguments);
  doSomethingHereToo();
};

2
कभी-कभी आप .callइसके बजाय विधि चाहते हो सकता है .applyयह StackOverflow प्रश्न देखें ।
मृदाना

@ ठीक है, मुझे आपका जावास्क्रिप्ट उदाहरण एक मौजूदा फ़ंक्शन को बहुत उपयोगी बनाने के लिए मिला है, लेकिन मैं उत्सुक था कि यह वही काम कैसे किया जाएगा?
सुनील

+1 धन्यवाद। यह वास्तव में आसान है यदि आप मूल js को संशोधित किए बिना कुछ 3 पार्टी प्लगइन को पैच करना चाहते हैं।
GFoley83

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

5

अन्य विधियां महान हैं, लेकिन वे init से जुड़े किसी भी प्रोटोटाइप फ़ंक्शन को संरक्षित नहीं करते हैं। चारों ओर पाने के लिए आप निम्न (निक क्रैवर के पोस्ट से प्रेरित) कर सकते हैं।

(function () {
    var old_prototype = init.prototype;
    var old_init = init;
    init = function () {
        old_init.apply(this, arguments);
        // Do something extra
    };
    init.prototype = old_prototype;
}) ();

5

एक और विकल्प हो सकता है:

var initial = function() {
    console.log( 'initial function!' );
}

var iWantToExecuteThisOneToo = function () {
    console.log( 'the other function that i wanted to execute!' );
}

function extendFunction( oldOne, newOne ) {
    return (function() {
        oldOne();
        newOne();
    })();
}

var extendedFunction = extendFunction( initial, iWantToExecuteThisOneToo );

0

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

पहले हमें जावास्क्रिप्ट फ़ंक्शन का विस्तार करने दें।

function Base(props) {
    const _props = props
    this.getProps = () => _props

    // We can make method private by not binding it to this object. 
    // Hence it is not exposed when we return this.
    const privateMethod = () => "do internal stuff" 

    return this
}

आप निम्न तरीके से बाल फ़ंक्शन बनाकर इस फ़ंक्शन का विस्तार कर सकते हैं

function Child(props) {
    const parent = Base(props)
    this.getMessage = () => `Message is ${parent.getProps()}`;

    // You can remove the line below to extend as in private inheritance, 
    // not exposing parent function properties and method.
    this.prototype = parent
    return this
}

अब आप निम्न प्रकार से बाल फ़ंक्शन का उपयोग कर सकते हैं,

let childObject = Child("Secret Message")
console.log(childObject.getMessage())     // logs "Message is Secret Message"
console.log(childObject.getProps())       // logs "Secret Message"

हम इस तरह से जावास्क्रिप्ट क्लासेस को बढ़ाकर जावास्क्रिप्ट फंक्शन भी बना सकते हैं।

class BaseClass {
    constructor(props) {
        this.props = props
        // You can remove the line below to make getProps method private. 
        // As it will not be binded to this, but let it be
        this.getProps = this.getProps.bind(this)
    }

    getProps() {
        return this.props
    }
}

आइए हम इस तरह से चाइल्ड फंक्शन के साथ इस वर्ग का विस्तार करें,

function Child(props) {
    let parent = new BaseClass(props)
    const getMessage = () => `Message is ${parent.getProps()}`;
    return { ...parent, getMessage} // I have used spread operator. 
}

फिर से आप इसी तरह के परिणाम प्राप्त करने के लिए बाल फ़ंक्शन का उपयोग कर सकते हैं,

let childObject = Child("Secret Message")
console.log(childObject.getMessage())     // logs "Message is Secret Message"
console.log(childObject.getProps())       // logs "Secret Message"

जावास्क्रिप्ट बहुत आसान भाषा है। हम लगभग कुछ भी कर सकते हैं। हैप्पी जावास्क्रिप्ट ... आशा है कि मैं आपको अपने मामले में उपयोग करने के लिए एक विचार देने में सक्षम था।


-1

ExpandFunction.js का उपयोग करें

init = extendFunction(init, function(args) {
  doSomethingHereToo();
});

लेकिन आपके विशिष्ट मामले में, वैश्विक ऑनलोड फ़ंक्शन को बढ़ाना आसान है:

extendFunction('onload', function(args) {
  doSomethingHereToo();
});

मैं वास्तव में आपके प्रश्न को पसंद करता हूं, यह मुझे अलग-अलग उपयोग के मामलों के बारे में सोचने पर मजबूर कर रहा है।

जावास्क्रिप्ट घटनाओं के लिए, आप वास्तव में हैंडलर जोड़ना और निकालना चाहते हैं - लेकिन विस्तार के लिए, आप बाद में कैसे निकाल सकते हैं कार्यक्षमता ? मैं आसानी से विस्तारित कार्यों के लिए एक -revert विधि जोड़ सकता है, इसलिए init = init.revert()मूल फ़ंक्शन वापस कर देगा। जाहिर है कि यह कुछ बहुत बुरा कोड हो सकता है, लेकिन शायद यह आपको कोडबेस के एक विदेशी हिस्से को छूने के बिना कुछ करने की अनुमति देता है।

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