মূল উল্লেখ করার সময় একটি জাভাস্ক্রিপ্ট ফাংশন ওভাররাইড করা


160

আমার একটি ফাংশন রয়েছে, a()যা আমি ওভাররাইড করতে চাই, তবে a()প্রসঙ্গের উপর নির্ভর করে মূলটি একটি ক্রমেও সম্পাদন করতে পারি। উদাহরণস্বরূপ, কখনও কখনও যখন আমি একটি পৃষ্ঠা উত্পন্ন করি তখন আমি এটির মতো ওভাররাইড করতে চাই:

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

এবং কখনও কখনও এটির মতো:

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

original_a()ওভার রাইডিংয়ের মধ্যে থেকে আমি কীভাবে এটি পাব a()? এটা কি সম্ভব?

এইভাবে ওভার রাইডিংয়ের বিকল্পগুলি পরামর্শ করবেন না, আমি অনেকেরই জানি। আমি এইভাবে বিশেষভাবে জিজ্ঞাসা করছি।

উত্তর:


179

আপনি এরকম কিছু করতে পারেন:

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কোনও বেনামি ফাংশনের ভিতরে ঘোষণা করা এটি বিশ্বব্যাপী নেমস্পেসকে বিশৃঙ্খলা থেকে বিরত রাখে তবে এটি অভ্যন্তরীণ ফাংশনগুলিতে উপলব্ধ।

মন্তব্যে উল্লিখিত Nerdmaster এর মত, ()শেষে অবশ্যই অন্তর্ভুক্ত করতে ভুলবেন না । আপনি বাইরের ফাংশনটি কল করতে এবং ফলাফলটি (দুটি অভ্যন্তরীণ ফাংশনগুলির মধ্যে একটি) এর মধ্যে aসংরক্ষণ করতে চান, বাহ্যিক ফাংশনটি নিজের মধ্যে সঞ্চয় না করে a


25
আমার মতো সেখানে যে কোনও বোকা লোকের জন্য - শেষে "()" তে ঘনিষ্ঠ মনোযোগ দিন - তা ছাড়া এটি বাহ্যিক ফাংশনটি ফিরিয়ে দেয়, অভ্যন্তরীণ ফাংশনগুলিকে নয় :)
নেড়ডমাস্টার

@ নেটডমাস্টার এটি নির্দেশ করার জন্য ধন্যবাদ। আশা করি লোকেরা লক্ষ্য করতে সহায়তা করার জন্য আমি একটি নোট যুক্ত করেছি।
ম্যাথু ক্রামলে

5
বাহ, আমি নেমস্পেস ছাড়াই এটি করার চেষ্টা করেছি এবং আমি একটি স্ট্যাক ওভারফ্লো পেয়েছি, হ'ল।
গোসুকিভি

আমি মনে করি ফলাফল প্রথম ও শেষ বন্ধনী ফাংশন থেকে অপসারণ করা হলে ফলাফল একই হবে। এখান থেকে (functi..এবং })। শুধু করণ }();একই ফলাফল তৈরি করতে পারে, যেমন (function{})()প্রথম বন্ধনীর প্রথম সেট ব্যবহৃত হয় কারণ আপনি কেবল ঘোষণা করতে পারেন না, বেনামে, ফাংশন এক্সপ্রেশন আপনাকে এটি বরাদ্দ করতে হবে। তবে () করে আপনি কোনও ক্রম ফিরিয়ে দিয়ে কোনও কিছুই সংজ্ঞায়িত করছেন না।
মুহাম্মদ উমার

@ মুহাম্মাদ উমর আপনি ঠিক বলেছেন যে ফাংশন প্রকাশের চারপাশে প্রথম বন্ধনী প্রয়োজনীয় নয়। আমি এগুলি অন্তর্ভুক্ত করেছি কারণ এগুলি ব্যতীত, আপনি যদি কেবল প্রথম দুটি লাইনের দিকে তাকান তবে মনে হয় (অন্তত আমার কাছে) আপনি বাহ্যিক ক্রিয়াটি সরাসরি অর্পণ করছেন a, এটিকে কল না করে এবং ফেরতের মান সংরক্ষণ না করে। প্রথম বন্ধনীগুলি আমাকে জানতে দেয় যে এখানে আরও কিছু চলছে।
ম্যাথু ক্রামলে

88

প্রক্সি প্যাটার্ন আপনি সাহায্য করতে পারেন:

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

উপরেরগুলি "প্রক্সাইড" -ভরিভেবলকে আড়াল করতে একটি ফাংশনে এর কোডটি গুটিয়ে দেয়। এটি একটি বন্ধে jQuery এর সেটআরে-পদ্ধতিটি সংরক্ষণ করে এবং ওভাররাইট করে। প্রক্সি তখন পদ্ধতিতে সমস্ত কলগুলিতে লগ করে এবং কলটিকে মূলটিতে উপস্থাপন করে। প্রয়োগ (এটি, যুক্তি) ব্যবহার করে গ্যারান্টি দেয় যে কলার মূল এবং প্রক্সিড পদ্ধতির মধ্যে পার্থক্যটি লক্ষ্য করতে সক্ষম হবে না।


10
প্রকৃতপক্ষে. 'প্রয়োগ' এবং 'যুক্তি' ব্যবহার অন্যান্য উত্তরগুলির তুলনায় এটিকে আরও শক্তিশালী করে তোলে
রবার্ট লেভি

মনে রাখবেন যে এই প্যাটার্নটির জন্য jQuery এর প্রয়োজন নেই — তারা কেবল উদাহরণ হিসাবে jQuery এর একটি ফাংশন ব্যবহার করছেন।
কেভ

28

ধন্যবাদ ছেলেরা প্রক্সি প্যাটার্নটি সত্যই সহায়তা করেছে ..... আসলে আমি একটি গ্লোবাল ফাংশন 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);
    }
};

এই সত্যই আমাকে সাহায্য করেছে


3
প্রক্সি প্যাটার্নটি অনুসরণ করার সময় , কিছু ক্ষেত্রে এই বিশদটি কার্যকর করা গুরুত্বপূর্ণ যা এই উত্তরের কোডটিতে নেই: পরিবর্তে org_foo(args), কল করুন org_foo.call(this, args)thisউইন্ডো.ফু সাধারণত কল করলে (প্রক্সড হয় না) এমনটিই বজায় রাখে । এই উত্তরটি
cellepo

10

আপনি যেমন একটি কনস্ট্রাক্ট ব্যবহার করে একটি ফাংশন ওভাররাইড করতে পারেন:

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

সম্পাদনা: একটি টাইপ ঠিক করা হয়েছে।


+1 এটি অন্যান্য প্রক্সি প্যাটার্ন উদাহরণগুলির চেয়ে অনেক বেশি পঠনযোগ্য!
মিঃ মাইন্ড

1
... তবে আমি যদি ভুল না হয়ে থাকি তবে এটি শূন্য-যুক্তি ফাংশন বা কমপক্ষে কিছু পূর্বনির্ধারিত সংখ্যার মধ্যে সীমাবদ্ধ। পাঠযোগ্যতা হারাতে না পেরে এটিকে নির্বিচারে সংখ্যক যুক্তিতে সাধারণ করার কোনও উপায় আছে কি?
মিঃ মাইন্ড

@ মিউমাইন্ড: হ্যাঁ, তবে প্রক্সি প্যাটার্নটি সঠিকভাবে ব্যবহার করা - আমার উত্তর দেখুন
ড্যান ড্যাসক্লেস্কু

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যদিও উল্লেখ ?
জোনাথন

2

@ ম্যাথেজ ক্রামলে যে উত্তরটি সরবরাহ করে তা তাত্ক্ষণিকভাবে অনুরোধ করা ফাংশন এক্সপ্রেশনগুলি ব্যবহার করে পুরানো 'এ' ফাংশনটি ফিরে ফাংশনের সম্পাদনের প্রসঙ্গে বন্ধ করে দেয়। আমি মনে করি এটি সেরা উত্তর ছিল, তবে ব্যক্তিগতভাবে আমি আইআইএফইয়ের পক্ষে যুক্তি হিসাবে 'ক' ফাংশনটি পাস করতে পছন্দ করব। আমি মনে করি এটি আরও বোধগম্য।

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

1

উপরের উদাহরণগুলি সঠিকভাবে প্রয়োগ করে না thisবা argumentsসঠিকভাবে ফাংশন ওভাররাইডে পাস করে না। অ্যান্ডস্কোর _.আর্যাপ () বিদ্যমান ফাংশনগুলি মোড়ানো, প্রয়োগ করে thisএবং argumentsসঠিকভাবে পাস করে । দেখুন: http://underscorejs.org/#wrap


0

আমার অন্য কারো দ্বারা লিখিত কিছু কোড ছিল এবং আমি কোনও ফাংশনে একটি লাইন যুক্ত করতে চেয়েছিলাম যা আমি কোডটিতে খুঁজে পাই না। সুতরাং একটি workaround হিসাবে আমি এটি ওভাররাইড করতে চেয়েছিলেন।

সমাধানগুলির কোনওটিই যদিও আমার পক্ষে কাজ করে নি।

আমার ক্ষেত্রে যা কাজ করেছে তা এখানে:

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

তবে ES6 সিনট্যাক্স ব্যবহার এটি ব্যবহারের পরিবর্তে সীমাবদ্ধ করে তোলে। আপনার কি ES5 তে কাজ করে এমন কোনও সংস্করণ রয়েছে?
ইচ

0

সুতরাং আমার উত্তরটি এমন একটি সমাধান হিসাবে শেষ হয়েছে যা আমাকে মূল অবজেক্টের দিকে নির্দেশ করে এই ভেরিয়েবলটি ব্যবহার করতে দেয়। আমি একটি "স্কয়ার" এর একটি নতুন উদাহরণ তৈরি করি তবে "স্কয়ার" এর আকারটি যেভাবে উত্পন্ন হয়েছিল তা আমি ঘৃণা করি। আমি ভেবেছিলাম এটি আমার নির্দিষ্ট চাহিদা অনুসরণ করা উচিত। তবে এটি করার জন্য আমার স্কয়ারটির একটি নতুন "গেটসাইজ" ফাংশন থাকার দরকার ছিল that ফাংশনের ইন্টার্নালগুলির সাথে ইতিমধ্যে স্কয়ারের অন্যান্য ফাংশনগুলিকে ডেকেছিল যেমন এই.হাইট, এটি.গেটভলিউম ()। তবে এটি করার জন্য আমার কোনও পাগল হ্যাক ছাড়াই এটি করা দরকার ছিল। সুতরাং এখানে আমার সমাধান।

অন্য কিছু অবজেক্ট ইনিশিয়ালাইজার বা সহায়তা সহায়ক।

this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(
  this.viewerContainer)
var viewer = this.viewer;
viewer.updateToolbarButtons =  this.updateToolbarButtons(viewer);

অন্য বস্তুতে ফাংশন।

updateToolbarButtons = function(viewer) {
  var _viewer = viewer;
  return function(width, height){ 
blah blah black sheep I can refer to this.anything();
}
};

0

এটি সব পরিস্থিতিতে কার্যকর হবে কিনা তা নিশ্চিত নয়, তবে আমাদের ক্ষেত্রে আমরা describeজেস্টে ফাংশনটি ওভাররাইড করার চেষ্টা করছিলাম যাতে আমরা নামটি বিশ্লেষণ করতে পারি এবং describeএটি যদি কিছু মানদণ্ড পূরণ করে তবে পুরো ব্লকটি এড়িয়ে যেতে পারি।

আমাদের জন্য কি কাজ করেছে তা এখানে:

function describe( name, callback ) {
  if ( name.includes( "skip" ) )
    return this.describe.skip( name, callback );
  else
    return this.describe( name, callback );
}

দুটি বিষয় যা এখানে গুরুত্বপূর্ণ:

  1. আমরা একটি তীর ফাংশন ব্যবহার করি না () =>

    তীর ফাংশনগুলি রেফারেন্স পরিবর্তন করে thisএবং আমাদের এটি ফাইলের হওয়া দরকার this

  2. ব্যবহারের this.describeএবং this.describe.skipপরিবর্তে শুধু describeএবং describe.skip

আবার, নিশ্চিত না এটা কেহ মূল্যের কিন্তু আমরা মূলত দিয়ে পার পেতে করার চেষ্টা ম্যাথু Crumley এর চমৎকার উত্তর কিন্তু আমাদের পদ্ধতি একটি ফাংশন করতে এবং যাতে তাদের শর্তাধীন মধ্যে পার্স করার জন্য প্যারাম গ্রহণ করা প্রয়োজন।

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