জাভাস্ক্রিপ্টে ফাংশন যা কেবল একবার কল করা যেতে পারে


116

আমার এমন একটি ক্রিয়াকলাপ তৈরি করা দরকার যা কেবল একবারেই কার্যকর করা যায়, প্রথমবারের পরে প্রতিটি সময়ে এটি কার্যকর করা হবে না। আমি স্ট্যাটিক ভেরিয়েবল সম্পর্কে সি ++ এবং জাভা থেকে জানি যা কাজটি করতে পারে তবে আমি আরও জানতে চাই যে এটি করার জন্য আরও মার্জিত উপায় আছে কিনা?


Years 8 বছর পরে আমি আমার সাজসজ্জারকে lib ( github.com/vlio20/utils-decorators ) এর জন্য একটি বৈশিষ্ট্য অনুরোধ তৈরি করেছি যা ঠিক এমনটি করবে ( github.com/vlio20/utils-decorators/issues/77 )
vlio20

উত্তর:


221

যদি "মৃত্যুদন্ড কার্যকর করা হবে না" এর অর্থ যদি আপনি "একবারে একাধিকবার ডাকা হয় তখন কিছুই করেন না", আপনি একটি বন্ধন তৈরি করতে পারেন:

var something = (function() {
    var executed = false;
    return function() {
        if (!executed) {
            executed = true;
            // do something
        }
    };
})();

something(); // "do something" happens
something(); // nothing happens

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

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

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

function once(fn, context) { 
    var result;
    return function() { 
        if (fn) {
            result = fn.apply(context || this, arguments);
            fn = null;
        }
        return result;
    };
}

আমি পরিবর্তন fn = null;করতে ঝোঁক হবে fn = context = null;contextএকবারে কোনও রেফারেন্স ধরে রাখার জন্য বন্ধের কোনও কারণ নেই fn

[*] তবে সচেতন থাকুন যে, অন্যান্য লাইব্রেরিগুলিতে, যেমন এই ডুপ্লাল এক্সটেনশন যেমন জিকুয়েরিতে , একটি ফাংশন নামের থাকতে পারে once()যা কিছু আলাদা করে।


1
খুব ভাল কাজ করে, আপনি কি এর পিছনে লগইনটি ব্যাখ্যা করতে পারবেন, কীভাবে কার্যকর হবে = মিথ্যা; কাজ করে
Amr.Ayoub

@ এজিকোড - ক্লোজারগুলি সম্পর্কিত এমডিএন ডকুমেন্টেশনে এটি দুর্দান্তভাবে ব্যাখ্যা করা হয়েছে ।
টেড হপ

দুঃখিত, আমি যুক্তি বোঝাতে
চাইছিলাম

1
@EgyCode - কিছু প্রেক্ষিতে (একটি মত ifবিবৃতি পরীক্ষা অভিব্যক্তি), জাভাস্ক্রিপ্ট মান এক আশা trueবা falseএবং মান অনুযায়ী প্রোগ্রাম প্রবাহ ক্ষীণভাবে যখন অভিব্যক্তি মূল্যায়ন করা হয় পাওয়া যায় নি। শর্তসাপেক্ষ অপারেটররা ==সর্বদা একটি বুলিয়ান মানকে মূল্যায়ন করে। একটি ভেরিয়েবলও হয় trueবা ধরে রাখতে পারে false। (আরও তথ্যের জন্য, বুলিয়ান , সত্যবাদী এবং মিথ্যা সম্পর্কিত ডকুমেন্টেশন দেখুন ))
টেড হপ

আমি বুঝতে পারি না যে মৃত্যুদন্ড কার্যকর করা প্রত্যেকটি নতুন কল দিয়ে পুনরায় সেট করা হয় না। দয়া করে কেউ এটি ব্যাখ্যা করতে পারেন?
জুয়ানস কোরা

64

এটি পুনরায় ব্যবহারযোগ্য NOOP (কোনও অপারেশন নয়) ফাংশন দিয়ে প্রতিস্থাপন করুন ।

// this function does nothing
function noop() {};

function foo() {
    foo = noop; // swap the functions

    // do your thing
}

function bar() {
    bar = noop; // swap the functions

    // do your thing
}

11
@ ফ্যাবলাল: এটি কীভাবে অযোগ্য? আবার এটি খুব পরিষ্কার, কম কোডের প্রয়োজন, এবং প্রতিটি ক্রিয়াকলাপের জন্য নতুন পরিবর্তনশীলের প্রয়োজন নেই যা অক্ষম করা উচিত। একটি "নুপ" ঠিক এই ধরণের পরিস্থিতির জন্য ডিজাইন করা হয়েছে।
আমি অলস ঘৃণা

1
@ ফ্যাবলাল: আমি কেবল হাকরার উত্তরের দিকে চেয়েছিলাম। সুতরাং প্রতিবার নতুন ফাংশনটি করার জন্য একটি নতুন ক্লোজার এবং ভেরিয়েবল তৈরি করুন? আপনার কাছে "মার্জিত" এর খুব মজার সংজ্ঞা রয়েছে।
আমি অলসকে ঘৃণা করি

2
Asawyer এর প্রতিক্রিয়া অনুসারে, আপনাকে কেবল _.once (foo) বা _.once (বার) করার দরকার ছিল এবং ফাংশনগুলি কেবল একবার চালানো সম্পর্কে সচেতন হওয়ার প্রয়োজন নেই (নূরের প্রয়োজন নেই এবং প্রয়োজন নেই) the * = noop)।
কাল্পনিক

7
সত্যিই সেরা সমাধান নয়। যদি আপনি এই ফাংশনটিকে কলব্যাক হিসাবে পাস করেন তবে এটি একাধিকবার কল করা যেতে পারে। উদাহরণস্বরূপ: setInterval(foo, 1000)- এবং ইতিমধ্যে এটি আর কাজ করে না। আপনি কেবল বর্তমান স্কোপে রেফারেন্সটি ওভাররাইট করছেন।
একটি বিড়াল

1
পুনর্ব্যবহারযোগ্য invalidateফাংশন যা দিয়ে কাজ করে setIntervalইত্যাদি। Jsbin.com/vicipar/1/edit?js,console
Q20

32

একটি নির্দেশ খালি ফাংশন একবার এটা বলা হয়েছে:

function myFunc(){
     myFunc = function(){}; // kill it as soon as it was called
     console.log('call once and never again!'); // your stuff here
};
<button onClick=myFunc()>Call myFunc()</button>


বা, যেমন:

var myFunc = function func(){
     if( myFunc.fired ) return;
     myFunc.fired = true;
     console.log('called once and never again!'); // your stuff here
};

// even if referenced & "renamed"
((refToMyfunc)=>{
  setInterval(refToMyfunc, 1000);
})(myFunc)


1
এই সমাধানটি জাভাস্ক্রিপ্টের মতো উচ্চ গতিশীল ভাষার চেতনায় আরও অনেক বেশি। কেন সেমফোরস সেট করুন, যখন আপনি কেবল ফাংশনটি ব্যবহার করার পরে খালি করতে পারবেন?
ইভান inurinjaković

খুব সুন্দর সমাধান! এই সমাধানটি ক্লোজার পদ্ধতির চেয়েও ভাল সম্পাদন করছে। একমাত্র গৌণ "অপূর্ণতা" হ'ল নাম পরিবর্তন হলে আপনার ফাংশনটির নাম সিঙ্কে রাখা দরকার।
লিওনেল

5
এর সাথে সমস্যাটি হ'ল যদি কোথাও ফাংশনটির অন্য কোনও রেফারেন্স থাকে (যেমন এটি একটি আর্গুমেন্ট হিসাবে পাস হয়েছিল এবং অন্য কোনও পরিবর্তনশীল হিসাবে স্থির করা হয়েছিল - যেমন একটি কল হিসাবে setInterval()) তবে রেফারেন্স কল করার সময় মূল কার্যকারিতা পুনরাবৃত্তি করবে।
টেড হপ্প

@ টেডহপ্প - এই ক্ষেত্রেগুলির জন্য এখানে একটি বিশেষ চিকিত্সা রয়েছে
ভ্যানসিঙ্ক 5'16

1
হ্যাঁ, এটি এই থ্রেডে বুনিকের উত্তরের মতো । এটি ক্লোজারের মতো ( আমার উত্তর হিসাবে ) তবে ক্লোজার ভেরিয়েবলের পরিবর্তে সম্পত্তি ব্যবহার করা। উভয় ক্ষেত্রেই এই উত্তরের আপনার পদ্ধতির থেকে পৃথক।
টেড হপ্প

25

UnderscoreJs একটি ফাংশন যে, না হয়েছে underscorejs.org/#once

  // Returns a function that will be executed at most one time, no matter how
  // often you call it. Useful for lazy initialization.
  _.once = function(func) {
    var ran = false, memo;
    return function() {
      if (ran) return memo;
      ran = true;
      memo = func.apply(this, arguments);
      func = null;
      return memo;
    };
  };

1
onceযুক্তি গ্রহণ করা আমার কাছে মজার মনে হয় । আপনি করতে squareo = _.once(square); console.log(squareo(1)); console.log(squareo(2));এবং 1উভয় কল করতে পারেন squareo। আমি কি এই অধিকার বুঝতে পারি?

@ এস্কমিড আপনি সঠিক - প্রথম অন্তর্নিহিত ফাংশনটি আর কখনও কল করা হয়নি বলে প্যারামিটার নির্বিশেষে সমস্ত কলগুলির সেটগুলির যুক্তিগুলির ফলাফল স্মরণীয় করে ফেলা হবে। এর মতো ক্ষেত্রে আমি _.onceপদ্ধতিটি ব্যবহার করার পরামর্শ দিই না । দেখুন jsfiddle.net/631tgc5f/1
asawyer

1
@ অ্যাশমিড বা আমি অনুমান করি যে প্রতি যুক্তি সংস্থায় একবার আলাদা কল ব্যবহার করা হবে। আমি মনে করি না যে এটি সত্যই এই ধরণের ব্যবহারের জন্য তৈরি।
asawyer

1
আপনি যদি ইতিমধ্যে ব্যবহার করছেন সহজ _; আমি এত ছোট কোডের জন্য পুরো লাইব্রেরির উপর নির্ভর করে প্রস্তাব দেব না।
জো শানাহান

11

স্ট্যাটিক ভেরিয়েবল সম্পর্কে কথা বলছি, এটি ক্লোজার বৈকল্পের মতো কিছুটা:

var once = function() {
    if(once.done) return;
    console.log('Doing this once!');
    once.done = true;
};

once(); once(); 

আপনি যদি চান তবে একটি ফাংশন পুনরায় সেট করতে পারেন:

once.done = false;

4
var quit = false;

function something() {
    if(quit) {
       return;
    } 
    quit = true;
    ... other code....
}

টেড হপ্পের প্রতিক্রিয়া দেখুন। এটি ফাংশন-স্তরের ভেরিয়েবলগুলি স্কোপ করার একটি উপায়।
ডায়োডিয়াস - জেমস ম্যাকফার্লেন

3

আপনি কেবল "নিজেকে সরান" ফাংশনটি করতে পারেন

function Once(){
    console.log("run");

    Once = undefined;
}

Once();  // run
Once();  // Uncaught TypeError: undefined is not a function 

তবে আপনি যদি ত্রুটি গিলতে না চান তবে এটি সেরা উত্তর হতে পারে না।

আপনি এটি করতে পারেন:

function Once(){
    console.log("run");

    Once = function(){};
}

Once(); // run
Once(); // nothing happens

আমার এটি স্মার্ট পয়েন্টারের মতো কাজ করা দরকার, টাইপ এ এর ​​কোনও উপাদান না থাকলে এটি কার্যকর করা যায়, যদি এক বা একাধিক এ উপাদান থাকে তবে ফাংশনটি কার্যকর করা যায় না।

function Conditional(){
    if (!<no elements from type A>) return;

    // do stuff
}

1
আমার এটি স্মার্ট পয়েন্টারের মতো কাজ করা দরকার, টাইপ এ এর ​​কোনও উপাদান না থাকলে এটি কার্যকর করা যায়, যদি এক বা একাধিক এ উপাদান থাকে তবে ফাংশনটি কার্যকর করা যায় না।
vlio20

পছন্দ করেছেন
শ্মিদ্দী

Onceকল-ব্যাক (যেমন, setInterval(Once, 100)) হিসাবে পাস করা হলে এটি কাজ করবে না । আসল ফাংশন কল করা অবিরত থাকবে।
টেড হপ্প

2

এটা চেষ্টা কর

var fun = (function() {
  var called = false;
  return function() {
    if (!called) {
      console.log("I  called");
      called = true;
    }
  }
})()

2

ক্রোকফোর্ড নামের কিছু ছেলে থেকে ... :)

function once(func) {
    return function () {
        var f = func;
        func = null;
        return f.apply(
            this,
            arguments
        );
    };
}

1
এটি দুর্দান্ত বলে আপনি যদি দুর্দান্ত মনে করেন TypeError: Cannot read property 'apply' of null। আপনি দ্বিতীয় বার ফিরে আসা ফাংশনটি শুরু করার জন্য এটি পান।
টেড হপ্প

2

পুনরায় ব্যবহারযোগ্য invalidateফাংশন যা এর সাথে কাজ করে setInterval:

var myFunc = function (){
  if (invalidate(arguments)) return;
  console.log('called once and never again!'); // your stuff here
};

const invalidate = function(a) {
  var fired = a.callee.fired;
  a.callee.fired = true;
  return fired;
}

setInterval(myFunc, 1000);

এটি জেএসবিনে ব্যবহার করে দেখুন: https://jsbin.com/vicipar/edit?js,console

প্রকরণ Bunyk থেকে উত্তর


1

এখানে একটি উদাহরণ জেএসফিডাল - http://jsfiddle.net/6yL6t/

এবং কোড:

function hashCode(str) {
    var hash = 0, i, chr, len;
    if (str.length == 0) return hash;
    for (i = 0, len = str.length; i < len; i++) {
        chr   = str.charCodeAt(i);
        hash  = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
    }
    return hash;
}

var onceHashes = {};

function once(func) {
    var unique = hashCode(func.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1]);

    if (!onceHashes[unique]) {
        onceHashes[unique] = true;
        func();
    }
}

আপনি করতে পারেন:

for (var i=0; i<10; i++) {
    once(function() {
        alert(i);
    });
}

এবং এটি শুধুমাত্র একবার চালানো হবে :)


1

প্রাথমিক সেটআপ:

var once = function( once_fn ) {
    var ret, is_called;
    // return new function which is our control function 
    // to make sure once_fn is only called once:
    return function(arg1, arg2, arg3) {
        if ( is_called ) return ret;
        is_called = true;
        // return the result from once_fn and store to so we can return it multiply times:
        // you might wanna look at Function.prototype.apply:
        ret = once_fn(arg1, arg2, arg3);
        return ret;
    };
}

1

আপনি যদি নোড.জেএস ব্যবহার করছেন বা ব্রাউজারফাই দিয়ে জাভাস্ক্রিপ্ট লিখছেন, তবে "একবার" এনপিএম মডিউলটি বিবেচনা করুন :

var once = require('once')

function load (file, cb) {
  cb = once(cb)
  loader.load('file')
  loader.once('load', cb)
  loader.once('error', cb)
}

1

আপনি যদি ভবিষ্যতে ফাংশনটি পুনরায় ব্যবহার করতে সক্ষম হতে চান তবে উপরের অ্যাড হপ্পের কোডের উপর ভিত্তি করে এটি ভালভাবে কাজ করে (আমি বুঝতে পারি যে মূল প্রশ্নটি এই অতিরিক্ত বৈশিষ্ট্যটির জন্য ডাকেনি!):

   var something = (function() {
   var executed = false;              
    return function(value) {
        // if an argument is not present then
        if(arguments.length == 0) {               
            if (!executed) {
            executed = true;
            //Do stuff here only once unless reset
            console.log("Hello World!");
            }
            else return;

        } else {
            // otherwise allow the function to fire again
            executed = value;
            return;
        }       
    }
})();

something();//Hello World!
something();
something();
console.log("Reset"); //Reset
something(false);
something();//Hello World!
something();
something();

আউটপুট চেহারা:

Hello World!
Reset
Hello World!

1

আপনার যখন প্রয়োজন তখন লিখতে সহজ সরল সজ্জাকারী

function one(func) {
  return function () {
     func && func.apply(this, arguments);
     func = null;
  }
}

ব্যবহার:

var initializer= one( _ =>{
      console.log('initializing')
  })

initializer() // 'initializing'
initializer() // nop
initializer() // nop

0

আন্ডারস্কোর "একবার" ফাংশনটি ব্যবহার করার চেষ্টা করছেন:

var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.

http://underscorejs.org/#once


না, আপনি যখন যুক্তি দিয়ে এটি কল করা শুরু করেন তখন এটি খুব কুশ্রী।
vsync

0
var init = function() {
    console.log("logges only once");
    init = false;
}; 

if(init) { init(); }

/* next time executing init() will cause error because now init is 
   -equal to false, thus typing init will return false; */

0

আপনি যদি রামদা ব্যবহার করেন তবে আপনি "একবার" ফাংশনটি ব্যবহার করতে পারেন ।

ডকুমেন্টেশন থেকে একটি উদ্ধৃতি:

একবার ফাংশন (ক ... → খ) → (ক ... → খ)

একটি ফাংশন fn গ্রহণ করে এবং এমন একটি ফাংশন প্রদান করে যা fn এর অনুরোধ রক্ষা করে যে fn কেবল একবারই ডাকা যেতে পারে, যতক্ষণ না ফেরত ফাংশনটি চাওয়া হয়। গণনা করা প্রথম মান পরবর্তী অনুরোধগুলিতে ফিরে আসে।

var addOneOnce = R.once(x => x + 1);
addOneOnce(10); //=> 11
addOneOnce(addOneOnce(50)); //=> 11

0

এটি যতটা সম্ভব সহজ রাখুন

function sree(){
  console.log('hey');
  window.sree = _=>{};
}

আপনি ফলাফল দেখতে পারেন

স্ক্রিপ্ট ফলাফল


আপনি যদি মডিউলটির ভিতরে থাকেন তবে কেবলমাত্র এর thisপরিবর্তে ব্যবহার করুনwindow
শ্রীকীঠ কে

0

JQuery কেবল একবার পদ্ধতিটি () ব্যবহার করে ফাংশনটিতে কল করতে দেয় :

let func = function() {
  console.log('Calling just once!');
}
  
let elem = $('#example');
  
elem.one('click', func);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <p>Function that can be called only once</p>
  <button id="example" >JQuery one()</button>
</div>

() এর উপর JQuery পদ্ধতি ব্যবহার করে বাস্তবায়ন :

let func = function(e) {
  console.log('Calling just once!');
  $(e.target).off(e.type, func)
}
  
let elem = $('#example');
  
elem.on('click', func);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <p>Function that can be called only once</p>
  <button id="example" >JQuery on()</button>
</div>

নেটিভ জেএস ব্যবহার করে বাস্তবায়ন:

let func = function(e) {
  console.log('Calling just once!');
  e.target.removeEventListener(e.type, func);
}
  
let elem = document.getElementById('example');
  
elem.addEventListener('click', func);
<div>
  <p>Functions that can be called only once</p>
  <button id="example" >ECMAScript addEventListener</button>
</div>


-1
if (!window.doesThisOnce){
  function myFunction() {
    // do something
    window.doesThisOnce = true;
  };
};

গ্লোবাল স্কোপ (ওরফে উইন্ডো) দূষিত করা এটি একটি খারাপ অভ্যাস
vlio20

আমি আপনার সাথে একমত কিন্তু কেউ এ থেকে কিছু পেতে পারে।
atw

এটি কাজ করে না। যখন কোডটি প্রথম কার্যকর করা হয়, তখন ফাংশনটি তৈরি করা হয়। তারপরে যখন ফাংশনটি বলা হয় এটি কার্যকর করা হয় এবং বিশ্বব্যাপী মিথ্যাতে সেট করা থাকে তবে ফাংশনটি এখনও পরবর্তী সময়ে বলা যেতে পারে।
ট্রিনকোট

এটি কোথাও মিথ্যাতে সেট করা নেই।
atw

-2

এই এক অসীম লুপগুলি প্রতিরোধের জন্য দরকারী (jQuery ব্যবহার করে):

<script>
var doIt = true;
if(doIt){
  // do stuff
  $('body').html(String($('body').html()).replace("var doIt = true;", 
                                                  "var doIt = false;"));
} 
</script>

আপনি যদি নেমস্পেস দূষণ সম্পর্কে উদ্বিগ্ন হন তবে "doIt" এর জন্য একটি দীর্ঘ, এলোমেলো স্ট্রিংটি বাদ দিন।


-2

এটি স্টিকি কার্যকর সম্পাদন রোধ করতে সহায়তা করে

var done = false;

function doItOnce(func){
  if(!done){
    done = true;
    func()
  }
  setTimeout(function(){
    done = false;
  },1000)
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.