জাভাস্ক্রিপ্ট: একটি ফাংশন প্রসারিত করুন


97

আমি এটি কেন চাই তার মূল কারণটি হ'ল আমি আমার প্রাথমিক ক্রিয়াকে প্রসারিত করতে চাই।

এটার মতো কিছু:

// main.js

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

// extend.js

function extends init(){
    doSomethingHereToo();
}

সুতরাং আমি পিএইচপি-তে ক্লাস বাড়িয়ে দেওয়ার মতো একটি ফাংশন বাড়িয়ে দিতে চাই।

এবং আমি এটি অন্যান্য ফাইলগুলি থেকেও প্রসারিত করতে চাই, উদাহরণস্বরূপ আমার কাছে আসল আর ডি ফাংশনটি main.jsএবং এর মধ্যে বর্ধিত ফাংশন রয়েছে extended.js



উত্তর:


106

আপনি আসলে যা করার চেষ্টা করছেন এবং যে প্রসঙ্গে আপনি এটি করছেন তার বিস্তৃত দর্শন সহ আমি নিশ্চিত যে আমরা আপনাকে আপনার প্রশ্নের আক্ষরিক উত্তরের চেয়ে আরও ভাল উত্তর দিতে পারব ।

তবে এখানে একটি আক্ষরিক উত্তর:

আপনি যদি কোথাও কোনও সম্পত্তিতে এই ফাংশনগুলি বরাদ্দ করেন তবে আপনি মূল ফাংশনটি মোড়ানো করতে পারেন এবং পরিবর্তে সম্পত্তির উপর প্রতিস্থাপন করতে পারেন:

// 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 = {
    init: function init() {
    }
};

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

তবে এটি করার আরও ভাল উপায় রয়েছে। উদাহরণস্বরূপ, initফাংশনগুলির নিবন্ধকরণের একটি মাধ্যম সরবরাহ করা ।

// In main.js
var MyLibrary = (function() {
    var initFunctions = [];
    return {
        init: function init() {
            var fns = initFunctions;
            initFunctions = undefined;
            for (var index = 0; index < fns.length; ++index) {
                try { fns[index](); } catch (e) { }
            }
        },
        addInitFunction: function addInitFunction(fn) {
            if (initFunctions) {
                // Init hasn't run yet, remember it
                initFunctions.push(fn);
            } else {
                // `init` has already run, call it almost immediately
                // but *asynchronously* (so the caller never sees the
                // call synchronously)
                setTimeout(fn, 0);
            }
        }
    };
})();

এখানে ২০২০ সালে (বা সত্যিকারের যে কোনও সময় ২০১ after সালের পরে), এটি আরও কিছুটা সংক্ষিপ্তভাবে লেখা যেতে পারে:

// In main.js
const MyLibrary = (() => {
    let initFunctions = [];
    return {
        init() {
            const fns = initFunctions;
            initFunctions = undefined;
            for (const fn of fns) {
                try { fn(); } catch (e) { }
            }
        },
        addInitFunction(fn) {
            if (initFunctions) {
                // Init hasn't run yet, remember it
                initFunctions.push(fn);
            } else {
                // `init` has already run, call it almost immediately
                // but *asynchronously* (so the caller never sees the
                // call synchronously)
                setTimeout(fn, 0);
                // Or: `Promise.resolve().then(() => fn());`
                // (Not `.then(fn)` just to avoid passing it an argument)
            }
        }
    };
})();

একটি দুর্দান্ত উত্তরের জন্য ধন্যবাদ। দ্বিতীয় উদাহরণটির সাথে আমার সমস্যাটি হ'ল আমি যে ফাংশনটি বাড়িয়ে দিচ্ছি তার ফলাফলের প্রয়োজন হতে পারে।
গারহার্ড ডেভিড

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();
};

4
কখনও কখনও আপনি এর .callপরিবর্তে পদ্ধতিটি চাইতে পারেন .apply। দেখুন এই Stackoverflow প্রশ্ন।
মিঃডানআ

@ নিক, বিদ্যমান ফাংশনটি খুব কার্যকর করার জন্য আমি আপনার জাভাস্ক্রিপ্টের উদাহরণটি পেয়েছি, তবে আমি আগ্রহী ছিলাম কীভাবে jQuery এর মাধ্যমে এই একই জিনিসটি করা হবে?
সুনীল

+1 ধন্যবাদ আপনি যদি আসল জেএস সংশোধন না করে কিছু তৃতীয় পক্ষের প্লাগইন প্যাচ করতে চান তবে এটি সত্যিই সহজ।
GFoley83

4
প্যারামিটারগুলি এবং প্রত্যাবর্তনের মানগুলি প্রত্যাশা করে এমন ফাংশনগুলির সাথে এটি কীভাবে ব্যবহার করবেন তা নিশ্চিত নন।
জিফ্রিড

5

অন্যান্য পদ্ধতিগুলি দুর্দান্ত তবে তারা আরআইডি সংযুক্ত কোনও প্রোটোটাইপ ফাংশন সংরক্ষণ করে না। এটি পেতে আপনি নিম্নলিখিতগুলি করতে পারেন (নিক ক্র্যাভারের পোস্ট দ্বারা অনুপ্রাণিত)।

(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 );

1

2017+ সমাধান

ফাংশন এক্সটেনশনের ধারণাটি কার্যকরী দৃষ্টান্ত থেকে আসে, যা ES6 থেকে স্থানীয়ভাবে সমর্থিত:

function init(){
    doSomething();
}

// extend.js

init = (f => u => { f(u)
    doSomethingHereToo();
})(init);

init();

স্ট্যাক ডাম্প সম্পর্কে @ টিজে ক্রাউডারের উদ্বেগ অনুসারে, ব্রাউজারগুলি আজ পরিস্থিতি আরও ভালভাবে পরিচালনা করছে। আপনি যদি এই কোডটিকে পরীক্ষার হারে html এ সঞ্চয় করেন এবং এটি চালান, আপনি পাবেন

test.html:3 Uncaught ReferenceError: doSomething is not defined
    at init (test.html:3)
    at test.html:8
    at test.html:12

লাইন 12: আরম্ভ কল, লাইন 8: আরম্ভ এক্সটেনশন, লাইন 3: অপরিজ্ঞাত doSomething()কল।

দ্রষ্টব্য: প্রবীণ টিজে ক্রোডারকে অনেক শ্রদ্ধা, যিনি বহু বছর আগে আমার প্রশ্নটির সদয়ভাবে উত্তর দিয়েছিলেন, যখন আমি নবাগত ছিলাম। বছর পরে, আমি এখনও সম্মানজনক মনোভাব মনে করি এবং আমি ভাল উদাহরণ অনুসরণ করার চেষ্টা করি।


"স্ট্যাক ডাম্প সম্পর্কে @ টিজে ক্রাউডারের উদ্বেগ অনুসারে, ব্রাউজারগুলি আজ পরিস্থিতি আরও ভালভাবে পরিচালনা করছে" " প্রকৃতপক্ষে, এবং এই উন্নতিগুলি স্পেসিফিকেশনটিতে কোডিংও হয়েছে। (আমি এমনকি বেনামে ইস্যুটি এড়িয়ে যেতে পারতাম, এমনকি ২০১১ সালেও, নামযুক্ত ফাংশন এক্সপ্রেশন সহ; আইই আইআই ৮ এবং এর নীচে ভুল হয়ে গেলেও এটি যেভাবে তাদের ভুল করে সেভাবে ক্ষতিহীন হত Live লাইভ এবং শিখুন: :-))
টিজে ক্রাউডার

(এবং অত্যন্ত সদয় মন্তব্যের জন্য আপনাকে ধন্যবাদ। সত্যই প্রশংসা!)
টিজে ক্রোডার

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

এক্সটেন্ডফানশন.জেএস ব্যবহার করুন

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

তবে আপনার নির্দিষ্ট ক্ষেত্রে, বিশ্বব্যাপী লোড ফাংশনটি বাড়ানো আরও সহজ:

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

আমি আসলে আপনার প্রশ্নটি সত্যিই পছন্দ করি, এটি আমাকে বিভিন্ন ব্যবহারের ক্ষেত্রে চিন্তা করতে বাধ্য করে।

জাভাস্ক্রিপ্ট ইভেন্টগুলির জন্য, আপনি হ্যান্ডলারগুলি সত্যিই যুক্ত এবং মুছে ফেলতে চান - তবে এক্সটেন্ডফানশনের জন্য, আপনি কীভাবে পরে কার্যকারিতা সরিয়ে ফেলতে পারেন ? আমি সহজেই প্রসারিত পদ্ধতিতে প্রসারিত ফাংশনে যুক্ত করতে পারতাম, সুতরাং init = init.revert()আসল ফাংশনটি ফিরে আসত। অবশ্যই এটি কিছু সুন্দর কোডের দিকে নিয়ে যেতে পারে, তবে সম্ভবত এটি আপনাকে কোডবেজের কোনও বিদেশী অংশ স্পর্শ না করেই কিছু করতে দেয় something

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.