javascript - tutorial - লুপ ভিতরে জাভাস্ক্রিপ্ট বন্ধ-সহজ বাস্তব উদাহরণ




জাভাস্ক্রিপ্ট ফাংশন (20)

var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = function() {          // and store them in funcs
    console.log("My value: " + i); // each should log its value.
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

এটি আউটপুট:

আমার মান: 3
আমার মান: 3
আমার মান: 3

যেখানে আমি আউটপুট করতে চাই:

আমার মান: 0
আমার মান: 1
আমার মান: 2

একই সমস্যা দেখা দেয় যখন ফাংশনটি চলতে বিলম্ব ইভেন্ট শোনার ব্যবহার করে ঘটে:

var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {          // let's create 3 functions
  buttons[i].addEventListener("click", function() { // as event listeners
    console.log("My value: " + i);                  // each should log its value.
  });
}
<button>0</button><br>
<button>1</button><br>
<button>2</button>

... বা অ্যাসিঙ্ক্রোনাস কোড, যেমন প্রতিশ্রুতি ব্যবহার করে:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for(var i = 0; i < 3; i++){
  wait(i * 100).then(() => console.log(i)); // Log `i` as soon as each promise resolves.
}

এই মৌলিক সমস্যার সমাধান কি?


আমরা চেক করব, আপনি যখন ঘোষণা করবেন varএবং letএকের পর এক কী হবে।

কেস 1 : ব্যবহারvar

<script>
   var funcs = [];
   for (var i = 0; i < 3; i++) {
     funcs[i] = function () {
        debugger;
        console.log("My value: " + i);
     };
   }
   console.log(funcs);
</script>

এবার F12 চাপুন এবং পৃষ্ঠা রিফ্রেশ করে আপনার ক্রোম কনসোল উইন্ডোটি খুলুন । অ্যারের ভিতরে প্রতি 3 ফাংশন ব্যয় করুন। আপনি একটি সম্পত্তি দেখতে হবে । এক্সপ্যান্ড যে এক। আপনি একটি অ্যারে বস্তু বলা হবে , যে এক প্রসারিত। আপনি বস্তুর মধ্যে ঘোষিত একটি সম্পত্তি খুঁজে পাবেন যা মান 3।[[Scopes]]"Global"'i'

উপসংহার:

  1. যখন আপনি 'var'একটি ফাংশনের বাইরে ব্যবহার করে একটি পরিবর্তনশীল ঘোষণা করেন , এটি বিশ্বব্যাপী পরিবর্তনশীল হয়ে যায় (আপনি টাইপিং iবা window.iকনসোল উইন্ডোতে চেক করতে পারেন। এটি 3 প্রদান করবে)।
  2. আপনি ঘোষিত Annominous ফাংশন ফাংশন ভিতরে মান না কল এবং চেক না করা পর্যন্ত আপনি ফাংশন আহ্বান করা হবে।
  3. যখন আপনি ফাংশন আহ্বান করেন, console.log("My value: " + i)তার Globalবস্তুর মানটি গ্রহণ করেন এবং ফলাফল প্রদর্শন করেন।

CASE2: ব্যবহার করে

এখন 'var'সঙ্গে প্রতিস্থাপন'let'

<script>
    var funcs = [];
    for (let i = 0; i < 3; i++) {
        funcs[i] = function () {
           debugger;
           console.log("My value: " + i);
        };
    }
    console.log(funcs);
</script>

একই জিনিস, scopes যান। এখন আপনি দুটি বস্তু দেখতে হবে "Block"এবং "Global"। এখন Blockবস্তুটি প্রসারিত করুন , আপনি সেখানে 'i' সংজ্ঞায়িত দেখতে পাবেন এবং অদ্ভুত বিষয় হল, প্রতিটি ফাংশনের জন্য মানটি যদি iভিন্ন হয় (0, 1, 2)।

উপসংহার:

যখন আপনি 'let'ফাংশনের বাইরেও ভেরিয়েবল ঘোষণা করেন তবে লুপের ভিতরে, এই পরিবর্তনশীলটি গ্লোবাল ভেরিয়েবল হবে না, এটি একটি Blockমাত্রিক পরিবর্তনশীল হয়ে যাবে যা কেবলমাত্র একই ফাংশনের জন্য উপলব্ধ। এই কারণেই, আমরা iভিন্ন আমরা ফাংশন আহ্বান যখন প্রতিটি ফাংশন জন্য।

কিভাবে কাছাকাছি কাজ সম্পর্কে আরো বিস্তারিত জানার জন্য, দয়া করে দুর্দান্ত ভিডিও টিউটোরিয়ালটি দেখুন https://youtu.be/71AtaJpJHw0


এই সংক্ষিপ্ত চেষ্টা করুন

  • কোন অ্যারে

  • লুপ জন্য কোন অতিরিক্ত


for (var i = 0; i < 3; i++) {
    createfunc(i)();
}

function createfunc(i) {
    return function(){console.log("My value: " + i);};
}

http://jsfiddle.net/7P6EN/


OP দ্বারা দেখানো কোড দিয়ে প্রধান সমস্যা হল যে i দ্বিতীয় লুপ পর্যন্ত পড়ি না। প্রদর্শনের জন্য, কোডের ভিতরে একটি ত্রুটি দেখতে কল্পনা করুন

funcs[i] = function() {            // and store them in funcs
    throw new Error("test");
    console.log("My value: " + i); // each should log its value.
};

funcs[someIndex] নির্বাহ করা হয় () পর্যন্ত আসলে ত্রুটি ঘটে না। এই একই যুক্তি ব্যবহার করে, এটা স্পষ্ট হওয়া উচিত যে i মূল্যটিও এই বিন্দু পর্যন্ত সংগ্রহ করা হয় না। একবার মূল লুপ শেষ হয়ে গেলে, i++ এর মান 3 তে আনতে পারি যা i < 3 ব্যর্থ অবস্থায় এবং লুপ শেষ হওয়ার ফলে পরিনত হয়। এই সময়ে, i 3 এবং তাই যখন funcs[someIndex]() ব্যবহার করা হয়, এবং i মূল্যায়ন করা হয়, এটি 3 - প্রতিবার।

এটি শেষ করার জন্য, আপনি এটি সম্মুখীন হয় হিসাবে i মূল্যায়ন করা আবশ্যক। মনে রাখবেন যে এটি ইতিমধ্যে funcs[i] আকারে ঘটেছে funcs[i] (যেখানে 3 টি অনন্য সূচী রয়েছে)। এই মান ক্যাপচার করার বিভিন্ন উপায় আছে। এক এটি একটি ফাংশন একটি পরামিতি হিসাবে এটি পাস করা হয় যা ইতিমধ্যে এখানে বিভিন্ন উপায়ে দেখানো হয়।

আরেকটি বিকল্প একটি ফাংশন অবজেক্ট গঠন করা যা পরিবর্তনশীল উপর বন্ধ করতে সক্ষম হবে। যেভাবে এইভাবে সম্পন্ন করা যেতে পারে

jsFiddle Demo

funcs[i] = new function() {   
    var closedVariable = i;
    return function(){
        console.log("My value: " + closedVariable); 
    };
};

আচ্ছা, সমস্যা হল যে পরিবর্তনশীল i , আপনার প্রতিটি বেনামী ফাংশনগুলির মধ্যে, ফাংশনের বাইরে একই পরিবর্তনশীলের সাথে আবদ্ধ।

ক্লাসিক সমাধান: ক্লোজার

আপনি যা করতে চান তা প্রতিটি ফাংশনের ভেরিয়েবলটিকে ফাংশনের বাইরে একটি আলাদা, অপরিবর্তনীয় মানতে আবদ্ধ করে:

var funcs = [];

function createfunc(i) {
    return function() { console.log("My value: " + i); };
}

for (var i = 0; i < 3; i++) {
    funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

যেহেতু জাভাস্ক্রিপ্টে কোনও ব্লক সুযোগ নেই - শুধুমাত্র ফাংশন সুযোগ - একটি নতুন ফাংশনে ফাংশন তৈরির মোড়কে, আপনি নিশ্চিত করুন যে "i" এর মানটি আপনার উদ্দেশ্য হিসাবেই থাকবে।

2015 সমাধান: সব জন্য

Array.prototype.forEach ফাংশন (২015 সালে) এর অপেক্ষাকৃত বিস্তৃত প্রাপ্যতা সহ, এটি উল্লেখযোগ্য যে, যে পরিস্থিতিতে প্রাথমিকভাবে মানগুলির অ্যারের উপর পুনরাবৃত্তি ঘটে, .forEach() একটি স্বতন্ত্র বন্ধ করার জন্য একটি পরিচ্ছন্ন, প্রাকৃতিক উপায় সরবরাহ করে প্রতি পুনরাবৃত্তি। অর্থাৎ, আপনি কোনও ধরণের অ্যারের মান পেয়েছেন (DOM রেফারেন্স, অবজেক্টস, যাই হোক না কেন), এবং সমস্যাটি প্রতিটি উপাদানের জন্য নির্দিষ্ট কলব্যাকগুলি সেটআপ করার ক্ষেত্রে উদ্ভূত হয়, আপনি এটি করতে পারেন:

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

ধারণাটি হল যে কলব্যাক ফাংশনের প্রতিটি আহ্বানের জন্য .forEach লুপটি নিজের বন্ধ করা হবে। ওই হ্যান্ডলারটিতে পাস করা পরামিতিটি পুনরাবৃত্তির নির্দিষ্ট ধাপে নির্দিষ্ট অ্যারের উপাদান। যদি এটি একটি অ্যাসিঙ্ক্রোনাস কলব্যাকে ব্যবহৃত হয় তবে এটি পুনরাবৃত্তি অন্যান্য ধাপে স্থাপিত অন্য কোনও কলব্যাকগুলির সাথে সংঘর্ষ করবে না।

আপনি যদি jQuery এ কাজ করতে থাকেন, $.each() ফাংশন আপনাকে একই রকম ক্ষমতা দেয়।

ES6 সমাধান: let

ইসিএমএসস্ক্রিপ্ট 6 (ES6), জাভাস্ক্রিপ্টের নতুন সংস্করণ, এখন অনেক চিরহরিৎ ব্রাউজার এবং ব্যাকএন্ড সিস্টেমে প্রয়োগ করা শুরু করেছে। Babel মতো ট্রান্সপারার রয়েছে যা পুরোনো সিস্টেমে নতুন বৈশিষ্ট্যগুলি ব্যবহার করার জন্য ES6 থেকে ES5 রূপান্তর করবে।

ES6 var -based ভেরিয়েবলের চেয়ে আলাদাভাবে scoped হয় নতুন লে এবং const কীওয়ার্ড প্রবর্তন করে। উদাহরণস্বরূপ, ল্যাব-ভিত্তিক সূচকের সাথে একটি লুপে, লুপের মাধ্যমে প্রতিটি পুনরাবৃত্তি আমার একটি নতুন মান পাবে যেখানে প্রতিটি মান লুপের অভ্যন্তরে স্কপ করা হবে, যাতে আপনার কোডটি আপনার প্রত্যাশা অনুসারে কাজ করবে। অনেকগুলি সম্পদ আছে, তবে আমি তথ্যটির দুর্দান্ত উত্স হিসাবে 2ality এর ব্লক-স্কোপিং পোস্টটি সুপারিশ করব

for (let i = 0; i < 3; i++) {
    funcs[i] = function() {
        console.log("My value: " + i);
    };
}

তবে সাবধান থাকুন যে এজ 9-আইই 11 এবং এজ 14 এর আগে এজ সমর্থন let তবে উপরের ভুলটি পেতে (তারা প্রতিটি সময় নতুন তৈরি করে না, তাই উপরের সমস্ত ফাংশন 3 টি লগ ইন করবে যেমন আমরা যদি var ব্যবহার করতাম)। এজ 14 অবশেষে এটা অধিকার পায়।


এই জাভাস্ক্রিপ্ট বন্ধ বন্ধ ব্যবহার সঙ্গে সাধারণ ভুল বর্ণনা করে।

একটি ফাংশন একটি নতুন পরিবেশ সংজ্ঞায়িত করে

বিবেচনা:

function makeCounter()
{
  var obj = {counter: 0};
  return {
    inc: function(){obj.counter ++;},
    get: function(){return obj.counter;}
  };
}

counter1 = makeCounter();
counter2 = makeCounter();

counter1.inc();

alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0

প্রতিবার makeCounter আহ্বান করা হয়, {counter: 0} একটি নতুন বস্তু তৈরি করা হয়। এছাড়াও, নতুন বস্তুর উল্লেখ করার জন্য obj একটি নতুন অনুলিপি তৈরি করা হয়েছে। সুতরাং, counter1 এবং counter2 একে অপরের থেকে স্বাধীন।

Loops মধ্যে বন্ধন

একটি লুপ একটি ক্লোজার ব্যবহার চতুর।

বিবেচনা:

var counters = [];

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = {
      inc: function(){obj.counter++;},
      get: function(){return obj.counter;}
    }; 
  }
}

makeCounters(2);

counters[0].inc();

alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1

লক্ষ্য করুন যে counters[0] এবং counters[1] স্বাধীন নয় । বস্তুত, তারা একই obj কাজ করে!

কারণ obj সমস্ত পুনরাবৃত্তি জুড়ে obj ভাগ করা শুধুমাত্র একটি কপি রয়েছে, সম্ভবত কার্য সম্পাদনের কারণে। যদিও {counter: 0} প্রতিটি পুনরাবৃত্তির মধ্যে একটি নতুন বস্তু তৈরি করে, তবে obj একই কপিটি কেবলমাত্র নতুন বস্তুর একটি রেফারেন্সের সাথে আপডেট হবে।

সমাধান অন্য সাহায্যকারী ফাংশন ব্যবহার করা হয়:

function makeHelper(obj)
{
  return {
    inc: function(){obj.counter++;},
    get: function(){return obj.counter;}
  }; 
}

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = makeHelper(obj);
  }
}

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

বিস্তারিত আলোচনার জন্য, জাভাস্ক্রিপ্ট বন্ধের ক্ষতি এবং ব্যবহার দেখুন


একটি অবিলম্বে-ইনভোকড ফাংশন এক্সপ্রেশন ব্যবহার করে, একটি সূচক ভেরিয়েবল ঘিরে সহজ এবং সর্বাধিক পঠনযোগ্য উপায়:

for (var i = 0; i < 3; i++) {

    (function(index) {
        console.log('iterator: ' + index);
        //now you can also loop an ajax call here 
        //without losing track of the iterator value: $.ajax({});
    })(i);

}

এটি i অ্যানিমেটেড ফাংশনে প্রেরক প্রেরণ i যা আমরা index হিসাবে সংজ্ঞায়িত করি। এটি একটি ক্লোজার তৈরি করে, যেখানে পরিবর্তনশীল i আইফাইয়ের মধ্যে যেকোন অ্যাসিঙ্ক্রোনাস কার্যকারিতা পরে পরে ব্যবহার করার জন্য সংরক্ষণ করে।


এখানে একটি সহজ সমাধান যা প্রত্যেকের জন্য ব্যবহার forEach (IE9 এ কাজ করে):

var funcs = [];
[0,1,2].forEach(function(i) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
})
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

ছাপে:

My value: 0
My value: 1
My value: 2

এখানে বিজোরের (apphacker) অনুরূপ কৌশলটির অন্যতম বৈচিত্র্য রয়েছে যা আপনাকে ফাংশনের ভিতরে পরিবর্তনশীল মান নির্ধারণ করতে দেয়, যা এটি একটি পরামিতি হিসাবে পাস করার পরিবর্তে, যা কখনও কখনও পরিষ্কার হতে পারে:

for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

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


জাভাস্ক্রিপ্ট ফাংশন তাদের কাছে অ্যাক্সেসের সুযোগটি "বন্ধ করে দেওয়া" এবং সেই সুযোগের অ্যাক্সেস বজায় রাখে, এমনকি সেই সুযোগ পরিবর্তনের ভেরিয়েবলগুলিও।

var funcs = []

for (var i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

উপরের অ্যারের প্রতিটি ফাংশন বিশ্বব্যাপী সুযোগের উপর বন্ধ করে দেয় (বিশ্বব্যাপী, কেবল যে কারণে এটি ঘোষিত সুযোগটি হ'ল)।

পরে যারা ফাংশন বিশ্বব্যাপী সুযোগ i সবচেয়ে বর্তমান মান লগিং আহ্বান করা হয়। যে জাদু, এবং হতাশা, বন্ধ।

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

var পরিবর্তে এটি for করার for প্রতিটি লুপ চালানোর for একটি নতুন সুযোগ তৈরি করে সমাধান করে, প্রতিটি ফাংশনটি বন্ধ করার জন্য একটি পৃথক সুযোগ তৈরি করে। বিভিন্ন অন্যান্য কৌশল অতিরিক্ত ফাংশন সঙ্গে একই জিনিস না।

var funcs = []

for (let i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

(ফাংশন scoped পরিবর্তে ব্লক scoped হয় যে ভেরিয়েবল তোলে। ব্লক কোঁকড়া ধনুর্বন্ধনী দ্বারা চিহ্নিত করা হয়, কিন্তু জন্য লুপ প্রারম্ভিক পরিবর্তনশীল ক্ষেত্রে, i আমাদের ক্ষেত্রে, ধনুর্বন্ধনী ঘোষণা করা হয়।)


বলার আরেকটি উপায় হল যে আপনার ফাংশনটি কার্যকর করার সময় ফাংশনটি কার্যকর করার সময় i আবদ্ধ।

আপনি বন্ধ করার সময়, i বাইরের সুযোগে সংজ্ঞায়িত পরিবর্তনশীলের একটি রেফারেন্স, এটির একটি অনুলিপি হিসাবে আপনি বন্ধ করার সময় এটি ছিল। এটি কার্যকর করার সময় মূল্যায়ন করা হবে।

অন্য বেশিরভাগ উত্তর অন্য একটি পরিবর্তনশীল তৈরি করে চারপাশে কাজ করার উপায় সরবরাহ করে যা আপনার জন্য মান পরিবর্তন করবে না।

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


সবচেয়ে সহজ সমাধান হবে,

ব্যবহার করার পরিবর্তে:

var funcs = [];
for(var i =0; i<3; i++){
    funcs[i] = function(){
        alert(i);
    }
}

for(var j =0; j<3; j++){
    funcs[j]();
}

যা 3 বার জন্য, "2" সতর্কতা। এটি কারণ লুপের জন্য বেনামী ফাংশন তৈরি করা, একই বন্ধের ভাগ করে এবং সেই বন্ধনে, i মান একই। শেয়ার বন্ধ করার জন্য এটি ব্যবহার করুন:

var funcs = [];
for(var new_i =0; new_i<3; new_i++){
    (function(i){
        funcs[i] = function(){
            alert(i);
        }
    })(new_i);
}

for(var j =0; j<3; j++){
    funcs[j]();
}

এর পিছনে ধারণা, IIFE (অবিলম্বে-ইনভোকড ফাংশন এক্সপ্রেশন) সহ লুপের পুরো শরীরকে new_i করা এবং new_i প্যারামিটার হিসেবে প্রেরণ করা এবং এটির মতো ক্যাপচার করা। যেহেতু বেনামী ফাংশনটি অবিলম্বে কার্যকর করা হয়, তাই বেনামী ফাংশনের ভিতরে সংজ্ঞায়িত প্রতিটি ফাংশনের জন্য i মান ভিন্ন।

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


একটি প্রাইভেট হচ্ছে COUNTER

নিম্নরূপ কলব্যাক ফাংশন সংজ্ঞায়িত করা যাক:

// ****************************
// COUNTER BEING A PRIMITIVE
// ****************************
function test1() {
    for (var i=0; i<2; i++) {
        setTimeout(function() {
            console.log(i);
        });
    }
}
test1();
// 2
// 2

সময়সীমার সমাপ্তির পরে এটি উভয়ের জন্য 2 মুদ্রণ করবে। কারণ কলব্যাক ফাংশনটি এক্সিকিউটিভ স্কোপের উপর ভিত্তি করে মানটি অ্যাক্সেস করে , যেখানে এটি ফাংশনটি সংজ্ঞায়িত করা হয়েছিল।

কলব্যাক সংজ্ঞায়িত করা হয়েছে যখন মান পাস এবং সংরক্ষণ, আমরা callback আহ্বান আগে মান সংরক্ষণ করতে, একটি closure নির্মাণ করতে পারেন । ইহা এভাবে করা যাবে:

function test2() {
    function sendRequest(i) {
        setTimeout(function() {
            console.log(i);
        });
    }

    for (var i = 0; i < 2; i++) {
        sendRequest(i);
    }
}
test2();
// 1
// 2

এখন এই সম্পর্কে বিশেষ কি "Primitives মান এবং কপি দ্বারা পাস করা হয়। সুতরাং যখন বন্ধ সংজ্ঞায়িত করা হয়, তারা আগের লুপ থেকে মান রাখা।"

একটি বিষয় হচ্ছে COUNTER

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

// ****************************
// COUNTER BEING AN OBJECT
// ****************************
function test3() {
    var index = { i: 0 };
    for (index.i=0; index.i<2; index.i++) {
        setTimeout(function() {
            console.log('test3: ' + index.i);
        });
    }
}
test3();
// 2
// 2

সুতরাং, যদি একটি অবজেক্টের জন্য একটি ক্লোজার তৈরি করা হয় যেমন কোনও বস্তু হিসাবে প্রেরণ করা হয়, তবে লুপ সূচকের মান সংরক্ষণ করা হবে না। এটি দেখানো হয় যে কোনও বস্তুর মান কপি করা হয় না তবে এটি রেফারেন্সের মাধ্যমে অ্যাক্সেস করা হয়।

function test4() {
    var index = { i: 0 };
    function sendRequest(index, i) {
        setTimeout(function() {
            console.log('index: ' + index);
            console.log('i: ' + i);
            console.log(index[i]);
        });
    }

    for (index.i=0; index.i<2; index.i++) {
        sendRequest(index, index.i);
    }
}
test4();
// index: { i: 2}
// 0
// undefined

// index: { i: 2}
// 1
// undefined

আপনার কোড কাজ করে না, কারণ এটি কি করে:

Create variable `funcs` and assign it an empty array;  
Loop from 0 up until it is less than 3 and assign it to variable `i`;
    Push to variable `funcs` next function:  
        // Only push (save), but don't execute
        **Write to console current value of variable `i`;**

// First loop has ended, i = 3;

Loop from 0 up until it is less than 3 and assign it to variable `j`;
    Call `j`-th function from variable `funcs`:  
        **Write to console current value of variable `i`;**  
        // Ask yourself NOW! What is the value of i?

এখন প্রশ্ন হল, iফাংশন বলা হয় যখন পরিবর্তনশীল মান কি ? কারণ প্রথম লুপটি শর্তের সাথে তৈরি হয় i < 3, যখন এটি মিথ্যা হয় তখন তা অবিলম্বে বন্ধ হয়ে যায়, তাই এটি হয় i = 3

আপনার বুঝতে হবে যে, যখন আপনার ফাংশন তৈরি হয় তখন তাদের কোনও কোড কার্যকর করা হয় না, এটি শুধুমাত্র পরে সংরক্ষণ করা হয়। এবং যখন তাদেরকে পরে বলা হয়, তখন দোভাষী তাদের নির্বাহ করে এবং জিজ্ঞেস করে: "বর্তমান মূল্য কত i?"

সুতরাং, আপনার লক্ষ্য প্রথমে iফাংশনের মানটি সংরক্ষণ করা এবং তারপরে শুধুমাত্র ফাংশনটি সংরক্ষণ করার পরে funcs। এই উদাহরণস্বরূপ এই ভাবে করা যেতে পারে:

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function(x) {            // and store them in funcs
        console.log("My value: " + x); // each should log its value.
    }.bind(null, i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

এই ভাবে, প্রতিটি ফাংশন এটা নিজস্ব পরিবর্তনশীল থাকবে xএবং আমরা এই সেট xএর মান iপ্রতিটি পুনরাবৃত্তির।

এই সমস্যাটি সমাধানের একাধিক উপায়ে এটি এক।


সর্বোপরি, এই কোডটি কী ভুল বুঝেছেন:

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

এখানে যখন funcs[]অ্যারের সূচনা iহচ্ছে, বাড়ানো হচ্ছে, funcsঅ্যারে শুরু করা হয়েছে এবং funcঅ্যারের আকার 3 হয়ে যায়, তাই i = 3,। এখন যখন funcs[j]()বলা হয়, এটি আবার পরিবর্তনশীল ব্যবহার করছে i, যা ইতিমধ্যে 3 বৃদ্ধি পেয়েছে।

এখন সমাধান করার জন্য আমাদের অনেক অপশন আছে। নীচে তাদের দুটি

  1. আমরা আরম্ভ করতে পারেন iসঙ্গে letঅথবা একটি নতুন পরিবর্তনশীল আরম্ভ indexসঙ্গে letএবং এটি সমান করা i। তাই যখন কল করা হচ্ছে, তখন indexব্যবহার করা হবে এবং এর সুযোগ শুরু হওয়ার পরে শেষ হবে। এবং কলিং জন্য, indexআবার শুরু করা হবে:

    var funcs = [];
    for (var i = 0; i < 3; i++) {          
        let index = i;
        funcs[i] = function() {            
            console.log("My value: " + index); 
        };
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
    
  2. অন্যান্য বিকল্প tempFuncপ্রকৃত ফাংশন ফেরত যা একটি পরিচয় করিয়ে দিতে হতে পারে :

    var funcs = [];
    function tempFunc(i){
        return function(){
            console.log("My value: " + i);
        };
    }
    for (var i = 0; i < 3; i++) {  
        funcs[i] = tempFunc(i);                                     
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
    

অনেক সমাধান সঠিক বলে মনে হয় তবে তারা এটির নাম উল্লেখ করে না Curryingযা এটির মতো পরিস্থিতিগুলির জন্য একটি কার্যকরী প্রোগ্রামিং ডিজাইন প্যাটার্ন। ব্রাউজার উপর নির্ভর করে বাঁধন তুলনায় 3-10 গুণ দ্রুত।

var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = curryShowValue(i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

function curryShowValue(i) {
  return function showValue() {
    console.log("My value: " + i);
  }
}

বিভিন্ন ব্রাউজারে কর্মক্ষমতা লাভ দেখুন ।


আপনার মূল উদাহরণ কাজ করে না কারণ লুপে আপনি যে সমস্ত বন্ধন তৈরি করেছেন সেটি একই ফ্রেমের উল্লেখ করেছে। ফলস্বরূপ, শুধুমাত্র একটি একক iপরিবর্তনশীল সঙ্গে একটি বস্তুর 3 পদ্ধতি হচ্ছে । তারা সব একই মান মুদ্রিত।


আমি forEachফাংশন ব্যবহার করতে পছন্দ করি , এটি একটি ছদ্ম পরিসীমা তৈরির সাথে নিজস্ব বন্ধ রয়েছে:

var funcs = [];

new Array(3).fill(0).forEach(function (_, i) { // creating a range
    funcs[i] = function() {            
        // now i is safely incapsulated 
        console.log("My value: " + i);
    };
});

for (var j = 0; j < 3; j++) {
    funcs[j](); // 0, 1, 2
}

অন্যান্য ভাষাগুলির চেয়ে শ্রেণিবদ্ধ মনে হচ্ছে, তবে অন্যান্য সমাধানগুলির চেয়ে IMHO কম ক্ষতিকর।


আমি forEachস্থানীয় ভেরিয়েবল ব্যবহার করে ভালভাবে এড়াতে আবার (ফাংশন) ফাংশন ব্যবহার করে প্রস্তাব করা হয়েছে যে কেউ এখনো অবাক । আসলে, আমি for(var i ...)এই কারণে আর সব ব্যবহার করছি না ।

[0,2,3].forEach(function(i){ console.log('My value:', i); });
// My value: 0
// My value: 2
// My value: 3

// forEachপরিবর্তে মানচিত্র ব্যবহার করতে সম্পাদনা ।


এবং এখনো আরেকটি সমাধান: অন্য লুপ তৈরি করার পরিবর্তে, thisফিরতি ফাংশনটির সাথে যুক্ত করুন।

var funcs = [];

function createFunc(i) {
  return function() {
    console.log('My value: ' + i); //log value of i.
  }.call(this);
}

for (var i = 1; i <= 5; i++) {  //5 functions
  funcs[i] = createFunc(i);     // call createFunc() i=5 times
}

এই বাঁধাই দ্বারা, পাশাপাশি সমস্যার সমাধান।


বিভিন্ন সমাধানের মাধ্যমে পড়ার পরে, আমি যুক্ত করতে চাই যে সমাধানগুলির কারণটি সুযোগ চেইনটির ধারণার উপর নির্ভর করা । জাভাস্ক্রিপ্ট এক্সিকিউশন সময় একটি পরিবর্তনশীল সমাধান উপায়।

  • প্রতিটি ফাংশন সংজ্ঞা varতার দ্বারা ঘোষিত সমস্ত স্থানীয় ভেরিয়েবল গঠিত একটি সুযোগ গঠন করে arguments
  • যদি আমাদের ভিতরের ফাংশনটি অন্য (বহিরাগত) ফাংশনের ভিতরে সংজ্ঞায়িত থাকে, এটি একটি শৃঙ্খল গঠন করে এবং কার্যকরকরণের সময় ব্যবহার করা হবে
  • একটি ফাংশন কার্যকর করা হয়, রানটাইম সুযোগ চেইন অনুসন্ধান করে ভেরিয়েবল মূল্যায়ন । যদি কোন পরিবর্তনশীল শৃঙ্খলের একটি নির্দিষ্ট বিন্দুতে এটি পাওয়া যায় তবে এটি অনুসন্ধান বন্ধ করে দেবে এবং এটি ব্যবহার করবে না, অন্যথায় এটি বিশ্বব্যাপী সুযোগ পৌঁছানোর পূর্ব পর্যন্ত এটি অব্যাহত থাকবে window

প্রাথমিক কোডে:

funcs = {};
for (var i = 0; i < 3; i++) {         
  funcs[i] = function inner() {        // function inner's scope contains nothing
    console.log("My value: " + i);    
  };
}
console.log(window.i)                  // test value 'i', print 3

যখন funcsমৃত্যুদন্ড কার্যকর করা হবে, সুযোগ চেইন হবে function inner -> global। যেহেতু ভেরিয়েবলটি iপাওয়া যাবে না function inner(তত্সহ ঘোষনা varহিসাবে ব্যবহার না করেও ঘোষণা করা হয়েছে না), এটি অনুসন্ধান অব্যাহত থাকবে যতক্ষন iনা মূলত গ্লোবাল সুযোগটি পাওয়া যায় window.i

এটিকে একটি বাইরের ফাংশনে মোড়কে পারেন স্পষ্টভাবে সংজ্ঞায়িত মত একটি সাহায্যকারী ফাংশন share করেনি বা একটি বেনামী ফাংশন ব্যবহার মত share যা করেছে:

funcs = {};
function outer(i) {              // function outer's scope contains 'i'
  return function inner() {      // function inner, closure created
   console.log("My value: " + i);
  };
}
for (var i = 0; i < 3; i++) {
  funcs[i] = outer(i);
}
console.log(window.i)          // print 3 still

যখন funcsমৃত্যুদন্ড কার্যকর করা হবে, এখন সুযোগ চেইন হবে function inner -> function outer। এই সময় iবাইরের ফাংশনের সুযোগে পাওয়া যেতে পারে যা লুপের জন্য 3 বার কার্যকর করা হয়, প্রতিটি সময় মান iসঠিকভাবে আবদ্ধ থাকে। এটি window.iঅভ্যন্তরীণ নির্বাহ যখন মান ব্যবহার করবে না ।

আরো বিস্তারিত here পাওয়া যাবে here
লুপ বন্ধ করার ক্ষেত্রে সাধারণ ভুল অন্তর্ভুক্ত রয়েছে যা আমাদের এখানে আছে, সেইসাথে আমাদের বন্ধ করার এবং কর্মক্ষমতা বিবেচনা করার প্রয়োজন রয়েছে।





closures