জাভাস্ক্রিপ্ট ক্লোজারগুলি কীভাবে কাজ করবে?


7636

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

আমি উইকিপিডিয়ায় দেওয়া স্কিমের উদাহরণটি দেখেছি , তবে দুর্ভাগ্যক্রমে এটি কার্যকর হয়নি।


391
জাভাস্ক্রিপ্ট এবং আপনি যে ব্যবহারিক পরিস্থিতিতে আপনি এটি ব্যবহার করছেন তাতে কেন ক্লোজার প্রয়োজন হয় তা কেবল ব্যাখ্যা দিয়ে শুরু করার পরিবর্তে এগুলি এবং অনেক উত্তরগুলির সাথে আমার সমস্যাটি হ'ল তারা এটিকে একটি বিমূর্ত, তাত্ত্বিক দৃষ্টিভঙ্গি থেকে দেখেন। আপনি একটি টিএল; ড আর্টিকেলটি দিয়ে শেষ করতে পারেন যা আপনাকে সর্বদা ভাবতে হবে, "তবে, কেন?"। আমি কেবল এইটি দিয়ে শুরু করব: বন্ধগুলি জাভাস্ক্রিপ্টের নিম্নলিখিত দুটি বাস্তবতার সাথে আচরণ করার একটি ঝরঝরে উপায় are সুযোগ ফাংশন স্তরে, ব্লক স্তর নয় এবং, খ। আপনি জাভাস্ক্রিপ্টে অনুশীলনে যা করেন তার বেশিরভাগই অ্যাসিনক্রোনাস / ইভেন্ট চালিত।
জেরেমি বার্টন

53
@ রেডসানড্রো একটির জন্য এটি ইভেন্ট-চালিত কোডকে লেখা অনেক সহজ করে তোলে। HTML বা উপলভ্য বৈশিষ্ট্যগুলি সম্পর্কে সুনির্দিষ্টতা নির্ধারণ করতে পৃষ্ঠাটি লোড হয়ে গেলে আমি কোনও ফাংশন নষ্ট করতে পারি। আমি সেই ফাংশনে একটি হ্যান্ডলার সংজ্ঞায়িত করতে এবং সেট করতে পারি এবং হ্যান্ডলারটিকে পুনরায় জিজ্ঞাসা না করে প্রতিবার যখন ডাকা হয় তখন সমস্ত প্রসঙ্গের তথ্য উপলব্ধ থাকে। সমস্যাটি একবার সমাধান করুন, প্রতি পৃষ্ঠায় পুনরায় ব্যবহার করুন যেখানে হ্যান্ডলারের পুনরায় অনুরোধে হ্যান্ডলারের হ্রাস ওভারহেডের প্রয়োজন হয়। আপনি কখনও একই ডেটাটি এমন কোনও ভাষায় পুনরায় ম্যাপ করতে দেখেন যেটি নেই? বন্ধগুলি এই ধরণের জিনিস এড়ানো সহজ করে তোলে।
এরিক রেপেন

1
@ এরিক উত্তর দেওয়ার জন্য ধন্যবাদ। প্রকৃতপক্ষে, আমি closureকোডটি পড়ার পক্ষে এর শক্ত সুবিধার বিষয়ে কৌতূহলী ছিলাম Object Literalযার বিপরীতে নিজেই পুনরায় ব্যবহার করে এবং ওভারহেডকে হ'ল হ্রাস করে, তবুও 100% কম মোড়ানোর কোডের প্রয়োজন হয়।
রেডসান্দ্রো

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

8
আমি এই ব্যবহারিক উদাহরণটি খুব দরকারী হিসাবে পেয়েছি: youtube.com/watch?v=w1s9PgtEoJs
অভি

উত্তর:


7355

বন্ধ একটি জুড়ি:

  1. একটি ফাংশন, এবং
  2. এই ফাংশনের বাইরের স্কোপের একটি রেফারেন্স (লেক্সিকাল পরিবেশ)

একটি লেজিকাল এনভায়রনমেন্ট প্রতিটি সম্পাদন প্রসঙ্গে (স্ট্যাক ফ্রেম) অংশ এবং এটি শনাক্তকারীদের (যেমন স্থানীয় পরিবর্তনশীল নাম) এবং মানগুলির মধ্যে একটি মানচিত্র between

জাভাস্ক্রিপ্টের প্রতিটি ফাংশন তার বাইরের লেক্সিকাল পরিবেশের একটি রেফারেন্স বজায় রাখে। এই রেফারেন্সটি যখন কোনও ফাংশন শুরু হয় তখন তৈরি কার্যকর সম্পাদনা কনফিগার করতে ব্যবহৃত হয়। এই রেফারেন্সটি ফাংশনটির ভিতরে কোডটি সক্ষম করে ফাংশনটি কখন এবং কোথায় ডাকা হয় তা নির্বিশেষে ফাংশনের বাইরে ঘোষিত ভেরিয়েবলগুলি "দেখতে" দেয়।

যদি কোনও ফাংশন কোনও ফাংশন দ্বারা ডাকা হত, যার পরিবর্তে অন্য ফাংশন দ্বারা ডাকা হত, তবে বহিরাগত বর্ণগত পরিবেশগুলির জন্য রেফারেন্সের একটি শৃঙ্খলা তৈরি হয়। এই চেইনকে স্কোপ চেইন বলে called

নিম্নলিখিত innerকোডটিতে, ডাকে যখন fooপ্রয়োগ করা হয় তখন কার্যকর করা প্রসঙ্গের লেজিকাল পরিবেশের সাথে একটি বন্ধের রূপ দেয় , ভেরিয়েবলের উপর দিয়ে বন্ধ করেsecret :

function foo() {
  const secret = Math.trunc(Math.random()*100)
  return function inner() {
    console.log(`The secret number is ${secret}.`)
  }
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret`, is to invoke `f`

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

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

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

সুতরাং, আপনি যদি কোনও ফাংশনটির সর্বদা ব্যক্তিগত বেসরকারী অংশে অ্যাক্সেস পেতে চান তবে আপনি একটি বন্ধ ব্যবহার করতে পারেন।

... এবং প্রায়শই আমরা একটি ফাংশনের সাথে রাষ্ট্রকে যুক্ত করতে চাই। উদাহরণস্বরূপ, জাভা বা সি ++ এ, আপনি যখন ক্লাসে একটি বেসরকারী উদাহরণ পরিবর্তনশীল এবং একটি পদ্ধতি যুক্ত করেন, তখন আপনি কার্যকারিতার সাথে রাষ্ট্রের সাথে যুক্ত হন।

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

বন্ধের ব্যবহার

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

ব্যক্তিগত তাত্ক্ষণিক চলক

নিম্নলিখিত কোডে, ফাংশন toStringগাড়ির বিবরণ বন্ধ করে দেয়।

function Car(manufacturer, model, year, color) {
  return {
    toString() {
      return `${manufacturer} ${model} (${year}, ${color})`
    }
  }
}
const car = new Car('Aston Martin','V8 Vantage','2012','Quantum Silver')
console.log(car.toString())

ফাংশনাল প্রোগ্রামিং

নিম্নলিখিত কোডে, ফাংশন innerউভয় fnএবং বন্ধ হয়ে যায় args

function curry(fn) {
  const args = []
  return function inner(arg) {
    if(args.length === fn.length) return fn(...args)
    args.push(arg)
    return inner
  }
}

function add(a, b) {
  return a + b
}

const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5

ইভেন্ট-ওরিয়েন্টেড প্রোগ্রামিং

নিম্নলিখিত কোডে, ফাংশনটি onClickভেরিয়েবলের উপরে বন্ধ হয় BACKGROUND_COLOR

const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200,200,242,1)'

function onClick() {
  $('body').style.background = BACKGROUND_COLOR
}

$('button').addEventListener('click', onClick)
<button>Set background color</button>

modularization

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

let namespace = {};

(function foo(n) {
  let numbers = []
  function format(n) {
    return Math.trunc(n)
  }
  function tick() {
    numbers.push(Math.random() * 100)
  }
  function toString() {
    return numbers.map(format)
  }
  n.counter = {
    tick,
    toString
  }
}(namespace))

const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())

উদাহরণ

উদাহরণ 1

এই উদাহরণটি দেখায় যে স্থানীয় ভেরিয়েবলগুলি বন্ধে অনুলিপি করা হয়নি: বন্ধটি মূল ভেরিয়েবলগুলির নিজস্ব একটি রেফারেন্স বজায় রাখে । এটি স্ট্যাক-ফ্রেমটি বাহ্যিক ক্রিয়াটি প্রস্থান করার পরেও স্মৃতিতে সজীব থাকে is

function foo() {
  let x = 42
  let inner  = function() { console.log(x) }
  x = x+1
  return inner
}
var f = foo()
f() // logs 43

উদাহরণ 2

নিম্নলিখিত কোড, তিন পদ্ধতিতে log, incrementএবং updateএকই আভিধানিক পরিবেশ উপর সব বন্ধ।

এবং প্রত্যেকবার createObjectবলা হয়, একটি নতুন এক্সিকিউশন কনটেক্সট (স্ট্যাক ফ্রেম) তৈরি করা হয় এবং একটি সম্পূর্ণ নতুন ভেরিয়েবল x, এবং ফাংশনগুলির একটি নতুন সেট ( logইত্যাদি) তৈরি করা হয়, যা এই নতুন ভেরিয়েবলের কাছাকাছি অবস্থিত।

function createObject() {
  let x = 42;
  return {
    log() { console.log(x) },
    increment() { x++ },
    update(value) { x = value }
  }
}

const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42

উদাহরণ 3

যদি আপনি ব্যবহার করে ঘোষিত ভেরিয়েবলগুলি ব্যবহার করে থাকেন তবে আপনি varকোন ভেরিয়েবলটি বন্ধ করে দিচ্ছেন সে বিষয়ে সতর্ক হন। ব্যবহার করে ঘোষিত varচলকগুলি উত্তোলন করা হয়। এই অনেক আধুনিক জাভাস্ক্রিপ্ট একটি সমস্যা কম প্রবর্তনের কারণে letএবং const

নিম্নলিখিত কোডে, প্রতিবার লুপের চারপাশে একটি নতুন ফাংশন innerতৈরি করা হয় যা বন্ধ হয়ে যায় i। তবে var iলুপের বাইরে উত্তোলন করা হওয়ায় এই সমস্ত অভ্যন্তরীণ ফাংশন একই ভেরিয়েবলের উপরে অবস্থিত, যার অর্থ i(3) এর চূড়ান্ত মানটি তিনবার মুদ্রিত হয়।

function foo() {
  var result = []
  for (var i = 0; i < 3; i++) {
    result.push(function inner() { console.log(i) } )
  }
  return result
}

const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
  result[i]() 
}

চূড়ান্ত পয়েন্ট:

  • যখনই জাভাস্ক্রিপ্টে কোনও ফাংশন ঘোষিত হয় তখন বন্ধ হয়ে যায়।
  • ফিরে আসা a functionঅন্য ফাংশনের অভ্যন্তর থেকে কোনও বন্ধের ক্লাসিক উদাহরণ, কারণ বাহ্যিক ক্রিয়াকলাপ শেষ হয়ে গেলেও বাইরের ফাংশনের অভ্যন্তরীণ অবস্থা প্রত্যাবর্তিত অভ্যন্তরীণ ফাংশনটিতে স্পষ্টতই উপলব্ধ।
  • আপনি যখনই eval()কোনও ফাংশনের ভিতরে ব্যবহার করেন , তখন একটি বন্ধ ব্যবহার করা হয়। পাঠ্যটি আপনি evalফাংশনের স্থানীয় ভেরিয়েবলগুলি উল্লেখ করতে পারেন এবং অ-কঠোর মোডে আপনি এমনকি নতুন স্থানীয় ভেরিয়েবল ব্যবহার করে তৈরি করতে পারেনeval('var foo = …')
  • আপনি যখন কোনও ফাংশনের অভ্যন্তরে new Function(…)( ফাংশন কনস্ট্রাক্টর ) ব্যবহার করেন, এটি এর লেজিকাল পরিবেশের সাথে বন্ধ হয় না: পরিবর্তে এটি বিশ্বব্যাপী প্রেক্ষাপটে বন্ধ হয়ে যায়। নতুন ফাংশনটি বাইরের ফাংশনের স্থানীয় ভেরিয়েবলগুলি উল্লেখ করতে পারে না।
  • জাভাস্ক্রিপ্টে বন্ধ হওয়া একটি রেফারেন্স রাখার মতো ( নয়) ফাংশন ঘোষণার বিন্দুতে অনুলিপি ) , যা তার বাহ্যিক ক্ষেত্রের রেফারেন্স রাখে, এবং এইভাবে, গ্লোবাল অবজেক্টের শীর্ষে অবস্থিত সমস্ত উপায় সুযোগ শৃঙ্খলা।
  • কোনও ফাংশন ঘোষিত হওয়ার পরে একটি ক্লোজার তৈরি হয়; এই সমাপনিটি ফাংশনটি চালিত হওয়ার পরে নির্বাহের প্রসঙ্গটি কনফিগার করতে ব্যবহৃত হয়।
  • লোকাল ভেরিয়েবলগুলির একটি নতুন সেটটি যখনই কোনও ফাংশন বলা হয় ততবার তৈরি হয়।

লিংক


74
এটি দুর্দান্ত শোনায়: "জাভাস্ক্রিপ্টে একটি বন্ধকরণ সমস্ত স্থানীয় ভেরিয়েবলের অনুলিপি রাখার মতো, যেমন কোনও ফাংশনটি বের হওয়ার সময় ছিল" " তবে এটি বেশ কয়েকটি কারণে বিভ্রান্তিকর। (1) বন্ধ করার জন্য ফাংশন কলটি প্রস্থান করতে হবে না। (২) এটি স্থানীয় ভেরিয়েবলের মানগুলির অনুলিপি নয়, ভেরিয়েবলগুলি নিজেরাই। (3) এই ভেরিয়েবলগুলিতে কার অ্যাক্সেস রয়েছে তা তা বলে না।
dlaliberte

27
উদাহরণ 5 একটি "গ্যাচা" দেখায় যেখানে কোডটি উদ্দেশ্য অনুযায়ী কাজ করে না। তবে এটি কীভাবে ঠিক করা যায় তা দেখায় না। এই অন্যান্য উত্তর এটি করার একটি উপায় দেখায়।
ম্যাট

190
আমি পছন্দ করি যে কীভাবে "ক্লোজারস আর নট ম্যাজিক" বলে বড় সাহসী চিঠিগুলি দিয়ে এই পোস্টটি শুরু হবে এবং "যাদুটি হ'ল জাভাস্ক্রিপ্টে কোনও ফাংশন রেফারেন্সে এটি বন্ধ হওয়ার বিষয়ে একটি গোপনীয় রেফারেন্স রয়েছে" দিয়ে শেষ হয়।
অ্যান্ড্রু মাচেরেট

6
উদাহরণ # 3 হ'ল জাভাস্ক্রিপ্ট উত্তোলনের সাথে ক্লোজার মিশ্রণ। এখন আমি মনে করি যে উত্তোলনের আচরণ না আনাই কেবল বন্ধের ব্যাখ্যা দেওয়া যথেষ্ট কঠিন। এটি আমাকে সবচেয়ে বেশি সহায়তা করেছে: বিকাশকারী.মোজিলা.অর্গClosures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created. থেকে
ইউএস

3
ECMAScript 6 বন্ধ হওয়া সম্পর্কে এই দুর্দান্ত নিবন্ধে কিছু পরিবর্তন করতে পারে। উদাহরণস্বরূপ, আপনি যদি উদাহরণ 5 এর let i = 0পরিবর্তে ব্যবহার করেন var i = 0তবে testList()আপনি যা চান সেটি প্রিন্ট করবে।
নাইয়ার

3988

জাভাস্ক্রিপ্টের প্রতিটি ফাংশন তার বাইরের লেক্সিকাল পরিবেশের একটি লিঙ্ক বজায় রাখে। একটি লেজিকাল এনভায়রনমেন্ট হ'ল একটি মানচিত্রের মধ্যে সমস্ত নামের একটি মানচিত্র (যেমন ভেরিয়েবল, পরামিতি) যার মান রয়েছে।

সুতরাং, আপনি যখনই functionকীওয়ার্ডটি দেখতে পাচ্ছেন তখন সেই ফাংশনের অভ্যন্তরের কোডটিতে ফাংশনের বাইরে ঘোষিত ভেরিয়েবলগুলির অ্যাক্সেস থাকে।

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

এটি লগ করবে 16কারণ ফাংশনটি barপ্যারামিটার xএবং ভেরিয়েবলের উপরে বন্ধ হয়ে যায় tmp, উভয়ই বাহ্যিক ফাংশনের লেজিকাল পরিবেশে বিদ্যমানfoo

ফাংশন bar, ফাংশন আভিধানিক পরিবেশের সঙ্গে তার লিঙ্কের সাথে একত্রে fooএকটি অবসান হয়।

একটি ফাংশন নেই আসতে অর্ডার অবসান তৈরি করার জন্য। কেবলমাত্র এটির ঘোষণার ভিত্তিতে, প্রতিটি ফাংশন তার ঘেরযুক্ত লেজিকাল পরিবেশের উপর বন্ধ হয়ে একটি বন্ধন গঠন করে।

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2);
bar(10); // 16
bar(10); // 17

উপরের ফাংশনটি 16 টিও লগ করবে, কারণ অভ্যন্তরীণ কোডটি barএখনও আর্গুমেন্ট xএবং ভেরিয়েবলকে উল্লেখ করতে পারে tmp, যদিও তারা সরাসরি সুযোগে নেই।

তবে tmpএখনও যেহেতু barবন্ধের ভিতরে এখনও ঝুলছে তাই এটি বাড়ানোর জন্য উপলব্ধ। আপনি প্রতিবার কল করলে এটি বাড়ানো হবেbar

বন্ধ হওয়ার সহজ উদাহরণ হ'ল:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

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

প্রতিটি ফাংশন একটি ক্লোজার তৈরি করে কারণ প্রতিটি ফাংশনটির বাইরের লেক্সিকাল পরিবেশের একটি লিঙ্ক রয়েছে।

মনে রাখবেন যে, ভেরিয়েবল নিজেদের একটি বন্ধ, মধ্যে থেকে দৃশ্যমান না কপি।


24
@ ফিফিলা: হ্যাঁ, প্রতিটি জেএস ফাংশন একটি বন্ধ করে দেয়। পরিবর্তনশীল যা রেফারেন্সযুক্ত নয় সম্ভবত আধুনিক জেএস ইঞ্জিনগুলিতে আবর্জনা সংগ্রহের জন্য যোগ্য করে তোলা হবে, তবে এটি বাস্তবায়িত হয় না যে আপনি যখন একটি কার্যকর সম্পাদনা প্রসঙ্গে তৈরি করেন, সেই প্রসঙ্গে আবদ্ধকরণের কার্যকর প্রসঙ্গে এবং তার ভেরিয়েবলগুলির একটি রেফারেন্স থাকে এবং সেই ফাংশনটি এমন একটি অবজেক্ট যা এর মূল রেফারেন্স ধরে রেখে বিভিন্ন ভেরিয়েবল স্কোপে স্থানান্তরিত হওয়ার সম্ভাবনা থাকে। এটাই বন্ধ।

@ অলি আমি সবেমাত্র আবিষ্কার করেছি যে আমার দেওয়া জেএসফিডেল আসলে কোনও প্রমাণ দেয় না, যেহেতু deleteব্যর্থ হয়। তবুও, ফাংশনটি [[Scope]] হিসাবে প্রায় বহন করবে (এবং শেষ পর্যন্ত তার নিজস্ব লেসিকাল পরিবেশের জন্য ভিত্তি হিসাবে ব্যবহার করবে) যে ফাংশনটিকে সংজ্ঞায়িত করে যে স্টেটমেন্টটি কার্যকর করা হয় তা নির্ধারণ করা হয়। এর অর্থ হ'ল ফাংশনটি নির্বাহের সুযোগের পুরো বিষয়বস্তুগুলিতে বন্ধ হয়ে যাচ্ছে, এটি কোন মানগুলি প্রকৃতপক্ষে উল্লেখ করে এবং এটি সুযোগ থেকে দূরে যায় কিনা তা নির্বিশেষে। দয়া করে বিভাগে 13.2 এবং 10 তাকান বৈশিষ্ট
আসাদ Saeeduddin

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

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

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

2442

পূর্ববর্তী: এই উত্তরটি যখন লেখা হয়েছিল তখন:

পুরানো অ্যালবার্ট যেমন বলেছিলেন: "আপনি যদি এটি ছয় বছরের বৃদ্ধকে ব্যাখ্যা করতে না পারেন তবে আপনি নিজেই এটি বুঝতে পারবেন না” "ভাল আমি জেএস বন্ধের একটি 27 বছরের পুরানো বন্ধুর কাছে ব্যাখ্যা করার চেষ্টা করেছি এবং সম্পূর্ণরূপে ব্যর্থ হয়েছিল।

কেউ কি বিবেচনা করতে পারেন যে আমি 6 এবং আশ্চর্যজনকভাবে সেই বিষয়ে আগ্রহী?

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


আমি কঠিন ধারণাটি ব্যাখ্যা করার সময় আমি উপমা এবং রূপকের একটি বড় অনুরাগী, তাই আমাকে একটি গল্প দিয়ে আমার হাত দিয়ে চেষ্টা করুন।

এককালে:

একটি রাজকন্যা ছিল ...

function princess() {

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

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

তবে তাকে সবসময় তার স্বাচ্ছন্দ্য এবং বয়োবৃদ্ধিতে ফিরে আসতে হবে।

    return {

এবং তিনি প্রায়শই রাজকন্যা হিসাবে তার সর্বশেষ বিস্ময়কর দু: সাহসিক কাজ তাদের বলতেন।

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

তবে তারা কেবল একটি ছোট মেয়ে দেখবে ...

var littleGirl = princess();

... যাদু এবং কল্পনা সম্পর্কে গল্প বলা।

littleGirl.story();

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

তবে আমরা আসল সত্য জানি; ভিতরে রাজকন্যার সাথে ছোট মেয়েটি ...

... সত্যিই ভিতরে একটি ছোট মেয়ে সহ একটি রাজকন্যা।


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

সুতরাং এখানে storyক্লোজারটি কিন্তু কোডটি ছিল var story = function() {}; return story;তাহলে littleGirlবন্ধ হবে। কমপক্ষে এমডিএন'র 'বেসরকারী' পদ্ধতিগুলির ক্লোজারগুলির ব্যবহার থেকে আমি এই ধারণাটি পেয়েছি : "এই তিনটি পাবলিক ফাংশন হ'ল ক্লোজার যা একই পরিবেশকে ভাগ করে দেয়।"
icc97

16
@ আইসিসি ৯7, হ্যাঁ, storyএর পরিধির মধ্যে প্রদত্ত পরিবেশকে উল্লেখ করা একটি ক্লোজার princessprincessএটি অন্য একটি অন্তর্নিহিত বন্ধ, অর্থাত্‍ এবং হ'ল পরিবেশের / স্কোপে যেখানে বিদ্যমান এবং সংজ্ঞা দেওয়া আছে সেখানে কোনও অ্যারের সাথে কোনও রেফারেন্স ভাগ princessকরে littleGirlনিবে । parentslittleGirlprincess
জ্যাকব সোয়ার্টউড

6
@ বেনজামিনক্রুপ আমি দেখানোর / বোঝাতে একটি স্পষ্ট কোড মন্তব্য যুক্ত করেছি যে princessযা লিখিত আছে তার চেয়ে বেশি অপারেশন রয়েছে show দুর্ভাগ্যক্রমে এই গল্পটি এখন এই থ্রেডের থেকে কিছুটা দূরে। মূলত প্রশ্নটি "5 বছরের পুরানো জাভাস্ক্রিপ্টের বন্ধগুলি ব্যাখ্যা করার জন্য" জিজ্ঞাসা করেছিল; আমার প্রতিক্রিয়া কেবলমাত্র এটিই করার চেষ্টা করেছিল। আমি সন্দেহ করি না যে এটি খারাপভাবে ব্যর্থ হয়ে গেছে, তবে কমপক্ষে এই প্রতিক্রিয়াতে 5 বছরের পুরানো আগ্রহের সুযোগ থাকতে পারে।
জ্যাকব সোয়ার্টউড

11
আসলে, আমার কাছে এটি নিখুঁত ধারণা তৈরি হয়েছিল made এবং আমাকে অবশ্যই স্বীকার করতে হবে, শেষ পর্যন্ত রাজকন্যা এবং অ্যাডভেঞ্চারের গল্প ব্যবহার করে একটি জেএস বন্ধের বিষয়টি বুঝতে পেরে আমাকে মায়াময় অদ্ভুত মনে হয়।
স্ফটিক করুন

753

প্রশ্নটিকে গুরুত্ব সহকারে বিবেচনা করে, আমাদের খুঁজে পাওয়া উচিত যে একজন সাধারণ 6 বছর বয়সী জ্ঞানীয়ভাবে কী সক্ষম, যদিও স্বীকার করেছেন যে, জাভাস্ক্রিপ্টে আগ্রহী এমন ব্যক্তি এতটা সাধারণ নয়।

উপর শৈশব উন্নয়ন: 5 থেকে 7 বছর এটা বলেছেন:

আপনার শিশু দ্বি-পদক্ষেপের দিকনির্দেশগুলি অনুসরণ করতে সক্ষম হবে। উদাহরণস্বরূপ, আপনি যদি আপনার শিশুটিকে বলেন, "রান্নাঘরে যান এবং আমাকে একটি ট্র্যাশ ব্যাগ আনুন" তারা সেই দিকটি মনে রাখতে সক্ষম হবে।

আমরা ক্লোজারগুলি ব্যাখ্যা করতে এই উদাহরণটি ব্যবহার করতে পারি:

রান্নাঘর একটি অবসান একটি স্থানীয় পরিবর্তনশীল নামক রয়েছে trashBags। রান্নাঘরের ভিতরে একটি ফাংশন রয়েছে যা একটি getTrashBagট্র্যাশ ব্যাগ পেয়ে তা ফেরত দেয় and

আমরা এটি জাভাস্ক্রিপ্টে এর মতো কোড করতে পারি:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

ক্লোজারগুলি আকর্ষণীয় কেন তা ব্যাখ্যা করে এমন আরও পয়েন্ট:

  • প্রতিটি সময় makeKitchen()বলা হয়, একটি পৃথক পৃথক সঙ্গে একটি নতুন বন্ধকরণ তৈরি করা হয়trashBags
  • trashBagsপরিবর্তনশীল প্রতিটি রান্নাঘর ভেতরে স্থানীয় এবং না বাইরে অ্যাক্সেসযোগ্য কিন্তু উপর ভেতরের ফাংশনgetTrashBag সম্পত্তি এটিতে অ্যাক্সেস আছে।
  • প্রতিটি ফাংশন কল একটি ক্লোজার তৈরি করে, তবে বন্ধের বাইরে থেকে কল না করা যদি না কোনও অভ্যন্তরীণ ফাংশন, যা ক্লোরের অভ্যন্তরে অ্যাক্সেস করে। getTrashBagফাংশনটির সাথে অবজেক্টটি ফিরিয়ে দেওয়া এখানে এটি করে।

6
আসলে, বিভ্রান্তিকরভাবে, মেক কিচেন ফাংশন কলটি আসল বন্ধ, রান্নাঘরের বস্তুটি ফিরে আসে না।
dlaliberte

6
অন্যদের মধ্য দিয়ে আমার পথ চলার পরে আমি এই উত্তরটি কী এবং কেন বন্ধ হওয়ার বিষয়ে ব্যাখ্যা করার সবচেয়ে সহজ উপায় হিসাবে খুঁজে পেয়েছি is
চিতাবহানা

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

584

স্ট্র ম্যান

আমাকে জানতে হবে কতবার একটি বোতাম ক্লিক করা হয়েছে এবং প্রতি তৃতীয় ক্লিকে কিছু করা ...

মোটামুটি সুস্পষ্ট সমাধান

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

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

এই বিকল্পটি বিবেচনা করুন

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

এখানে কয়েকটি বিষয় লক্ষ্য করুন।

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

একটি সাধারণ এক-লাইন বন্ধ

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

প্রত্যাশিত ফাংশনের বাইরে থাকা সমস্ত ভেরিয়েবলগুলি ফাংশনটিতে পাওয়া যায় তবে তারা ফিরে ফাংশন অবজেক্টে সরাসরি উপলভ্য হয় না ...

func();  // Alerts "val"
func.a;  // Undefined

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

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

এই নাও; আপনি এখন এই আচরণটি পুরোপুরি সজ্জিত করছেন।

সম্পূর্ণ ব্লগ পোস্ট (jQuery বিবেচনা সহ)


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

40
@ জেমস আপনি স্বীকার না করলেও, তাঁর উদাহরণ (এবং পুরো পোস্ট) আমি দেখেছি অন্যতম সেরা। যদিও প্রশ্নটি আমার পক্ষে পুরানো এবং সমাধান করা হয়নি, এটি পুরোপুরি একটি +1 এর জন্য প্রাপ্য।
ই-সন্তুষ্ট

84
"আমাকে জানতে হবে কতবার একটি বোতাম ক্লিক করা হয়েছে, এবং প্রতি তৃতীয় ক্লিকে কিছু করা ..." এটি আমার দৃষ্টি আকর্ষণ করেছে। একটি ব্যবহারের কেস এবং সমাধানটি বোঝায় যে কীভাবে বন্ধ হওয়া কোনও রহস্যজনক জিনিস নয় এবং আমাদের অনেকগুলি সেগুলি লিখেছিল তবে সরকারী নামটি ঠিক জানত না।
ক্রিস 22

দুর্দান্ত উদাহরণ কারণ এটি দেখায় যে ২ য় উদাহরণে "গণনা" "গণনা" এর মান ধরে রাখে এবং প্রতিবার "উপাদান" ক্লিক করলে 0 এ পুনরায় সেট করা হয় না। খুবই তথ্যবহুল!
আদম

বন্ধের আচরণের জন্য +1 । আমরা সীমিত করতে পারেন অবসান আচরণ করার ফাংশন জাভাস্ক্রিপ্ট অথবা এই ধারণা আরো ভাষার অন্যান্য কাঠামো প্রয়োগ করা যেতে পারে?
ডিজিমিড

492

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

    var bind = function(x) {
        return function(y) { return x + y; };
    }
    
    var plus5 = bind(5);
    console.log(plus5(3));

জাভাস্ক্রিপ্ট ক্লোজার না জানলে এখানে কী হবে ? কেবলমাত্র তার পদ্ধতির বডি দ্বারা শেষ লাইনে কলটি প্রতিস্থাপন করুন (যা মূলত ফাংশন কলগুলি কী করে) এবং আপনি পান:

console.log(x + 3);

এখন, সংজ্ঞা কোথায় x? আমরা বর্তমানের স্কোপে এটি সংজ্ঞায়িত করিনি। এর একমাত্র সমাধান হ'ল তার স্কোপটি (বা বরং এর পিতামাতার স্কোপ) চারপাশে plus5 বহন করা । এইভাবে, xসংজ্ঞায়িত হয় এবং এটি মান 5 এর সাথে আবদ্ধ।


11
এটি হুবহু উদাহরণস্বরূপ যা অনেক লোককে ভেবে ভ্রান্ত করে যে এটি সেই মানগুলি যা ফেরত ফাংশনে ব্যবহৃত হয়, পরিবর্তিত পরিবর্তনশীল নিজেই নয়। যদি এটি "রিটার্ন x + = y", বা এর চেয়ে ভাল আরও এবং অন্য একটি ফাংশন "x * = y" উভয় হয়ে থাকে, তবে এটি স্পষ্ট হবে যে কোনও কিছুই অনুলিপি করা হচ্ছে না। লোকেরা ফ্রেমগুলি স্ট্যাক করে রাখার জন্য পরিবর্তে হিপ ফ্রেম ব্যবহার করে কল্পনা করুন, যা ফাংশনটি ফিরে আসার পরে অবিরত থাকতে পারে।
ম্যাট

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

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

@ ম্যাট হুম, আমি নিশ্চিত নই যে আমি আপনাকে পুরোপুরি বুঝতে পেরেছি তবে আমি দেখতে শুরু করি যে আপনার কোনও বৈধ পয়েন্ট থাকতে পারে। যেহেতু মন্তব্যগুলি খুব সংক্ষিপ্ত, তাই আপনি কি বলতে চান যা আপনি মুস্ট / প্যাসিটি বা চ্যাট রুমে বোঝাতে চেয়েছেন? ধন্যবাদ।
কনরাড রুডল্ফ

2
@ কনরাড রুডল্ফ আমার মনে হয় আমি x + = y এর উদ্দেশ্য সম্পর্কে পরিষ্কার ছিলাম না। উদ্দেশ্যটি কেবল এটি দেখানো ছিল যে প্রত্যাবর্তিত ফাংশনে বারবার কলগুলি একই ভেরিয়েবল এক্স ব্যবহার করা চালিয়ে যায় (একই মানটির বিপরীতে , যা লোকেরা কল্পনা করে যে "ফাংশনটি তৈরি করা হয়" "sertedোকানো" হয়)। এটি আপনার ফিডেলের প্রথম দুটি সতর্কতার মতো। অতিরিক্ত ফাংশন x * = y এর উদ্দেশ্য হ'ল একাধিক রিটার্ন করা ফাংশনগুলি সমস্ত একই xকে ভাগ করে।
ম্যাট

376

ঠিক আছে, 6 বছর বয়সী ক্লোজার্স ফ্যান। আপনি কি বন্ধের সহজ উদাহরণটি শুনতে চান?

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

আমি এখানে আমার বিমানের গল্পটি কীভাবে রূপান্তর করতে পারি তা এখানে।

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");


26
আসল পোস্টারটি ভালভাবে খেলেছে এবং উত্তর দেয়। আমি মনে করি এটিই সেরা উত্তর। আমি লাগেজটি একইভাবে ব্যবহার করতে যাচ্ছিলাম: কল্পনা করুন আপনি ঠাকুরমার বাড়িতে যান এবং আপনি আপনার নিন্টেন্ডো ডিএস কেসটি আপনার মামলার ভিতরে গেম কার্ডের সাহায্যে প্যাক করেন তবে তার কেসটি আপনার ব্যাকপ্যাকের ভিতরে প্যাক করে এবং আপনার ব্যাকপ্যাকের পকেটে গেম কার্ড রাখেন, এবং তারপরে আপনি পুরো জিনিসটি স্যুটকেসের পকেটে আরও গেম কার্ড সহ একটি বড় স্যুটকেসে রেখে দেন। আপনি যখন দাদীর বাড়ীতে পৌঁছবেন, বাইরের সমস্ত কেস খোলা থাকবে না আপনি যতক্ষণ না ডিএস-তে কোনও খেলা খেলতে পারবেন। বা এই প্রভাব কিছু।
slartibart ব্রেকফাস্ট

376

TLDR

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

বিস্তারিত

ECMAScript নির্দিষ্টকরণের পরিভাষায়, [[Environment]]প্রতিটি ফাংশন-অবজেক্টের রেফারেন্স দ্বারা একটি ক্লোজার প্রয়োগ করা যেতে পারে , যা ফাংশনটি সংজ্ঞায়িত করা হয়েছে এমন লেজিকাল পরিবেশের দিকে নির্দেশ করে।

অভ্যন্তরীণ [[Call]]পদ্ধতির মাধ্যমে যখন কোনও ফাংশন আহ্বান করা হয় , তখন [[Environment]]সুনির্দিষ্ট নির্মিত এক্সিকিউশন কনটেক্সট (স্ট্যাক ফ্রেম) এর পরিবেশ রেকর্ডের বাইরের পরিবেশের রেফারেন্সে ফাংশন-অবজেক্টের রেফারেন্সটি অনুলিপি করা হয় ।

নিম্নলিখিত উদাহরণে, ফাংশন fবিশ্বব্যাপী বাস্তবায়নের প্রেক্ষাপটের লেজিকাল পরিবেশের উপর বন্ধ হয়:

function f() {}

নিম্নলিখিত উদাহরণে, ফাংশন ফাংশনটির hলেজিকাল পরিবেশের উপর বন্ধ হয়ে যায় g, যা ঘুরে দেখা যায়, বৈশ্বিক বাস্তবায়ন প্রসঙ্গে লেক্সটিক পরিবেশের উপর বন্ধ হয়।

function g() {
    function h() {}
}

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

নিম্নলিখিত উদাহরণে, ফাংশন ফাংশনটির jলেজিকাল পরিবেশের উপর বন্ধ হয় i, যার অর্থ হল ভেরিয়েবলটি xভিতরের ফাংশন থেকে দৃশ্যমান j, ফাংশন iকার্যকর হওয়ার পরে দীর্ঘস্থায়ী :

function i() {
    var x = 'mochacchino'
    return function j() {
        console.log('Printing the value of x, from within function j: ', x)
    }
} 

const k = i()
setTimeout(k, 500) // invoke k (which is j) after 500ms

একটি অবসান সালে বাইরের আভিধানিক পরিবেশে ভেরিয়েবল নিজেদের পাওয়া যায়, হয় না কপি।

function l() {
  var y = 'vanilla';

  return {
    setY: function(value) {
      y = value;
    },
    logY: function(value) {
      console.log('The value of y is: ', y);
    }
  }
}

const o = l()
o.logY() // The value of y is: vanilla
o.setY('chocolate')
o.logY() // The value of y is: chocolate

বহিরাগত পরিবেশের রেফারেন্সের মাধ্যমে এক্সিকিউশন কনটেক্সটগুলির মধ্যে সংযুক্ত লেক্সিকাল এনভায়রনমেন্টগুলির শৃঙ্খলা একটি স্কোপ চেইন গঠন করে এবং কোনও প্রদত্ত ফাংশন থেকে দৃশ্যমান শনাক্তকারীকে সংজ্ঞায়িত করে।

দয়া করে নোট করুন যে স্পষ্টতা এবং নির্ভুলতার উন্নতির প্রয়াসে, এই উত্তরটি মূল থেকে যথেষ্ট পরিবর্তন করা হয়েছে।


56
বাহ, আপনি জানেন না যে আপনি স্ট্রিং বিকল্পগুলি এর console.logমতো ব্যবহার করতে পারেন । অন্য কারও যদি আগ্রহী থাকে তবে সেগুলি আরও রয়েছে: বিকাশকারী.মোজিলা.আর.ইন.ইউএস
ফ্ল্যাশ করুন

7
ফাংশনের প্যারামিটার তালিকায় থাকা ভেরিয়েবলগুলিও বন্ধের অংশ (যেমন কেবল সীমাবদ্ধ নয় var)।
থমাস এডিং

ক্লোজারগুলি আরও বেশি জিনিস এবং ক্লাস ইত্যাদির মতো শোনাচ্ছে না কেন নিশ্চিত নয় যে খুব বেশি লোক এই দুটিটির তুলনা করে না - আমাদের পক্ষে নবীনদের পক্ষে শেখা আরও সহজ হবে!
almaruf

365

এটি অন্য কয়েকটি উত্তরের মধ্যে উপস্থিত হওয়া বন্ধ সম্পর্কে বেশ কয়েকটি (সম্ভাব্য) ভুল বোঝাবুঝি পরিষ্কার করার একটি প্রচেষ্টা।

  • আপনি যখন অভ্যন্তরীণ ফাংশনটি ফিরিয়ে দেন কেবল তখনই একটি ক্লোজার তৈরি হয় না। প্রকৃতপক্ষে, ঘেরটি তৈরির কার্যটি বন্ধ হওয়ার জন্য কোনওভাবেই ফিরতে হবে না। এর পরিবর্তে আপনি আপনার অভ্যন্তরীণ ফাংশনটি কোনও বহিরাগত স্কোপের একটি ভেরিয়েবলের জন্য বরাদ্দ করতে পারেন, বা অন্য কোনও ফাংশনে যুক্তি হিসাবে এটি পাস করতে পারেন যেখানে এটি অবিলম্বে বা যে কোনও সময় বলা যেতে পারে। সুতরাং, এনক্লোজিং ফাংশনটি বন্ধ হওয়ার কারণেই সম্ভবত এনক্লোজিং ফাংশনটি বলা হয় কারণ যে কোনও অভ্যন্তরীণ ফাংশনটি যখনই অভ্যন্তরীণ ফাংশনটি ডাকা হয় তার আগে বা পরে এনকোলেসিং ফাংশনটি ফিরে আসে তখন সেই বন্ধ হওয়ার অ্যাক্সেস থাকে।
  • একটি ক্লোজার তার ক্ষেত্রের ভেরিয়েবলের পুরানো মানগুলির একটি অনুলিপি উল্লেখ করে না । ভেরিয়েবলগুলি নিজেরাই বন্ধের অংশ, এবং সুতরাং যখন এই ভেরিয়েবলগুলির মধ্যে একটিতে অ্যাক্সেস করা হয় তখন যে মানটি দেখা হয় এটি সর্বশেষতম মান at এ কারণেই লুপগুলির অভ্যন্তরীণ অভ্যন্তরীণ ক্রিয়াকলাপগুলি জটিল হতে পারে, কারণ ফাংশনটি তৈরি হওয়ার সময় বা কল করার সময় প্রত্যেকটির ভেরিয়েবলের অনুলিপিটি ধারণ করার চেয়ে একই বাহ্যিক ভেরিয়েবলের অ্যাক্সেস থাকে।
  • ক্লোজারের "ভেরিয়েবলস" এর মধ্যে ফাংশনের মধ্যে ঘোষিত কোনও নামযুক্ত ফাংশন অন্তর্ভুক্ত রয়েছে । তারা ফাংশন যুক্তি অন্তর্ভুক্ত। একটি ক্লোজারের ক্লোজারের ভেরিয়েবলগুলি রয়েছে যা বিশ্বব্যাপী সুযোগ পর্যন্ত সমস্ত ক্ষেত্রে রয়েছে access
  • ক্লোজারগুলি মেমোরি ব্যবহার করে তবে জাভাস্ক্রিপ্ট নিজেই এর নিজস্ব বিজ্ঞপ্তি কাঠামো পরিষ্কার করে যেগুলি রেফারেন্সযুক্ত নয় এগুলি মেমরি ফাঁসের কারণ নয় don't ক্লোজারগুলির সাথে জড়িত ইন্টারনেট এক্সপ্লোরার মেমরি ফাঁস তৈরি হয় যখন এটি ডিওএম বৈশিষ্ট্যের মানগুলি সংযোগ বন্ধ করতে ব্যর্থ হয়, সুতরাং এটি সম্ভবত বৃত্তাকার কাঠামোগুলির জন্য রেফারেন্স বজায় রাখে।

15
জেমস, আমি বলেছিলাম বন্ধটি কার্যকরীকরণের ডাকের সময় বন্ধটি "সম্ভবত" তৈরি করা হয়েছিল কারণ এটি প্রশংসনীয় যে কোনও বাস্তবায়ন কোনও সময়ের পরে এটি বন্ধের সৃষ্টি স্থগিত করতে পারে, যখন এটি সিদ্ধান্ত নেয় যে কোনও বন্ধকরণ একেবারে প্রয়োজন। যদি এনকোলেসিং ফাংশনে কোনও অভ্যন্তরীণ ফাংশন সংজ্ঞায়িত না করা হয়, তবে কোনও বন্ধ হওয়ার দরকার পড়বে না। সুতরাং এটি প্রথম অভ্যন্তরীণ ফাংশনটি তৈরি না হওয়া পর্যন্ত অপেক্ষা করতে পারে তারপরে ঘেরের ফাংশনটির কল প্রসঙ্গে একটি ক্লোজার তৈরি করতে।
dlaliberte

9
@ বিটরুট-বিটরুট ধরুন আমাদের একটি অভ্যন্তরীণ ফাংশন রয়েছে যা অন্য কোনও ফাংশনে চলে গেছে যেখানে এটি বাহ্যিক ফাংশন ফিরে আসার আগে ব্যবহৃত হয় , এবং মনে করুন আমরাও একই অভ্যন্তরীণ ফাংশনটি বাহ্যিক ফাংশন থেকে ফিরে আসি। এটি উভয় ক্ষেত্রে একইভাবে একই ফাংশন, তবে আপনি বলছেন যে বাহ্যিক ফাংশনটি ফিরে আসার আগে অভ্যন্তরীণ ফাংশনটি কল স্ট্যাকের সাথে "আবদ্ধ" থাকে, যেখানে এটি ফিরে আসার পরে, অভ্যন্তরীণ ফাংশনটি হঠাৎ বন্ধ হয়ে যায়। এটি উভয় ক্ষেত্রে অভিন্ন আচরণ করে; শব্দার্থবিজ্ঞানগুলি অভিন্ন, তাই আপনি কেবল বাস্তবায়নের বিশদ সম্পর্কে কথা বলছেন না?
dlaliberte

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

9
এই নিবন্ধটি পড়া কঠিন, তবে আমি মনে করি এটি আসলে আমি যা বলছি তা সমর্থন করে। এটি বলে: "একটি ফাংশন অবজেক্ট [...] ফেরত দিয়ে বা সরাসরি যেমন একটি ফাংশন অবজেক্টের জন্য একটি রেফারেন্স অর্পণ করে উদাহরণস্বরূপ, একটি গ্লোবাল ভেরিয়েবলের মাধ্যমে একটি ক্লোজার তৈরি হয়" " আমার অর্থ এই নয় যে জিসি অপ্রাসঙ্গিক। বরং জিসির কারণে, এবং কারণ অভ্যন্তরীণ ফাংশনটি বাইরের ফাংশনের কল প্রসঙ্গে (বা নিবন্ধটি বলে [[[সুযোগ]]) এর সাথে সংযুক্ত রয়েছে, তবে বাইরের ফাংশন কলটি ফিরে আসে কিনা তা বিবেচ্য নয় কারণ সেই অভ্যন্তরের সাথে আবদ্ধ ফাংশন গুরুত্বপূর্ণ জিনিস।
dlaliberte

3
দুর্দান্ত উত্তর! আপনার যুক্ত করা উচিত একটি বিষয় হ'ল সমস্ত ফাংশনগুলি নির্বাহক স্কোপের পুরো বিষয়বস্তুর উপরে যা তারা সংজ্ঞায়িত হয়। তারা প্যারেন্ট স্কোপ থেকে কিছু বা কোনও ভেরিয়েবলকে রেফার করে কিনা তা বিবেচ্য নয়: প্যারেন্ট স্কোপের লেজিকাল পরিবেশের একটি রেফারেন্স নিঃশর্তভাবে [[স্কোপ]] হিসাবে সংরক্ষণ করা হয়। ইসিএমএ অনুচ্ছেদে ফাংশন তৈরির বিভাগ থেকে এটি দেখা যায়।
আসাদ সা Saeedদুদ্দিন

236

ক্লোজারগুলি ব্যাখ্যা করে কিছুক্ষণ আগে আমি একটি ব্লগ পোস্ট লিখেছিলাম। আপনি কেন চান তা শর্তে ক্লোজার সম্পর্কে আমি যা বলেছিলাম তা এখানে ।

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

সেই অর্থে, তারা কোনও ফাংশনটিকে ব্যক্তিগত বৈশিষ্ট্যযুক্ত কোনও বস্তুর মতো কিছুটা কাজ করতে দেয়।

সম্পূর্ণ পোস্ট:

তাহলে এই ক্লোজার জিনিসগুলি কী?


তাহলে কি ক্লোজারের মূল সুবিধাটি এই উদাহরণ দিয়ে জোর দেওয়া যেতে পারে? বলুন যে আমার একটি ফাংশন ইমেল রয়েছে (সেন্ডটো টোএড্রেস, ত্রুটিবিহীন) আমি তখন বলতে পারি devError = emailError("devinrhode2@googmail.com", errorString)এবং তারপরে একটি ভাগ করা ইমেল এরর ফাংশনের নিজস্ব নিজস্ব সংস্করণ থাকতে পারি?
ডেভিন জি রোড

এই ব্যাখ্যা এবং সম্পর্কিত সংযোগের নিখুঁত উদাহরণ (ক্লোজার টমেসিস) ক্লোজারগুলি বোঝার সেরা উপায় এবং শীর্ষে থাকা উচিত!
হোপকিং

215

বন্ধ সহজ:

নিম্নলিখিত সহজ উদাহরণটি জাভাস্ক্রিপ্ট বন্ধের সমস্ত প্রধান পয়েন্টকে coversেকে রেখেছে। *  

এখানে এমন একটি কারখানা রয়েছে যা ক্যালকুলেটর তৈরি করে যা যুক্ত করতে এবং গুণ করতে পারে:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

মূল বক্তব্য: প্রতিটি কল make_calculatorএকটি নতুন স্থানীয় ভেরিয়েবল তৈরি করে n, যা সেই ক্যালকুলেটর দ্বারা ব্যবহারের জন্য অব্যাহত থাকে addএবং রিটার্নের multiplyঅনেক পরে কাজ করে make_calculator

আপনি যদি স্ট্যাক ফ্রেমগুলির সাথে পরিচিত হন তবে এই ক্যালকুলেটরগুলি অদ্ভুত বলে মনে হয়: তারা কীভাবে nপরে অ্যাক্সেস রাখতে পারেmake_calculator রিটার্নের ? উত্তরটি কল্পনা করা যায় যে জাভাস্ক্রিপ্টটি "স্ট্যাক ফ্রেম" ব্যবহার করে না, পরিবর্তে "হিপ ফ্রেম" ব্যবহার করে, যা ফাংশন কলের পরেও তাদের ফিরিয়ে আনতে পারে।

বাইরের ফাংশন ** এ ঘোষিত অ্যাক্সেস ভেরিয়েবলগুলি addএবং এর মতো অভ্যন্তরীণ ফাংশনগুলিকে ক্লোজার বলা হয় ।multiply

এটি ক্লোসারের কাছে প্রায় অনেক কিছুই।



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

** যে কোনও বাহ্যিক ক্রিয়াকলাপ, যদি বেশ কয়েকটি বাসা বেঁধে দেওয়া হয়, বা এমনকি বৈশ্বিক প্রেক্ষাপটে, যেমন এই উত্তরটি পরিষ্কারভাবে উল্লেখ করেছে।


আপনি যদি কল করেন তবে কী হবে: দ্বিতীয়_ক্যালকুলেটর = প্রথম_ক্যালকুলেটর (); সেকেন্ড_ক্যালকুলেটারের পরিবর্তে = মেক_ক্যালকুলেটর (); ? একই হওয়া উচিত, তাই না?
রোনেন ফেস্টিংগার

4
@ রোনেন: যেহেতু first_calculatorএকটি অবজেক্ট (কোনও ফাংশন নয়) আপনার মধ্যে প্রথম বন্ধনী ব্যবহার করা উচিত নয় second_calculator = first_calculator;, কারণ এটি একটি অ্যাসাইনমেন্ট, কোনও ফাংশন কল নয়। আপনার প্রশ্নের উত্তর দেওয়ার জন্য, কেবলমাত্র মেক_ক্যালকুলেটরটিতে কেবল একটি কল থাকবে, সুতরাং কেবল একটি ক্যালকুলেটর তৈরি হবে এবং ভেরিয়েবলগুলি প্রথম_ক্যালকুলেটর এবং দ্বিতীয়_ক্যালকুলেটর উভয়ই একই ক্যালকুলেটরকে উল্লেখ করবে, সুতরাং উত্তরগুলি 3, 403, 4433, 44330 হবে।
ম্যাট

204

আমি কীভাবে এটি ছয় বছরের এক বৃদ্ধকে ব্যাখ্যা করব:

আপনি কি জানেন যে বড়রা কীভাবে কোনও বাড়ির মালিক হতে পারে এবং তারা এটিকে বাড়ি বলে? যখন একটি মায়ের একটি সন্তান থাকে, শিশু সত্যিকার অর্থে কোনও কিছুই মালিক করে না, তাই না? তবে এর বাবা-মা একটি বাড়ির মালিক, তাই যখনই কেউ শিশুটিকে "আপনার বাড়ি কোথায়?" জিজ্ঞাসা করেন, তখন সে "সেই বাড়িটি!" উত্তর দিতে পারে এবং তার পিতামাতার বাড়ির দিকে নির্দেশ করে। একটি "ক্লোজার" হ'ল সন্তানের সর্বদা (বিদেশে হলেও) এটির একটি বাড়ি আছে বলতে সক্ষম হবার ক্ষমতা, যদিও এটি সত্যিকার অর্থে বাড়িটির মালিক।


200

আপনি কি 5 বছরের বৃদ্ধের ক্লোজারটি ব্যাখ্যা করতে পারেন? *

আমি এখনও মনে করি গুগলের ব্যাখ্যাটি খুব ভালভাবে কাজ করে এবং সংক্ষিপ্ত:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

প্রমান যে এই উদাহরণটি অভ্যন্তরীণ ফাংশনটি ফিরে না আসলেও বন্ধ করে দেয়

* এসি # প্রশ্ন


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

6
@ সাইকিত না, মস ভুল। এটি যেভাবে নির্ধারণ করা হয়েছে সেই ফাংশনটি তার বাইরে চলে যায় কিনা তা বিবেচনা না করেই একটি ক্লোজার তৈরি করা হয় এবং পিতামাতার বর্ণবাদী পরিবেশের একটি নিঃশর্তভাবে তৈরি রেফারেন্স পিতা-মাতার সুযোগে সমস্ত ভেরিয়েবলগুলি সমস্ত ফাংশনের জন্য উপলভ্য করে তোলে, নির্বিশেষে তারা বাইরে বা অভ্যন্তরীণ হয়ে থাকে of তারা যে সুযোগে তৈরি হয়েছিল।
আসাদ সাইদুদ্দিন

176

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

বন্ধ সঠিকভাবে সম্পন্ন:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index in arr) {
    console.log(arr[index]());
}
  • উপরের কোডে createClosure(n) কোডটিতে লুপের প্রতিটি পুনরাবৃত্তিতে অনুরোধ করা হয়। নোট করুন যে আমি ভেরিয়েবলটির নাম nহাইলাইট করার জন্য রেখেছি যে এটি একটি নতুন ফাংশন স্কোপ-এ তৈরি নতুন ভেরিয়েবল indexএবং বাহ্যিক স্কোপের সাথে আবদ্ধ একই ভেরিয়েবল নয় ।

  • এটি একটি নতুন সুযোগ তৈরি করে এবং nসেই সুযোগে আবদ্ধ; এর অর্থ আমাদের কাছে 10 টি পৃথক স্কোপ রয়েছে, প্রতিটি পুনরাবৃত্তির জন্য একটি।

  • createClosure(n) এমন একটি ফাংশন প্রদান করে যা সেই সুযোগের মধ্য দিয়ে এন দেয়।

  • প্রতিটি স্কোপের মধ্যেই nযা যা মান ছিল তার কাছে আবদ্ধ থাকে createClosure(n)যাতে নেস্ট করা ফাংশন যা ফিরে আসে সর্বদা এর মান ফিরিয়ে দেয়n এটি ছিল যখন createClosure(n)চালানো হয়েছিল।

বন্ধগুলি ভুল করেছে:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index in badArr) {
    console.log(badArr[index]());
}
  • উপরের কোডে লুপটি createClosureArray()ফাংশনের মধ্যে সরিয়ে নেওয়া হয়েছিল এবং ফাংশনটি কেবলমাত্র সম্পন্ন অ্যারেটি দেয়, যা প্রথম নজরে আরও স্বজ্ঞাত বলে মনে হয়।

  • যা সুস্পষ্ট নাও হতে পারে তা হ'ল সেই থেকে createClosureArray() লুপের প্রতিটি পুনরাবৃত্তির পরিবর্তে এই ফাংশনের জন্য কেবল একবার একটি সুযোগ তৈরি করা হয় কেবল তখনই তা চাওয়া হয়।

  • এই ফাংশনটির মধ্যে একটি ভেরিয়েবল নামের indexসংজ্ঞা দেওয়া হয়। লুপটি চলে এবং অ্যারেতে ফাংশন যুক্ত করে যা ফিরে আসে index। নোটটি ফাংশনটির indexমধ্যে সংজ্ঞায়িত করা হয় createClosureArrayযা কেবলমাত্র একবারে প্রার্থনা করে।

  • কারণ createClosureArray()ফাংশনটির মধ্যে কেবল একটি সুযোগ ছিল, কেবলমাত্র সেই সুযোগের মধ্যে indexএকটি মানের কাছে আবদ্ধ। অন্য কথায়, প্রতিটি সময় লুপের মান পরিবর্তন করে index, এটি সেই সুযোগের মধ্যে এটি উল্লেখ করে এমন প্রতিটি কিছুর জন্য এটি পরিবর্তন করে।

  • অ্যারেতে যুক্ত সমস্ত ফাংশন indexপ্যারেন্ট স্কোপ থেকে একই ভেরিয়েবলটি ফেরত দেয় যেখানে এটি প্রথম উদাহরণের মতো 10 টি বিভিন্ন স্কোপের চেয়ে 10 টির পরিবর্তে সংজ্ঞায়িত হয়েছিল। শেষ ফলাফলটি হ'ল সমস্ত 10 ফাংশন একই স্কোপ থেকে একই পরিবর্তনশীল ফেরত দেয়।

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

ফলাফল

ক্লোজস ডোন রাইট
এন = 0
এন = 1
এন = 2
এন = 3
এন = 4
এন = 5
এন = 6
এন = 7
এন = 8
এন = 9

ক্লোজারের কাজটি ভুল হয়েছে
এন = 10
এন = 10
এন = 10
এন = 10
এন = 10
এন = 10
এন = 10
এন = 10
এন = 10
এন = 10


1
ভাল সংযোজন, ধন্যবাদ। এটি আরও পরিষ্কার করার জন্য আপনি কল্পনা করতে পারেন যে প্রতিটি পুনরাবৃত্তির সাথে "খারাপ" লুপটিতে কীভাবে "খারাপ" অ্যারে তৈরি করা হয়: 1 ম পুনরাবৃত্তি: [ফাংশন () {রিটার্ন 'এন =' + 0;;] ২ য় পুনরাবৃত্তি: [( ফাংশন () {রিটার্ন 'এন =' + 1;}), (ফাংশন () {রিটার্ন 'এন =' + 1;})] তৃতীয় পুনরাবৃত্তি: [(ফাংশন () {রিটার্ন 'এন =' + 2;}) , (ফাংশন () {রিটার্ন 'এন =' + 2;}), (ফাংশন () {রিটার্ন 'এন =' + 2;})] ইত্যাদি। সুতরাং, যখন প্রতিটি সূচকের মান পরিবর্তন হয় তখন এটি সমস্ত ফাংশনে প্রতিফলিত হয় ইতিমধ্যে অ্যারে যোগ করা হয়েছে।
অ্যালেক্স আলেভিভ

3
পার্থক্য সংশোধন করার letজন্য ব্যবহার var
রূপম দত্ত

এখানে কি "ক্লোজার ডান হয়ে গেছে" "ক্লোজার ইন ক্লোজার" এর উদাহরণ নয়?
টেকনিক্যালস্মাইল

আমার অর্থ, প্রতিটি ফাংশন প্রযুক্তিগতভাবে একটি বন্ধ তবে গুরুত্বপূর্ণ অংশটি হ'ল ফাংশনটির মধ্যে একটি নতুন ভেরিয়েবলের সংজ্ঞা দেওয়া হয়। যে ফাংশনটি রিটার্ন পায় কেবলমাত্র nএকটি নতুন বন্ধে তৈরি রেফারেন্স । আমরা কেবল একটি ফাংশন ফিরিয়েছি যাতে আমরা এটিকে অ্যারেতে সঞ্চয় করতে পারি এবং এটির পরে অনুরোধ করতে পারি।
শেভ

আপনি শুধু প্রথম পুনরাবৃত্তির অ্যারের মধ্যে ফলাফলের সঞ্চয় করতে চান, তাহলে আপনি ভালো এটা ইনলাইন পারে: arr[index] = (function (n) { return 'n = ' + n; })(index);। তবে তারপরে আপনি ফলশ্রুতিটি স্ট্রিংটি অ্যারের মধ্যে সংরক্ষণ করছেন যা আমার উদাহরণের বিন্দুটি হারাতে চেয়েছিল এমন কোনও ক্রিয়াকলাপের চেয়ে।
শেভ

164

ক্লোজারে উইকিপিডিয়া :

কম্পিউটার বিজ্ঞানে, একটি ক্লোজার হল সেই ফাংশনটির ননলোকাল নামগুলি (ফ্রি ভেরিয়েবল) এর জন্য একটি রেফারেন্সিং পরিবেশের সাথে একটি ফাংশন।

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

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

বন্ধগুলি প্রায়শই কিছু লুকানো ব্যক্তিগত ডেটা দিয়ে ফাংশন তৈরি করতে ব্যবহৃত হয় (তবে এটি সবসময় হয় না)।

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

EMS

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


2
এটি জাভাস্ক্রিপ্ট বন্ধের জন্য সেরা ব্যাখ্যা। নির্বাচিত উত্তর হওয়া উচিত। বাকিগুলি যথেষ্ট বিনোদনমূলক তবে এটি বাস্তব-বাস্তব জাভাস্ক্রিপ্ট কোডারদের জন্য ব্যবহারিক উপায়ে কার্যকর।
জিওএডসিক

136

ক্লোজারগুলি কীভাবে কাজ করে তা ব্যাখ্যা করার জন্য আমি একটি ইন্টারেক্টিভ জাভাস্ক্রিপ্ট টিউটোরিয়াল একসাথে রেখেছি। একটি বন্ধ কি?

এখানে উদাহরণগুলির মধ্যে একটি:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here

128

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

জাভাস্ক্রিপ্ট ফাংশনগুলির গোপনীয়তাগুলি হ'ল ব্যক্তিগত ভেরিয়েবল

var parent = function() {
 var name = "Mary"; // secret
}

যতবার আপনি এটি কল করবেন, স্থানীয় পরিবর্তনশীল "নাম" তৈরি করা হবে এবং নাম দেওয়া হয়েছে "মেরি"। এবং প্রতিবার ফাংশনটি প্রস্থান করলে ভেরিয়েবলটি হারিয়ে যায় এবং নামটি ভুলে যায়।

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

তবে, জাভাস্ক্রিপ্টে এই খুব বিশেষ জিনিস রয়েছে যা অন্যান্য ফাংশনের অভ্যন্তরে তৈরি করা ফাংশনগুলি তাদের পিতামাতার স্থানীয় পরিবর্তনগুলিও জানতে পারে এবং যতক্ষণ বেঁচে থাকে ততক্ষণ তাদের রাখতে পারে keep

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

সুতরাং, যতক্ষণ আমরা পিতা-মাতার ফাংশনে আছি ততক্ষণ এটি এক বা একাধিক শিশু ফাংশন তৈরি করতে পারে যা গোপন স্থান থেকে গোপন পরিবর্তনগুলি ভাগ করে share

তবে দুঃখের বিষয় হ'ল, যদি শিশুটিও তার পিতামাতার ফাংশনের একটি ব্যক্তিগত পরিবর্তনশীল হয়, তবে বাবা-মা শেষ হলে এটি মারা যায় এবং গোপনীয়তাগুলি তাদের সাথে মারা যায়।

তাই বাঁচতে বাচ্চাকে অনেক দেরি করার আগে চলে যেতে হবে

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

এবং এখন, যদিও মেরি "আর চলছেন না", তবুও তার স্মৃতি হারিয়ে যায় না এবং তার শিশুটি সর্বদা তার নাম এবং তাদের গোপনীয়তার সাথে একসাথে তাদের ভাগ করে নেওয়া অন্যান্য গোপন কথা স্মরণ করবে।

সুতরাং, আপনি যদি শিশুটিকে "অ্যালিস" ডাকেন তবে সে প্রতিক্রিয়া জানাবে

child("Alice") => "My name is Alice, child of Mary"

এটাই বলার আছে।


15
এটি সেই ব্যাখ্যা যা আমার কাছে সর্বাধিক উপলব্ধি করেছিল কারণ এটি প্রযুক্তিগত শর্তাদির উল্লেখযোগ্য পূর্ববর্তী জ্ঞান গ্রহণ করে না। এখানে শীর্ষ ভোটের ব্যাখ্যাটি ধরে নিয়েছে যে যে ব্যক্তি ক্লোজারগুলি বুঝতে পারে না তার মধ্যে 'লেক্সিকাল স্কোপ' এবং 'এক্সিকিউশন প্রসঙ্গ' এর মতো পদগুলির একটি সম্পূর্ণ এবং সম্পূর্ণ বোঝা আছে - যদিও আমি এই ধারণাগতভাবে বুঝতে পারি, আমি মনে করি না আমি হিসাবে আছি আমার যেমন হওয়া উচিত সেগুলির বিবরণে স্বাচ্ছন্দ্যবোধ করা এবং এতে কোনও জারগোন না দিয়ে ব্যাখ্যা হ'ল অবশেষে আমার জন্য ক্লিক করুন, আপনাকে ধন্যবাদ। একটি বোনাস হিসাবে, আমি মনে করি এটি কী স্কোপটি খুব সংক্ষিপ্তভাবে তা ব্যাখ্যা করে।
এমা W

103

উত্তরগুলি কেন এখানে এত জটিল তা আমি বুঝতে পারি না।

এখানে একটি বন্ধ রয়েছে:

var a = 42;

function b() { return a; }

হ্যাঁ. আপনি সম্ভবত দিনে বহুবার এটি ব্যবহার করেন।


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

এখন এটি আপনাকে যা করতে দেয় তা আরও দর্শনীয় হতে পারে, অন্যান্য উত্তর দেখুন।


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

1
হুবহু যা যা বলেছিল। অবশেষে ক্লোজারগুলি কাটাবার আগে আমার ব্যবহারিক উদাহরণ খুঁজে পেতে খুব কষ্ট হয়েছিল। হ্যাঁ, ফ্লরিবোন একটি বন্ধন তৈরি করেছিল, তবে আমাকে অশিক্ষিত করার জন্য এটি আমাকে একেবারে কিছুই শেখাত না।
শেভ

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

91

Dlaliberte দ্বারা প্রথম পয়েন্ট উদাহরণস্বরূপ:

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

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);

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

88

একটি সমাপনি যেখানে কোনও অভ্যন্তরীণ ফাংশনটির বাহ্যিক ক্রিয়ায় ভেরিয়েবলের অ্যাক্সেস থাকে। এটি সম্ভবত বন্ধগুলির জন্য আপনি পেতে পারেন সবচেয়ে সহজ এক-লাইন ব্যাখ্যা।


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

22
প্রকৃতপক্ষে, এটি অভ্যন্তরীণ ফাংশনের জন্য উপলব্ধ বাইরের ফাংশনের পুরানো মান নয় , তবে পুরানো ভেরিয়েবলগুলি , যা কিছু ফাংশন পরিবর্তন করতে সক্ষম হলে নতুন মান থাকতে পারে।
dlaliberte

86

আমি জানি ইতিমধ্যে প্রচুর সমাধান রয়েছে, তবে আমি অনুমান করি যে এই ছোট এবং সাধারণ লিপিটি ধারণাটি প্রদর্শনের জন্য কার্যকর হতে পারে:

// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined

82

আপনি ঘুমিয়ে আছেন এবং আপনি ড্যানকে আমন্ত্রণ জানিয়েছেন। আপনি ড্যানকে একটি এক্সবক্স নিয়ামক আনতে বলছেন।

ড্যান পলকে আমন্ত্রণ জানায়। ড্যান পলকে একজন নিয়ামক আনতে বলেছে। পার্টিতে কয়জন কন্ট্রোলার আনা হয়েছিল?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

80

লেখক বন্ধ চমত্কার বন্ধ ব্যাখ্যা করেছেন, কারণ ব্যাখ্যা কেন আমরা তাদের প্রয়োজন এবং LexicalEnvironment যা বোঝার বন্ধ করা প্রয়োজন ব্যাখ্যা।
এখানে সংক্ষিপ্তসার:

যদি কোনও ভেরিয়েবল অ্যাক্সেস করা হয় তবে তা স্থানীয় নয়? এখানকার মত:

এখানে চিত্র বিবরণ লিখুন

এই ক্ষেত্রে, দোভাষী বাইরের মধ্যে পরিবর্তনশীল সন্ধান করে LexicalEnvironment অবজেক্টে ।

প্রক্রিয়া দুটি পদক্ষেপ নিয়ে গঠিত:

  1. প্রথমত, যখন একটি ফাংশন এফ তৈরি করা হয়, এটি খালি জায়গায় তৈরি করা হয় না। একটি বর্তমান লেক্সিকাল এনভায়রনমেন্ট অবজেক্ট রয়েছে। উপরের ক্ষেত্রে এটি উইন্ডো (ফাংশন তৈরির সময় একটি অপরিজ্ঞাত)।

এখানে চিত্র বিবরণ লিখুন

যখন কোনও ফাংশন তৈরি করা হয়, তখন এটি [[স্কোপ]] নামে একটি গোপন সম্পত্তি পায় যা বর্তমান লেক্সিক্যাল এনভায়রনমেন্টের উল্লেখ করে।

এখানে চিত্র বিবরণ লিখুন

যদি কোনও ভেরিয়েবল পাঠ করা হয় তবে কোথাও খুঁজে পাওয়া যায় না, ত্রুটি উত্পন্ন হয়।

নেস্টেড ফাংশন

ফাংশনগুলি একে অপরের অভ্যন্তরে বাসা বাঁধতে পারে, যা লেক্সিক্যাল এনভায়রনমেন্টগুলির একটি শৃঙ্খলা তৈরি করে যা স্কোপ চেইনও বলা যেতে পারে।

এখানে চিত্র বিবরণ লিখুন

সুতরাং, ফাংশন g এর g, a এবং f এ অ্যাক্সেস রয়েছে।

বন্ধ

বাইরের ফাংশন শেষ হওয়ার পরে একটি নেস্টেড ফাংশনটি চলতে থাকবে:

এখানে চিত্র বিবরণ লিখুন

লেক্সিকাল পরিবেশগুলি চিহ্নিত করা:

এখানে চিত্র বিবরণ লিখুন

যেমনটি আমরা দেখছি, this.say যে ব্যবহারকারীর অবজেক্টের মধ্যে একটি সম্পত্তি, তাই এটি ব্যবহারকারী সম্পূর্ণ হওয়ার পরেও চলতে থাকবে।

এবং যদি আপনি মনে রাখেন, কখন this.sayতৈরি হয়, এটি (প্রতিটি ফাংশন হিসাবে) একটি অভ্যন্তরীণ রেফারেন্স পায়this.say.[[Scope]] রাখেন বর্তমান লেক্সিক্যাল এনভায়রনমেন্টের । সুতরাং, বর্তমান ব্যবহারকারীর প্রয়োগের লেক্সিক্যাল এনভায়রনমেন্ট স্মৃতিতে থেকে যায়। ব্যবহারকারীর সমস্ত ভেরিয়েবলগুলিও এর বৈশিষ্ট্য, তাই এগুলিও যত্ন সহকারে রাখা হয়, সাধারণভাবে জঙ্ক করা হয় না।

পুরো বিষয়টিটি নিশ্চিত করা হয় যে ভবিষ্যতে যদি অভ্যন্তরীণ ফাংশনটি কোনও বাহ্যিক ভেরিয়েবল অ্যাক্সেস করতে চায় তবে তা করতে সক্ষম।

সংক্ষেপ:

  1. অভ্যন্তরীণ ফাংশন বহিরাগত লেক্সিক্যাল এনভায়রনমেন্টের একটি রেফারেন্স রাখে।
  2. বাইরের ফাংশন শেষ হয়ে গেলেও অভ্যন্তরীণ ফাংশন যে কোনও সময় এ থেকে পরিবর্তনশীল অ্যাক্সেস করতে পারে।
  3. কোনও অভ্যন্তরীণ ফাংশন যা উল্লেখ না করে ব্রাউজারটি লেক্সিকাল এনভায়রনমেন্ট এবং তার সমস্ত বৈশিষ্ট্য (পরিবর্তনশীল) মেমরিতে রাখে।

একে ক্লোজার বলা হয়।


78

জাভাস্ক্রিপ্ট ফাংশনগুলি এগুলি অ্যাক্সেস করতে পারে:

  1. যুক্তি
  2. স্থানীয় (এটি তাদের স্থানীয় ভেরিয়েবল এবং স্থানীয় ফাংশন)
  3. পরিবেশ, যা অন্তর্ভুক্ত:
    • গ্লোবালগুলি, ডিওএম সহ
    • বাইরের কাজগুলিতে কিছু

যদি কোনও ফাংশন তার পরিবেশ ব্যবহার করে তবে ফাংশনটি একটি বন্ধ closure

নোট করুন বাহ্যিক ক্রিয়াকলাপগুলি প্রয়োজনীয় নয়, যদিও তারা এখানে সুবিধার প্রস্তাব না করে benefits এর পরিবেশে ডেটা অ্যাক্সেস করার মাধ্যমে, একটি ক্লোজার সেই ডেটাটিকে জীবিত রাখে। বাহ্যিক / অভ্যন্তরীণ ফাংশনগুলির সাবকাসে, একটি বহিরাগত ফাংশন স্থানীয় তথ্য তৈরি করতে পারে এবং শেষ পর্যন্ত প্রস্থান করতে পারে এবং তবুও, যদি কোনও অভ্যন্তরীণ ফাংশন (গুলি) বাহ্যিক ক্রিয়াটি বেরিয়ে যাওয়ার পরে বেঁচে থাকে তবে অভ্যন্তরীণ ফাংশনগুলি বাহ্যিক ফাংশনের স্থানীয় ডেটা রাখে জীবিত।

বিশ্বব্যাপী পরিবেশ ব্যবহার করে এমন একটি বন্ধের উদাহরণ:

কল্পনা করুন যে স্ট্যাক ওভারফ্লো ভোট এবং আপ এবং ভোট-ডাউন বোতাম ইভেন্টগুলি ক্লোজার, ভোটউপ_ক্লিক এবং ভোটডাউন_ক্লিক হিসাবে প্রয়োগ করা হয়েছে, যেগুলি বহিরাগত ভেরিয়েবলগুলি আইভোটডআপ এবং আইসোভোটডাউন অ্যাক্সেস পেয়েছে যা বিশ্বব্যাপী সংজ্ঞায়িত হয়েছে। (সরলতার স্বার্থে, আমি স্ট্যাকওভারফ্লো এর প্রশ্নোত্তর ভোট বোতামগুলি উল্লেখ করছি, উত্তর ভোট বোতামগুলির অ্যারে নয়))

যখন ব্যবহারকারী ভোটআপ বোতামটি ক্লিক করে, তখন ভোটআউপি_ক্লিক ফাংশনটি আইভডডাউন == সত্য কিনা তা নিরূপণ করতে নিছক ভোট দেওয়া বা নিছক ভোট বাতিল করতে হবে কিনা তা পরীক্ষা করে। ফাংশন votUp_click একটি বন্ধ কারণ এটি এর পরিবেশে অ্যাক্সেস করছে।

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

এগুলি চারটি ফাংশনই ক্লোজার হ'ল এগুলি সমস্ত তাদের পরিবেশে অ্যাক্সেস করে।


59

একজন old বছরের বাচ্চা হিসাবে, বর্তমানে অল্প বয়স্ক শিশুদের পড়াচ্ছেন (এবং কোনও আপেক্ষিক নবাগত আনুষ্ঠানিক শিক্ষার সাথে কোডিং করার জন্য যাতে সংশোধন করা দরকার), আমি মনে করি পাঠটি হ্যান্ড-অন খেলার মাধ্যমে সবচেয়ে ভাল হবে। যদি 6-বছর বয়সের শিশুটি বন্ধ কী তা বোঝার জন্য প্রস্তুত হয়, তবে তারা নিজেরাই যাওয়ার মতো বয়স্ক old আমি কোডটি jsfiddle.net এ আটকানোর পরামর্শ দিচ্ছি, কিছুটা ব্যাখ্যা করে এবং এগুলিকে একা রেখে একটি অনন্য গানের কথা বলি। নীচের বর্ণনামূলক পাঠ্যটি সম্ভবত 10 বছরের পুরানোটির জন্য আরও উপযুক্ত।

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

নির্দেশাবলীর

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

কোড: উপরের সমস্ত লেখাকে কোড বলা হয় । এটি জাভাস্ক্রিপ্ট লিখিত হয়।

জাভাস্ক্রিপ্ট: জাভাস্ক্রিপ্ট একটি ভাষা। ইংরেজি বা ফ্রেঞ্চ বা চাইনিজ ভাষার মতো। কম্পিউটার এবং অন্যান্য ইলেকট্রনিক প্রসেসরের দ্বারা বোঝা যায় এমন প্রচুর ভাষা রয়েছে। জাভাস্ক্রিপ্ট একটি কম্পিউটার দ্বারা বোঝার জন্য এটি একটি দোভাষী প্রয়োজন। ভাবুন যে কোনও শিক্ষক যিনি কেবল রাশিয়ান ভাষায় কথা বলছেন তিনি যদি স্কুলে আপনার ক্লাসটি পড়ানোর জন্য আসেন। শিক্ষক "все садятся" বললে, ক্লাসটি বুঝতে পারে না। তবে ভাগ্যক্রমে আপনার ক্লাসে একজন রাশিয়ান শিক্ষার্থী রয়েছে যিনি সবাইকে এর অর্থ "সবাই বসি" - তাই আপনি সকলেই করেন। ক্লাসটি কম্পিউটারের মতো এবং রাশিয়ান শিক্ষার্থী দোভাষী হয়। জাভাস্ক্রিপ্টের জন্য সর্বাধিক সাধারণ দোভাষীকে ব্রাউজার বলা হয়।

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

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

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

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

একটি ফাংশনের সাধারণত একটি নাম, প্রথম বন্ধনী এবং ধনুর্বন্ধনী থাকে। এটার মত:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

নোট করুন /*...*/এবং //ব্রাউজার দ্বারা পড়া স্টপ কোড।

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

প্যারেন্টিস: "পেরেন্টিহেসিস" বা ()কারখানায় তথ্যের প্যাকেট প্রেরণের জন্য জাভাস্ক্রিপ্ট ফাংশন কারখানার দরজায় লেটার বক্স বা রাস্তায় একটি পোস্ট বাক্স। কখনও কখনও পোস্টবক্স উদাহরণস্বরূপ চিহ্নিত হতে পারে, এক্ষেত্রে cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime)আপনি কী ডেটা আপনাকে দিতে হবে তা আপনি জানেন।

ব্র্যাকস: "ধনুর্বন্ধনী" যা দেখতে দেখতে {}আমাদের কারখানার রঙিন উইন্ডো। কারখানার অভ্যন্তর থেকে আপনি দেখতে পাচ্ছেন তবে বাইরে থেকে আপনি দেখতে পাচ্ছেন না।

দীর্ঘ কোডটি উপরে উদাহরণ

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

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

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

এখন, ফাংশনটি গাওয়ার পরে () , কোডের শেষের কাছে লাইন

var person="an old lady";

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

বিশ্বব্যাপী পরিবর্তনশীল: ব্যক্তি , একটি বিশ্বব্যাপী পরিবর্তনশীল, যার অর্থ যে আপনি যদি থেকে "একটি পুরানো লেডি" "একটি যুবক" তার মান পরিবর্তন করেন, ব্যক্তি যতক্ষণ না আপনি এটিকে পুনরায় পরিবর্তন করার সিদ্ধান্ত নেন এক যুবকের হচ্ছে রাখা এবং করবে অন্য কোন ফাংশন কোড দেখতে পাবে যে এটি একজন যুবক। প্রেস F12বোতাম বা বিকল্পগুলি সেটিংস তাকান ব্রাউজারের বিকাশকারী কনসোলের খুলুন এবং "ব্যক্তি" টাইপ তা দেখতে এই মান প্রত্যাবর্তন করতে হবে। টাইপ করুন person="a young man"আবার দেখতে এটি পরিবর্তিত হয়েছে এটিকে পরিবর্তন করতে এবং তারপর টাইপ করুন "ব্যক্তি"।

এই পরে আমাদের লাইন আছে

sing(person);

এই লাইনটি ফাংশনটিকে কল করছে, যেন এটি কোনও কুকুরকে ডাকছে

"আসুন গান করুন , আসুন এবং ব্যক্তি পান !"

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

ফাংশনগুলি ক্রিয়া সংজ্ঞায়িত করে - মূল ফাংশনটি গাওয়া সম্পর্কে। এটিতে ফার্স্ট পার্ট নামে একটি পরিবর্তনশীল রয়েছে যা সেই ব্যক্তির সম্পর্কে গাওয়ার ক্ষেত্রে প্রযোজ্য যা গানের প্রতিটি শ্লোককে প্রয়োগ করে: "সেখানে" + ব্যক্তি + "যিনি গিলেন"। আপনি যদি কনসোলে ফার্স্ট পার্ট টাইপ করেন তবে আপনি কোনও উত্তর পাবেন না কারণ ভেরিয়েবলটি কোনও ফাংশনে লক করা আছে - ব্রাউজারটি ধনুর্বন্ধনীগুলির রঙিন উইন্ডোর ভিতরে দেখতে পাবে না।

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

ক্লোজার্সগুলি সমস্তই জানে যে ফার্স্ট পার্ট নামে পরিচিত গাওয়ার () ফাংশনের ভেরিয়েবল কী, কারণ তারা তাদের রঙিন উইন্ডো থেকে দেখতে পাবে।

বন্ধ হওয়ার পরে লাইনে আসে

fly();
spider();
bird();
cat();

গানের () ফাংশনটি এই ক্রিয়াকলাপগুলির প্রত্যেককে তাদের দেওয়া ক্রমে কল করবে। তারপরে গান () ফাংশনের কাজ হয়ে যাবে।


56

ঠিক আছে, 6 বছর বয়সী সন্তানের সাথে কথা বলছি, আমি সম্ভবত নিম্নলিখিত সংস্থানগুলি ব্যবহার করব।

ভাবুন - আপনি পুরো বাড়িতে আপনার ছোট ভাই-বোনদের সাথে খেলছেন, এবং আপনি আপনার খেলনাগুলি নিয়ে ঘুরে বেড়াচ্ছেন এবং তাদের কয়েকটিকে আপনার বড় ভাইয়ের ঘরে নিয়ে এসেছেন। কিছুক্ষণ পরে আপনার ভাই স্কুল থেকে ফিরে তার ঘরে গেলেন এবং সে এটির ভিতরে তালাবদ্ধ হয়ে গেছে, সুতরাং এখন আপনি সরাসরি খেলনাগুলিতে আর প্রবেশ করতে পারবেন না। তবে আপনি দরজাটি কড়াতে পারেন এবং আপনার ভাইকে সেই খেলনাগুলির জন্য জিজ্ঞাসা করতে পারেন। এটিকে খেলনা বন্ধ বলা হয় ; আপনার ভাই এটি আপনার জন্য তৈরি করেছিলেন, এবং তিনি এখন বাইরের পরিসরে

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

উন্নত সন্তানের জন্য আমি নীচের মতো কিছু রাখি। এটি নিখুঁত নয়, তবে এটি আপনাকে এটি সম্পর্কে অনুভূতি দেয়:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

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


49

ছয় বছর বয়সের একটি উত্তর (ধরে নিলেন তিনি জানেন যে কোনও ফাংশন কী এবং ভেরিয়েবল কী এবং কী ডেটা হয়):

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

function the_closure() {
  var x = 4;
  return function () {
    return x; // Here, we look back inside the_closure for the value of x
  }
}

var myFn = the_closure();
myFn(); //=> 4

এটি ব্যাখ্যা করার জন্য আরও একটি সহজ উপায় হ'ল সুযোগের শর্তে:

আপনি যে কোনও সময় বৃহত্তর স্কোপের অভ্যন্তরে একটি ছোট স্কোপ তৈরি করবেন, ছোট স্কোপ সর্বদা বৃহত্তর স্কোপটিতে কী রয়েছে তা দেখতে সক্ষম হবে।


49

জাভাস্ক্রিপ্টের কোনও ক্রিয়াকলাপ কেবল নির্দেশের সেট (সি ভাষা হিসাবে) এর একটি রেফারেন্স নয়, তবে এটিতে একটি লুকানো ডেটা স্ট্রাকচারও রয়েছে যা এটি ব্যবহার করে এমন সমস্ত ননলোকাল ভেরিয়েবল (ক্যাপচারড ভেরিয়েবল) এর রেফারেন্স দ্বারা গঠিত। এ জাতীয় দ্বি-পিস ফাংশনগুলিকে ক্লোজার বলা হয়। জাভাস্ক্রিপ্ট প্রতিটি ফাংশন একটি বন্ধ হিসাবে বিবেচনা করা যেতে পারে।

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

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

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

একটি উদাহরণ:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();

47

সম্ভবত ছাপ-ছয় বছরের বাচ্চাদের সবচেয়ে সংকুচিত ছাড়াও কিছুটা ছাড়িয়ে গেলেও জাভাস্ক্রিপ্টে বন্ধের ধারণাটি তৈরি করতে সহায়তা করে এমন কয়েকটি উদাহরণ আমার জন্য ক্লিক করুন।

ক্লোজার হ'ল এমন একটি ফাংশন যা অন্য ফাংশনের স্কোপ (এর ভেরিয়েবল এবং ফাংশন) অ্যাক্সেস করে। ক্লোজার তৈরির সবচেয়ে সহজ উপায় হ'ল কোনও ফাংশনের মধ্যে ফাংশন দিয়ে; জাভাস্ক্রিপ্টে কোনও ফাংশনের সর্বদা এর ফাংশনটির ব্যাপ্তিটির সুযোগ থাকতে পারে তার কারণ।

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    innerFunction();
}

outerFunction();

এলার্ট: বানর

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

এখন নিম্নলিখিত বিবেচনা করুন:

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

এলার্ট: বানর

संदर्भToInnerFunction আউটআর ফাংশন () এ সেট করা হয়েছে, যা কেবলমাত্র অভ্যন্তরীণ ফাংশনটির জন্য একটি রেফারেন্স দেয়। রেফারেন্সটোয়ার ফাংশন যখন ডাকা হয় তখন এটি আউটটার ভারে ফিরে আসে। আবারও, উপরে হিসাবে, এটি দেখায় যে আধ্যাত্মিক ফাংশনের বহিরাগতের অ্যাক্সেস রয়েছে আউটআরফরনের একটি পরিবর্তনশীল। তদ্ব্যতীত, এটি আকর্ষণীয় যে লক্ষণীয় যে এটি বহির্মুখী কার্য সম্পাদন শেষ করার পরেও এই অ্যাক্সেসটিকে ধরে রাখে।

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

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

outerFunction = null;
alert(referenceToInnerFunction());

ALERT: বানর ALERT: বানর

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

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

//////////

ক্লোজার সম্পর্কে আরও দুটি বিষয় লক্ষ্য করুন। প্রথমত, বন্ধটি সর্বদা এর ধারণকৃত কার্যের শেষ মানগুলিতে অ্যাক্সেস পাবে।

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    outerVar = "gorilla";

    innerFunction();
}

outerFunction();

এলার্ট: গরিলা

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


45

আমি কেবল তাদের মজিলা ক্লোজার পৃষ্ঠাতে নির্দেশ করব । এটি ক্লোজার বুনিয়াদি এবং ব্যবহারিক ব্যবহারের সর্বাধিক সংক্ষিপ্ত এবং সাধারণ ব্যাখ্যা যা আমি খুঁজে পেয়েছি। এটি জাভাস্ক্রিপ্ট শেখার জন্য অত্যন্ত প্রস্তাবিত।

এবং হ্যাঁ, আমি এমনকি এটি একটি 6 বছর বয়সী হিসাবেও সুপারিশ করব - 6 বছর বয়সী যদি ক্লোজারগুলি সম্পর্কে শিখতে থাকে তবে এটি যৌক্তিক যে তারা নিবন্ধে প্রদত্ত সংক্ষিপ্ত এবং সহজ ব্যাখ্যা উপলব্ধি করতে প্রস্তুত ।


আমি সম্মত হই: উক্ত মোজিলা পৃষ্ঠাটি বিশেষত সরল এবং সংক্ষিপ্ত। আশ্চর্যজনকভাবে আপনার পোস্টটি অন্যদের মতো এত ব্যাপকভাবে প্রশংসিত হয়নি।
ব্রাইস কসটিলাস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.