জাভাস্ক্রিপ্ট: পুনরাবৃত্তি বেনামে ফাংশন?


120

ধরা যাক আমার একটি বেসিক পুনরাবৃত্তি ফাংশন রয়েছে:

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}

আমার কোনও বেনামি ফাংশন থাকলে আমি কীভাবে এটি করতে পারি ...

(function(data){
    data = data+1;
    var nothing = function() {
        //Something here that calls the function?
    }
    nothing();
})();

আমি এই ফাংশনটিকে কল করার একটি উপায় চাই যা আমি এই ফাংশনটিকে কল করেছি ... আমি কোথাও স্ক্রিপ্ট দেখেছি (যেখানে আমি মনে করতে পারি না) এটি আপনাকে ফাংশনটির নাম বলতে পারে তবে আমি কোনওটিই স্মরণ করতে পারি না এখনই তথ্য।


আপনার প্রয়োজন এমন কোনও কারণ আছে বা আপনি কি কেবল কৌতূহলী? আমার কাছে মনে হয় কেবল এটির নাম দেওয়া আরও পরিষ্কার হবে ...
rfunduk

1
@ থেন্ডুকস: একই কারণে কেন কেউ বেনামে ফাংশন ব্যবহার করবেন। শুধু যে কখনও কখনও পুনরাবৃত্তি প্রয়োজন।
অকর্মা

5
এটি লজ্জাজনকভাবে arguments.calleeবিদ্যমান এবং এই ফান্টনিও দরকারী কিছু করে না। আমি ওয়াই কম্বিনেটর খুঁজছিলাম :P। জঘন্য, সেই জিনিসগুলি কখনই দরকারী হবে না ...
কোবি

1
হ্যাঁ, কোবি যুক্ত হিসাবে, যুক্তি ছাড়াই বেনামে পুনরাবৃত্ত ফাংশন করতে ওয়াইয়ের মতো স্থির পয়েন্ট সংযোজক ব্যবহার করুন .c
steamer25

উত্তর:


145

আপনি "ফাংশন ডিক্লেয়ারেশন" বিবৃতি না দিয়ে মান হিসাবে ফাংশনটি তৈরি করার পরেও আপনি ফাংশনটিকে একটি নাম দিতে পারেন । অন্য কথায়:

(function foo() { foo(); })();

এটি একটি স্ট্যাক-ফুঁ দিয়ে যাওয়া পুনরাবৃত্তি ফাংশন। এখন, এটি বলেছিল, আপনি সম্ভবত এটি সাধারণভাবে না করতে চাইবেন না কারণ জাভাস্ক্রিপ্টের বিভিন্ন বাস্তবায়ন নিয়ে কিছু অদ্ভুত সমস্যা রয়েছে। ( দ্রষ্টব্য - এটি মোটামুটি পুরানো মন্তব্য; কঙ্গাকসের ব্লগ পোস্টে বর্ণিত কিছু / অনেকগুলি / সমস্ত সমস্যা আরও আধুনিক ব্রাউজারগুলিতে সংশোধন করা যেতে পারে))

আপনি যখন এর মতো কোনও নাম দেন, নামটি ফাংশনের বাইরে দৃশ্যমান হয় না (ভাল, এটি এমনটি হওয়ার কথা নয়; এটি একটি অদ্ভুততা)। এটি লিস্পে "লেটারেক" এর মতো।

হিসাবে arguments.callee, এটি "কঠোর" মোডে অনুমোদিত নয় এবং সাধারণত এটি একটি খারাপ জিনিস হিসাবে বিবেচিত হয়, কারণ এটি কিছু অনুকূলিতকরণকে শক্ত করে তোলে। এটি প্রত্যাশার চেয়ে অনেক ধীর।

সম্পাদনা করুন - আপনি যদি এমন কোনও "বেনামি" ফাংশনটির প্রভাব পেতে চান যা নিজে কল করতে পারে, আপনি এই জাতীয় কিছু করতে পারেন (ধরে নিবেন আপনি কলব্যাক হিসাবে ফাংশনটি পাস করছেন বা এর মতো কিছু):

asyncThingWithCallback(params, (function() {
  function recursive() {
    if (timeToStop())
      return whatever();
    recursive(moreWork);
  }
  return recursive;
})());

এটি যা করে তা হ'ল একটি ফাংশনকে একটি সুন্দর, নিরাপদ, ভাঙা-না-ই-আই ফাংশন ঘোষণার বিবৃতি দিয়ে সংজ্ঞা দেয়, এমন একটি স্থানীয় ফাংশন তৈরি করে যার নাম বিশ্বব্যাপী নেমস্পেসকে দূষিত করবে না। মোড়ক (সত্যই বেনামে) ফাংশনটি কেবল সেই স্থানীয় ফাংশনটি ফিরিয়ে দেয়।


আমরা কী ES5 স্ক্রিট্রিক্টের সাথে বিশ্বব্যাপী নেমস্পেসকে অন্যভাবে দূষণ করা এড়াতে পারি (আমি এখনও ইএস 5 তে গভীরভাবে পড়িনি)?
ছদ্মবেশে

@ পয়েন্ট আপনি দয়া করে এই সন্ধান খুঁজছেন করতে পারেন stackoverflow.com/questions/27473450/…
গ্লাদসন রবিনসন

আমার ধারণা (() => { call_recursively_self_here() })(), নিজেকে পুনরাবৃত্তভাবে ব্যবহার করা এবং কল করা সম্ভব নয় , তাই না? আমি অবশ্যই এটি একটি নাম দিতে হবে।
কিওয়ার্টি

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

1
@ পয়েন্টে সম্ভবত কিছু হ্যাকার অ্যাপ্লিকেশন খুঁজে পাবেন;)
কামিল কিয়েসজেউস্কি

31

লোকেরা মন্তব্যগুলিতে ওয়াই সংযুক্তকারী সম্পর্কে কথা বলেছিল, তবে কেউই এটি উত্তর হিসাবে লিখেছিল না।

ওয়াই সংযুক্তকারী নীচে জাভাস্ক্রিপ্টে সংজ্ঞায়িত করা যেতে পারে: (লিঙ্কের জন্য স্টিমার 25 ধন্যবাদ)

var Y = function (gen) {
  return (function(f) {
    return f(f);
  }(function(f) {
    return gen(function() {
      return f(f).apply(null, arguments);
    });
  }));
}

এবং যখন আপনি আপনার বেনামে ফাংশনটি পাস করতে চান:

(Y(function(recur) {
  return function(data) {
    data = data+1;
    var nothing = function() {
      recur(data);
    }
    nothing();
  }
})());

এই সমাধানটি সম্পর্কে সর্বাধিক গুরুত্বপূর্ণ বিষয়টি হ'ল এটি আপনার ব্যবহার করা উচিত নয়।


16
"এই সমাধানটি সম্পর্কে সর্বাধিক গুরুত্বপূর্ণ বিষয় হ'ল আপনার এটি ব্যবহার করা উচিত নয়" " কেন?
nyuszika7h

7
এটি দ্রুত হবে না। এটি ব্যবহার করা কুৎসিত (যদিও ধারণাটি সুন্দর!)। আপনি আপনার ফাংশনটিকে ট্যাগ বা ভেরিয়েবল নাম দিতে হবে এড়ানো (এবং কেন এটি উদ্বেগজনক হবে তা আমি দেখতে পাচ্ছি না), তবে আপনি এখনও Y এর কাছে বহিরাগত ফাংশনটির প্যারামিটার হিসাবে একটি নাম দিয়েছেন So সুতরাং আপনি না এই সমস্ত সমস্যার মধ্যে দিয়ে কিছু অর্জন।
জেম

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

হাই, আমি কিছুটা "ক্লিনার" পরিবর্তনের প্রস্তাব দিচ্ছি। অ্যাপ্লিকেশন (নাল, আর্গুমেন্ট) আমার কাছে কুৎসিত বলে মনে হচ্ছে: var Y = ফাংশন (জেনার)) রিটার্ন (ফাংশন (চ) {রিটার্ন এফ (এফ);} (ফাংশন (চ)) {রিটার্ন জেন (ফাংশন (এক্স) {রিটার্ন এফ (চ) (এক্স);});})); Arrow বা সমানভাবে ((ফাংশন (এক্স) {রিটার্ন y} সমান (x => y))) তীর স্বরলিপি (বৈধ জেএস কোড) ব্যবহার করে: var Y = Gen => (f => f (f)) (f = > জেনার (x => f (f) (x)))
মাইফিস্টআরসভার

23

ইউ সংযুক্তকারী

আর্গুমেন্ট হিসাবে কোনও ক্রিয়াকলাপটি নিজের কাছে পাস করার মাধ্যমে কোনও ফাংশন তার নামের পরিবর্তে প্যারামিটার ব্যবহার করে পুনরাবৃত্তি করতে পারে! সুতরাং প্রদত্ত Uফাংশনটিতে কমপক্ষে একটি প্যারামিটার থাকা উচিত যা ফাংশনটির সাথে আবদ্ধ হবে (নিজেই)।

নীচের উদাহরণে, আমাদের কোনও প্রস্থান শর্ত নেই, তাই স্ট্যাকের ওভারফ্লো না হওয়া পর্যন্ত আমরা অনির্দিষ্টকালের জন্য লুপ করব

const U = f => f (f) // call function f with itself as an argument

U (f => (console.log ('stack overflow imminent!'), U (f)))

আমরা বিভিন্ন কৌশল ব্যবহার করে অসীম পুনরাবৃত্তি থামাতে পারি। এখানে, আমি আমাদের বেনাম ফাংশনটি লিখব অন্য কোনও বেনামী ফাংশন যা ইনপুটটির জন্য অপেক্ষা করছে; এই ক্ষেত্রে, কিছু নম্বর। যখন কোনও সংখ্যা সরবরাহ করা হয়, এটি যদি 0 এর চেয়ে বেশি হয় তবে আমরা পুনরাবৃত্তি চালিয়ে যাব, অন্যথায় 0 ফিরে আসবে।

const log = x => (console.log (x), x)

const U = f => f (f)

// when our function is applied to itself, we get the inner function back
U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)
// returns: (x => x > 0 ? U (f) (log (x - 1)) : 0)
// where f is a reference to our outer function

// watch when we apply an argument to this function, eg 5
U (f => x => x > 0 ? U (f) (log (x - 1)) : 0) (5)
// 4 3 2 1 0

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

const log = x => (console.log (x), x)

const U = f => f (f)

const countDown = U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)

countDown (5)
// 4 3 2 1 0

countDown (3)
// 2 1 0

কেবল এটি সরাসরি পুনরাবৃত্তি নয় - এমন একটি ফাংশন যা নিজের নাম ব্যবহার করে নিজেকে কল করে। আমাদের সংজ্ঞাটি countDownতার দেহের অভ্যন্তরে নিজেকে উল্লেখ করে না এবং এখনও পুনরাবৃত্তি সম্ভব

// direct recursion references itself by name
const loop = (params) => {
  if (condition)
    return someValue
  else
    // loop references itself to recur...
    return loop (adjustedParams)
}

// U combinator does not need a named reference
// no reference to `countDown` inside countDown's definition
const countDown = U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)

ইউ সংযোজক ব্যবহার করে কীভাবে বিদ্যমান ফাংশন থেকে স্ব-রেফারেন্স সরিয়ে ফেলা যায়

এখানে আমি আপনাকে দেখাব যে কীভাবে একটি পুনরাবৃত্ত ফাংশন নিতে হবে যা নিজের কাছে একটি রেফারেন্স ব্যবহার করে এবং এটি এমন একটি ফাংশনে পরিবর্তন করে যা ইউ সংযোজককে স্ব-রেফারেন্সের জায়গায় নিয়োগ দেয় to

const factorial = x =>
  x === 0 ? 1 : x * factorial (x - 1)
  
console.log (factorial (5)) // 120

অভ্যন্তরীণ রেফারেন্সটি প্রতিস্থাপন করতে এখন ইউ সংযোগকারী ব্যবহার করে factorial

const U = f => f (f)

const factorial = U (f => x =>
  x === 0 ? 1 : x * U (f) (x - 1))

console.log (factorial (5)) // 120

বেসিক রিপ্লেসমেন্ট প্যাটার্নটি এটি। একটি মানসিক নোট দিন, আমরা পরবর্তী বিভাগে অনুরূপ কৌশল ব্যবহার করব

// self reference recursion
const foo =         x => ...   foo (nextX) ...

// remove self reference with U combinator
const foo = U (f => x => ... U (f) (nextX) ...)

ওয়াই সংযুক্তকারী

সম্পর্কিত: ইউ এবং ওয়াই সংযুক্তকারীরা একটি আয়না উপমা ব্যবহার করে ব্যাখ্যা করেছিলেন

পূর্ববর্তী বিভাগে আমরা দেখেছি কীভাবে স্ব-রেফারেন্স পুনরাবৃত্তিটিকে একটি পুনরাবৃত্ত ফাংশনে রূপান্তর করতে হয় যা ইউ সংযোজক ব্যবহার করে একটি নামকৃত ফাংশনের উপর নির্ভর করে না। প্রথম আর্গুমেন্ট হিসাবে নিজেকে সর্বদা ফাংশনটি পাস করার কথা মনে রাখার সাথে সাথে বিরক্তি কিছুটা আছে। ঠিক আছে, ওয়াই-কম্বিনেটর ইউ-কম্বিনেটর তৈরি করে এবং সেই ক্লান্তিকর কিছুটা সরিয়ে দেয়। এটি একটি ভাল জিনিস কারণ জটিলতা অপসারণ / হ্রাস করা হ'ল আমাদের কার্য সম্পাদন করার প্রাথমিক কারণ

প্রথমে আসুন আমাদের নিজস্ব নিজস্ব-সংযুক্তকারী তৈরি করা যাক

// standard definition
const Y = f => f (Y (f))

// prevent immediate infinite recursion in applicative order language (JS)
const Y = f => f (x => Y (f) (x))

// remove reference to self using U combinator
const Y = U (h => f => f (x => U (h) (f) (x)))

এখন আমরা দেখতে পাচ্ছি কীভাবে এটির ব্যবহারটি ইউ-সংযুক্তকারীটির সাথে তুলনা করে। লক্ষ্য করুন, পুনরাবৃত্তি করার পরিবর্তে U (f)আমরা কেবল কল করতে পারিf ()

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

Y (f => (console.log ('stack overflow imminent!'),  f ()))

এখন আমি countDownপ্রোগ্রামটি ব্যবহার করে প্রদর্শন করব Y- আপনি দেখতে পাবেন যে প্রোগ্রামগুলি প্রায় অভিন্ন তবে Y সংযোজক জিনিসগুলিকে কিছুটা পরিষ্কার রাখবেন

const log = x => (console.log (x), x)

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const countDown = Y (f => x => x > 0 ? f (log (x - 1)) : 0)

countDown (5)
// 4 3 2 1 0

countDown (3)
// 2 1 0

এবং এখন আমরা factorialপাশাপাশি দেখতে পাবেন

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const factorial = Y (f => x =>
  x === 0 ? 1 :  x * f (x - 1))

console.log (factorial (5)) // 120

আপনি দেখতে পাচ্ছেন, fনিজেই পুনরাবৃত্তি হওয়ার প্রক্রিয়া হয়ে ওঠে। পুনরাবৃত্তি করার জন্য, আমরা এটিকে একটি সাধারণ ফাংশনের মতো বলি। আমরা বিভিন্ন যুক্তি সহ এটি একাধিকবার কল করতে পারি এবং ফলাফলটি এখনও সঠিক হবে। এটি যেহেতু এটি একটি সাধারণ ফাংশন প্যারামিটার, তাই আমরা যা চাই তার নাম দিতে পারি যেমন recurনীচে -

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const fibonacci = Y (recur => n =>
  n < 2 ? n : recur (n - 1) +  (n - 2))

console.log (fibonacci (10)) // 55


1 টিরও বেশি পরামিতি সহ ইউ এবং ওয়াই সংযুক্তকারী

উপরের উদাহরণগুলিতে, আমরা দেখেছি যে আমরা কীভাবে আমাদের গণনার "অবস্থা" র উপর নজর রাখতে একটি আর্গুমেন্ট লুপ করতে পারি এবং পাস করতে পারি। তবে আমাদের যদি অতিরিক্ত অবস্থার উপর নজর রাখা দরকার?

আমরা পারে একটি অ্যারের বা কিছু মত যৌগ ডেটা ব্যবহার ...

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const fibonacci = Y (f => ([a, b, x]) =>
  x === 0 ? a : f ([b, a + b, x - 1]))

// starting with 0 and 1, generate the 7th number in the sequence
console.log (fibonacci ([0, 1, 7])) 
// 0 1 1 2 3 5 8 13

তবে এটি খারাপ কারণ এটি অভ্যন্তরীণ অবস্থা (কাউন্টার aএবং b) প্রকাশ করছে। আমরা চাইলে fibonacci (7)আমাদের উত্তরটি পেতে কেবল ফোন করতে পারলে ভাল লাগবে ।

ক্রেডিড ফাংশন (আনারি (1-প্যারামটার) ক্রিয়াকলাপ) সম্পর্কে আমরা যা জানি তা ব্যবহার করে, আমরা Yযৌগিক ডেটা বা উন্নত ভাষার বৈশিষ্ট্যগুলিতে আমাদের সংজ্ঞাটি সংশোধন না করে বা নির্ভর করতে না পেরে সহজেই আমাদের লক্ষ্য অর্জন করতে পারি ।

fibonacciনীচে নীচে সংজ্ঞা দেখুন। আমরা অবিলম্বে আবেদন করছি 0এবং 1যা যথাক্রমে আবদ্ধ aএবং আবদ্ধ b। এখন ফিবোনাচি কেবল শেষ যুক্তির সরবরাহের জন্য অপেক্ষা করছে যা আবদ্ধ হবে x। যখন আমরা পুনরাবৃত্তি করি, আমাদের অবশ্যই কল করতে হবে f (a) (b) (x)(নয় f (a,b,x)) কারণ আমাদের ফাংশনটি ত্রিযুক্ত আকারে রয়েছে।

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const fibonacci = Y (f => a => b => x =>
  x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)

console.log (fibonacci (7)) 
// 0 1 1 2 3 5 8 13


এই ধরণের প্যাটার্নটি সমস্ত ধরণের কার্যকারিতা সংজ্ঞায়িত করতে কার্যকর হতে পারে। নীচে আমরা আরো দুটি ফাংশন ব্যবহার করে সংজ্ঞায়িত দেখতে পাবেন Ycombinator ( rangeএবং reduce) এবং একটি অমৌলিক reduce, map

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const range = Y (f => acc => min => max =>
  min > max ? acc : f ([...acc, min]) (min + 1) (max)) ([])

const reduce = Y (f => g => y => ([x,...xs]) =>
  x === undefined ? y : f (g) (g (y) (x)) (xs))
  
const map = f =>
  reduce (ys => x => [...ys, f (x)]) ([])
  
const add = x => y => x + y

const sq = x => x * x

console.log (range (-2) (2))
// [ -2, -1, 0, 1, 2 ]

console.log (reduce (add) (0) ([1,2,3,4]))
// 10

console.log (map (sq) ([1,2,3,4]))
// [ 1, 4, 9, 16 ]


এটি সমস্ত অনিয়মস ওএমজি

যেহেতু আমরা এখানে খাঁটি ফাংশন নিয়ে কাজ করছি, আমরা এর নাম সংজ্ঞায়নের জন্য যেকোন নামকৃত ফাংশনকে বিকল্প করতে পারি। যখন আমরা ফিবোনাচি নিই এবং নাম প্রকাশিত ফাংশনগুলি তাদের অভিব্যক্তি দিয়ে প্রতিস্থাপন করি তখন কী ঘটে তা দেখুন

/* const U = f => f (f)
 *
 * const Y = U (h => f => f (x => U (h) (f) (x)))
 *
 * const fibonacci = Y (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)
 *
 */

/*
 * given fibonacci (7)
 *
 * replace fibonacci with its definition
 * Y (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
 *
 * replace Y with its definition
 * U (h => f => f (x => U (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
//
 * replace U with its definition
 * (f => f (f)) U (h => f => f (x => U (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
 */

let result =
  (f => f (f)) (h => f => f (x => h (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
  
console.log (result) // 13

এবং সেখানে আপনার এটি রয়েছে - fibonacci (7)অজ্ঞাতনামা ফাংশন ব্যতীত পুনরাবৃত্তভাবে গণনা করা


14

পরিবর্তে একটি "বেনামে অবজেক্ট" ব্যবহার করা সহজ হতে পারে:

({
  do: function() {
    console.log("don't run this ...");
    this.do();
  }
}).do();

আপনার গ্লোবাল স্পেস পুরোপুরি অবিবাহিত। এটা বেশ সোজা। এবং আপনি সহজেই অবজেক্টের অ-বৈশ্বিক রাষ্ট্রের সুবিধা নিতে পারেন।

সিনট্যাক্সটিকে আরও সংক্ষিপ্ত করতে আপনি ES6 অবজেক্ট পদ্ধতিগুলিও ব্যবহার করতে পারেন।

({
  do() {
    console.log("don't run this ...");
    this.do();
  }
}).do();

13

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

আপনি যদি সত্যিই আবশ্যক, arguments.calleeFabrizio এর উত্তর হিসাবে আছে। তবে এটিকে সাধারণত অনিবার্য বলে বিবেচনা করা হয় এবং ECMAScript পঞ্চম সংস্করণের 'কঠোর মোডে' অস্বীকার করা হয়। যদিও ইসিএমএ 3 এবং অ-কঠোর-মোডটি সরে যাচ্ছে না, কঠোর মোডে কাজ করা আরও সম্ভাব্য ভাষার অপ্টিমাইজেশনের প্রতিশ্রুতি দেয়।

একটি নামযুক্ত ইনলাইন ফাংশনও ব্যবহার করতে পারে:

(function foo(data){
    data++;
    var nothing = function() {
        foo(data);
    }
    nothing();
})();

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

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


আমি সম্মত, একটি নামকরণ ফাংশন আর্গুমেন্টগুলির চেয়ে বেশি উপযুক্ত .c )

কাব্যিকদের জন্য +1, "pushing against the boundaries of good taste"- (ভাল, এবং ভাল তথ্য)।
পিটার আজতাই

এখানে যদি দূষণ সত্যিই উদ্বেগজনক হয় তবে একটি প্রাক প্রাক / পোস্টফিক্স সম্পর্কে কী বলা যায়? এটি বৈশ্বিক পরিমণ্ডলে নেই বলে বিবেচনা করে (এমনকি যদি ফাংশনটি শীর্ষ lvl হয় তবে তার ইতিমধ্যে তার পুরো কোডটি মোড়ানো একটি বেনামী ফাংশন থাকা উচিত) এর মতো কোনও নাম recur_fooপ্যারেন্ট স্কোপের কোনও ক্রিয়াকলাপের সাথে সংঘটিত হবে (বা অসুস্থ হওয়ার জন্য) -যুক্ত)।
gblazex

খুব আকর্ষণীয় - jsfiddle.net/hck2A - আইই এই ক্ষেত্রে পিতামাতাকে দূষিত করে, যেমন আপনি বলেছেন। তা কখনই বুঝতে পারিনি।
পিটার আজতাই

1
@ পিটার: kangax.github.com/nfe (বিশেষত ' জেএসক্রিপ্ট বাগ') এই বিষয়টিতে আপনি যা জানতে চেয়েছিলেন তার চেয়ে বেশি জন্য এটি শেষ পর্যন্ত আই 9 এ স্থির করা হয়েছে (তবে কেবল আইই 9 স্ট্যান্ডার্ডস মোডে)।
ববিনস

10
(function(data){
    var recursive = arguments.callee;
    data = data+1;
    var nothing = function() {
        recursive(data)
    }
    nothing();
})();

34
আমি আশা করি সকলেই এই (প্রযুক্তিগতভাবে সঠিক) উত্তরের জন্য ভোট দিয়ে সমস্যাগুলি বুঝতে পেরেছেন arguments.callee: এটি কঠোর মোডে এবং ES5 এ অনুমোদিত নয়।
পয়েন্টি

ভোট দেওয়া হয়েছে, আর্গুমেন্টস.ক্যালিকে ES5- এ অবহিত করা হয়েছে
যায়েম রড্রিগেজ

এটি নোডজেএসে কাজ করে। আমি ES5 সম্পর্কে কম যত্ন নিতে পারি না যতক্ষণ না এটি একটি স্থির পরিবেশে অনুমানযোগ্য ফ্যাশনে কাজ করে।
অঙ্গদ

1
এটি একটি টাইম বোমা। উপরের মন্তব্যে যেমন পরামর্শ দেওয়া হয়েছে তেমন কোনও "স্থির" পরিবেশ বলে কিছু নেই। এমন হাজার হাজার কারণে যে কোনও কারণে আপনি প্রায় সর্বদা আপগ্রেড হতেন।
সংপাথ্রিস

6

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

(foo = function() { foo(); })()

বা আপনার ক্ষেত্রে:

(recur = function(data){
    data = data+1;
    var nothing = function() {
        if (data > 100) return; // put recursion limit
        recur(data);
    }
    nothing();
})(/* put data init value here */ 0);

আপনি recurএকটি varবিবৃতি দিয়ে প্রথমে ঘোষণা দিয়ে করতে পারেন । ডুনো কিনা তা প্রশ্নের নিয়মগুলি ভঙ্গ করে কিনা, তবে আপনার এখন যেমনটি রয়েছে, varবিবৃতি ব্যতীত আপনি ECMAScript 5 কঠোর মোডে ত্রুটি পাবেন।
টিম ডাউন

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

হ্যাঁ, কাজ করা কার্যকর (var recur = function() {...})();হবে না কারণ এটি এখন একটি অ্যাসাইনমেন্ট এক্সপ্রেশন (যা নির্ধারিত মানটি দেয়) এর পরিবর্তে একটি বিবৃতি। আমি var recur; (recur = function() {...})();পরিবর্তে পরামর্শ দিচ্ছিলাম।
টিম ডাউন

3

আপনি যখন এইরকম একটি বেনামী ফাংশন ঘোষণা করেন:

(function () {
    // Pass
}());

এটি একটি ফাংশন এক্সপ্রেশন হিসাবে বিবেচিত এবং এটির একটি nameচ্ছিক নাম রয়েছে (যা আপনি এটি নিজের মধ্যে থেকে কল করতে ব্যবহার করতে পারেন But তবে এটি কোনও ফাংশন এক্সপ্রেশন (এবং বিবৃতি নয়) এটি বেনামে থেকে যায় (তবে একটি নাম রয়েছে যা আপনি কল করতে পারেন) So এই ফাংশনটি নিজেকে কল করতে পারে:

(function foo () {
    foo();
}());
foo //-> undefined

"এটি অজ্ঞাত থাকে" - না এটি হয় না। বেনামে ফাংশনটির কোনও নাম নেই। আমি বুঝতে পারি যে fooবর্তমান প্রসঙ্গে প্রকাশিত হয় না, তবে এটি কম-বেশি অপ্রাসঙ্গিক। নাম সহ একটি ফাংশন এখনও একটি নামযুক্ত ফাংশন - বেনামে নয়
আপনাকে ধন্যবাদ

3

কেন ফাংশনটি নিজেই ফান্টিটিওতে পাস করবেন না?

    var functionCaller = function(thisCaller, data) {
        data = data + 1;
        var nothing = function() {
            thisCaller(thisCaller, data);
        };
        nothing();
    };
    functionCaller(functionCaller, data);

3

নির্দিষ্ট পরিস্থিতিতে আপনাকে বেনামে ফাংশনগুলির উপর নির্ভর করতে হবে। প্রদত্ত একটি পুনরাবৃত্তি mapফাংশন:

const map = f => acc => ([head, ...tail]) => head === undefined 
 ? acc
 : map (f) ([...acc, f(head)]) (tail);

const sqr = x => x * x;
const xs = [1,2,3,4,5];

console.log(map(sqr) ([0]) (xs)); // [0] modifies the structure of the array

দয়া করে নোট করুন যে mapঅ্যারের গঠন পরিবর্তন করতে হবে না। সুতরাং আহরণকারী accউন্মুক্ত করার প্রয়োজন নেই। mapউদাহরণস্বরূপ আমরা অন্য কোনও কার্যে গুটিয়ে রাখতে পারি :

const map = f => xs => {
  let next = acc => ([head, ...tail]) => head === undefined
   ? acc
   : map ([...acc, f(head)]) (tail);

  return next([])(xs);
}

তবে এই সমাধানটি বেশ ভার্জোজ। আসুন অবমূল্যায়নযুক্ত Uসংযুক্তি ব্যবহার করুন :

const U = f => f(f);

const map = f => U(h => acc => ([head, ...tail]) => head === undefined 
 ? acc
 : h(h)([...acc, f(head)])(tail))([]);

const sqr = x => x * x;
const xs = [1,2,3,4,5];

console.log(map(sqr) (xs));

সংক্ষিপ্ত, তাই না? Uমরে যাওয়া সহজ তবে এর অসুবিধেও রয়েছে যে পুনরাবৃত্তি কলটি কিছুটা উদ্বিগ্ন sum(...)হয়ে যায় : হয়ে যায় h(h)(...)- এটাই।


2

উত্তরটি এখনও প্রয়োজনীয় কিনা তা আমি নিশ্চিত নই তবে এটি ফাংশন.বাইন্ড ব্যবহার করে তৈরি প্রতিনিধিদের ব্যবহার করেও করা যেতে পারে:

    var x = ((function () {
        return this.bind(this, arguments[0])();
    }).bind(function (n) {
        if (n != 1) {
            return n * this.bind(this, (n - 1))();
        }
        else {
            return 1;
        }
    }))(5);

    console.log(x);

এতে নামযুক্ত ফাংশন বা আর্গুমেন্টস.কলে জড়িত না।


1

বোবিন্স যেমন লিখেছেন, কেবল আপনার ফাংশনটির নাম দিন।

তবে, আমি অনুমান করছি আপনি একটি প্রাথমিক মানও পাস করতে চান এবং শেষ পর্যন্ত আপনার ফাংশনটি বন্ধ করতে চান!

var initialValue = ...

(function recurse(data){
    data++;
    var nothing = function() {
        recurse(data);
    }
    if ( ... stop condition ... )
        { ... display result, etc. ... }
    else
        nothing();
}(initialValue));

জেএসফিডেল উদাহরণ (মজাদার জন্য ডেটা + = ডেটা ব্যবহার করে)



1
+1, এটি একটি খুব দরকারী উত্তর এবং এর জন্য আপনার আরও বেশি পরিমাণে পদক্ষেপ নেওয়া উচিত, তবে এটি অনামী নয়।
ছদ্মবেশে

আপনি পরিষ্কারভাবে পড়তেন না bobince কি লিখেছিলেন: However named inline function expressions are also best avoided.। তবে ওপি পয়েন্টটি খুব মিস করে ... :)
gblazex

@ গালাম্ব - আমি এটি পড়েছি। কঠোর মোডে এবং ES5 এ অনুমোদিত না পিতামাতার সুযোগকে দূষিত করা এবং অতিরিক্ত দৃষ্টান্ত তৈরি করার মতো নয়।
পিটার আজতাই

1

আমার স্ট্রিং তৈরির উদ্দেশ্যে একটি ওয়াইনলাইন বেনামি ফাংশন প্রয়োজন (বা বরং চেয়েছিল), এবং এটি হ্যান্ডেল করেছিলাম:

var cmTitle = 'Root' + (function cmCatRecurse(cmCat){return (cmCat == root) ? '' : cmCatRecurse(cmCat.parent) + ' : ' + cmCat.getDisplayName();})(cmCurrentCat);

যা 'রুট: ফু: বার: বাজ: ...' এর মতো স্ট্রিং তৈরি করে


1

ES2015 এর সাহায্যে আমরা সিনট্যাক্স এবং ডিফল্ট প্যারামিটার এবং থঙ্কগুলি নিয়ে কিছুটা খেলতে পারি। পরবর্তীগুলি কোনও যুক্তি ছাড়াই কেবল ফাংশন:

const applyT = thunk => thunk();

const fib = n => applyT(
  (f = (x, y, n) => n === 0 ? x : f(y, x + y, n - 1)) => f(0, 1, n)
);

console.log(fib(10)); // 55

// Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55...

অনুগ্রহ করে নোট করুন যে fএটি বেনামে ফাংশন সহ একটি (x, y, n) => n === 0 ? x : f(y, x + y, n - 1)ডিফল্ট মান হিসাবে একটি পরামিতি । এই অনুরোধটি যখন fডাকা হয় তখন applyTঅবশ্যই আর্গুমেন্ট ছাড়াই হওয়া উচিত, যাতে ডিফল্ট মান ব্যবহৃত হয়। ডিফল্ট মান হ'ল একটি ফাংশন এবং তাই fএটি একটি নামযুক্ত ফাংশন, যা নিজেকে পুনরাবৃত্তভাবে কল করতে পারে।


0

নাম দেওয়া ফাংশন বা যুক্তি

var sum = (function(foo,n){
  return n + foo(foo,n-1);
})(function(foo,n){
     if(n>1){
         return n + foo(foo,n-1)
     }else{
         return n;
     }
},5); //function takes two argument one is function and another is 5

console.log(sum) //output : 15

সুন্দর: একটি স্থানীয় প্যারামিটারে একটি বেনামে ফাংশন বাঁধুন এবং তারপরে স্থানীয় প্যারামিটারের মাধ্যমে ফাংশনটি কল করুন, তবে পুনরাবৃত্তির জন্য ফাংশনটি নিজেই পাস করুন।
englebart

0

এটি বিভিন্ন নাম এবং সামান্য পরিবর্তিত এন্ট্রি সহ জফোর্জের উত্তরগুলির একটি পুনর্নির্মাণ।

// function takes two argument: first is recursive function and second is input
var sum = (function(capturedRecurser,n){
  return capturedRecurser(capturedRecurser, n);
})(function(thisFunction,n){
     if(n>1){
         return n + thisFunction(thisFunction,n-1)
     }else{
         return n;
     }
},5); 

console.log(sum) //output : 15

প্রথম পুনরাবৃত্তিটি আনরোল করার দরকার পড়েনি। একটি রেফারেন্স হিসাবে নিজেকে প্রাপ্ত ফাংশনটি ওওপির আদিম গতিতে ফিরে আসে।


0

এটি তীর ফাংশন সহ @ জেমের উত্তরের একটি সংস্করণ।

আপনি Uবা Yসংযোগকারী ব্যবহার করতে পারেন । ওয়াই কম্বিনেটরটি ব্যবহার করা সহজ।

U সংযুক্তকারী, এটির সাথে আপনাকে ফাংশনটি পাস করতে হবে: const U = f => f(f) U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))

Y সংযুক্তকারী, এটির সাথে আপনাকে ফাংশনটি পাস করতে হবে না: const Y = gen => U(f => gen((...args) => f(f)(...args))) Y(selfFn => arg => selfFn('to infinity and beyond'))


0

তবুও আরেকটি ওয়াই-কম্বিনেটর সমাধান, রোসেটটা-কোড ব্যবহার করে লিঙ্কটি (আমার মনে হয় স্ট্যাক ওভারফ্লোতে কেউ এই লিঙ্কটি আগে কোথাও উল্লেখ করেছিলেন।

তীরগুলি বেনামে ফাংশনগুলির জন্য আমার কাছে আরও পঠনযোগ্য:

var Y = f => (x => x(x))(y => f(x => y(y)(x)));

-1

এটি সর্বত্র কাজ না করে তবে আপনি ব্যবহার করতে পারেন arguments.callee বর্তমান ফাংশনটি উল্লেখ ।

সুতরাং, ঘটনাচক্রে এইভাবে করা যেতে পারে:

var fac = function(x) { 
    if (x == 1) return x;
    else return x * arguments.callee(x-1);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.