diff --git a/basic/1. execution-context/Practices/practice2.md b/basic/1. execution-context/Practices/practice2.md new file mode 100644 index 0000000..54781e3 --- /dev/null +++ b/basic/1. execution-context/Practices/practice2.md @@ -0,0 +1,15 @@ + +```JavaScript +let num = 5; + +const changeNum = () => { + let num; + num = 72; + console.log(num); +} + +changeNum(); +console.log(num); +``` + +উপরের কোডের আউটপুট কি হবে? যদি changeNum() ফাংশনের ভেতরে গ্লোবাল ভ্যারিয়েবল num -এর মান পরিবর্তন না হয় তাহলে আমরা কিভাবে সেটা করতে পারবো? \ No newline at end of file diff --git a/basic/1. execution-context/README.md b/basic/1. execution-context/README.md index 6edac9a..9c09c02 100644 --- a/basic/1. execution-context/README.md +++ b/basic/1. execution-context/README.md @@ -6,7 +6,7 @@ - **গ্লোবাল এক্সিকিউশন কন্টেক্সট -** এটি ডিফল্ট এক্সিকিউশন কন্টেক্সট। যে কোডটি কোন ফাংশনের ভিতরে নেই তা গ্লোবাল এক্সিকিউশন কন্টেক্সটে আছে। এটি দুটি জিনিস সম্পন্ন করেঃ - - এটি একটি গ্লোবাল অবজেক্ট তৈরি করে যা একটি **window** অবজেক্ট (ব্রাউজারের ক্ষেত্রে) এবং **global** অবজেক্ট (নোডের ক্ষেত্রে) + - এটি একটি গ্লোবাল অবজেক্ট তৈরি করে যা ব্রাউজারের ক্ষেত্রে **window** অবজেক্ট এবং নোডের ক্ষেত্রে **global** অবজেক্ট নামে পরিচিত। - **this** এর ভ্যালু হিসাবে গ্লোবাল অবজেক্টকে সেট করে। একটি প্রোগ্রামে শুধুমাত্র একটি গ্লোবাল এক্সিকিউশন কন্টেক্সট থাকতে পারে। - **ফাংশন এক্সিকিউশন কন্টেক্সট -** যখনই কোন ফাংশন কল করা হয়, সেই ফাংশনের জন্য জেএস ইঞ্জিন একটি নতুন এক্সিকিউশন কন্টেক্সট তৈরি করে। প্রতিটি ফাংশনের নিজস্ব এক্সিকিউশন কন্টেক্সট আছে। একাধিক সংখ্যক ফাংশন এক্সিকিউশন কন্টেক্সট হতে পারে। ফাংশন এক্সিকিউশন কন্টেক্সটের গ্লোবাল এক্সিকিউশন কন্টেক্সটের সকল কোড অ্যাক্সেস আছে যদিও গ্লোবাল কন্টেক্সটের ফাংশন এক্সিকিউশন কন্টেক্সটের কোডের অ্যাক্সেস নেই। গ্লোবাল এক্সিকিউশন কন্টেক্সটের কোড এক্সিকিউট করার সময় যদি জেএস ইঞ্জিন কোন ফাংশন কল পায়, এটি সেই ফাংশনের জন্য একটি নতুন ফাংশন এক্সিকিউশন কন্টেক্সট তৈরি করে। ব্রাউজার কন্টেক্সটে, যদি কোড strict মোডে এক্সিকিউট করা হয়, তাহলে **this** এর ভ্যালু **undefined** অন্যথায় **window** অবজেক্ট হবে ফাংশন এক্সিকিউশন কন্টেক্সট। @@ -37,13 +37,13 @@ console.log(results); // 70 ### ১। Creation phase - একটি গ্লোবাল অবজেক্ট তৈরি করে অর্থাৎ, ওয়েব ব্রাউজারে **window** বা নোড জেএসে **global**। -- **this** নামে একটি গ্লোবাল ভ্যারিয়াবল তৈরি করে যা গ্লোবাল অবজেক্টকে নির্দেশ করে। +- **this** নামে একটি গ্লোবাল ভ্যারিয়েবল তৈরি করে যা গ্লোবাল অবজেক্টকে নির্দেশ করে। - সকল ভ্যারিয়েবল এবং ফাংশনের জন্য একটি মেমোরি স্পেস সেটআপ করে। - ভ্যারিয়েবলের ডিফল্ট ভ্যালু হিসাবে **undefined** অ্যাসাইন করে এবং ফাংশন ডিক্লেয়ারেশনগুলি হীপ মেমোরিতে স্টোর করে। আমাদের উদাহরণে, creation phase - এ জাভাস্ক্রিপ্ট ইঞ্জিন গ্লোবাল এক্সিকিউশন কন্টেক্সটে ভ্যারিয়েবল a ও results এবং ফাংশন ডিক্লেয়ারেশন multByTen() স্টোর করে। এছাড়াও, এটি ভ্যারিয়েবল a এবং results কে undefined হিসাবে ইনিশিয়ালাইজ করে। -> #### Global Execution Context (Creaton Phase Browser) +> #### Global Execution Context (Creation Phase Browser) > > - **window**: Global Object > - **this**: window @@ -73,7 +73,7 @@ Execution phase - এ, জাভাস্ক্রিপ্ট ইঞ্জি > - **this**: window > - **a**: undefined -আমাদের উদাহরণে, ফাংশন এক্সিকিউশন কন্টেক্সট **arguments** অবজেক্ট তৈরি করে যা ফাংশনে পাস করা সকল প্যারামিটারকে নির্দেশ করে, **this** এর মান হিসাবে গ্লোবাল অবজেক্টে **window** কে সেট করে। এবং **a** প্যারামিটার কে **undefined** হিসাবে ইনিশিয়ালাইজ করে। +আমাদের উদাহরণে, ফাংশন এক্সিকিউশন কন্টেক্সট **arguments** অবজেক্ট তৈরি করে যা ফাংশনে পাস করা সকল প্যারামিটারকে নির্দেশ করে, **this** এর মান হিসাবে গ্লোবাল অবজেক্টে **window** কে সেট করে এবং **a** প্যারামিটার কে **undefined** হিসাবে ইনিশিয়ালাইজ করে। > #### Function Execution Context (Execution Phase Browser) > @@ -83,9 +83,6 @@ Execution phase - এ, জাভাস্ক্রিপ্ট ইঞ্জি ফাংশন এক্সিকিউশন কন্টেক্সটে **Execution phase** চলার সময়, এটি **a** প্যারামিটারে **7** অ্যাসাইন করে এবং ফলাফল **(70)** গ্লোবাল এক্সিকিউশন কন্টেক্সটের **results** ভ্যারিয়েবলে রিটার্ন করেঃ - - - > #### Global Execution Context (Execution Phase Browser) > > - **window**: Global Object @@ -94,11 +91,12 @@ Execution phase - এ, জাভাস্ক্রিপ্ট ইঞ্জি > - **multByTen**: fn() > - **results**: 70 -### আরও বাংলা টিউটোরিয়াল -> - ভালো কিছু পাওয়া যায়নি। +### আরও বাংলা টিউটোরিয়াল + +> - ভালো কিছু পাওয়া যায়নি। +### বাংলা ভিডিও টিউটোরিয়াল -### বাংলা ভিডিও টিউটোরিয়াল > - [Execution Context in Javascript | JS All You Need To Know | JS Bangla Tutorials](https://www.youtube.com/watch?v=MoPW9pxHMkI) > - [JavaScript Advance (Bangla) Execution Context](https://www.youtube.com/watch?v=Ke0HhvI9tpw) diff --git a/basic/10. browser-storage-and-caching/README.md b/basic/10. browser-storage-and-caching/README.md index 1b02a3a..fc4c087 100644 --- a/basic/10. browser-storage-and-caching/README.md +++ b/basic/10. browser-storage-and-caching/README.md @@ -1,44 +1,44 @@ ### Browser Storage ওয়েব অ্যাপস/সাইটগুলিতে অফলাইন/Cache মেকানিজম প্রদান করার জন্য Browser Storage ব্যবহার করে: - - local storage: localStorage অনেক ডেভেলপারদের মধ্যে ব্রাউজারে সবচেয়ে জনপ্রিয় স্টোরেজ বিকল্পগুলির মধ্যে একটি। localStorage-এ, ডেটা সেশন জুড়ে সংরক্ষণ করা হয়, সার্ভারের সাথে share করা হয় না এবং একই প্রোটোকল এবং ডোমেনের অধীনে সমস্ত web-page এর জন্য ব্যবহারযোগ্য। localStorage সীমা সর্বাধিক ~5MB। localStorage-এ সংরক্ষণ করার আগে আমাদের অবশ্যই ডেটাটিকে স্ট্রিংয়ে রূপান্তর করতে হবে। localStorage এর প্রধান তিনটি function হল: + - local storage: localStorage অনেক ডেভেলপারদের মধ্যে ব্রাউজারে সবচেয়ে জনপ্রিয় স্টোরেজ বিকল্পগুলির মধ্যে একটি। localStorage-এ, ডেটা সেশন জুড়ে সংরক্ষণ করা হয়, সার্ভারের সাথে share করা হয় না এবং একই প্রোটোকল এবং ডোমেনের অধীনে সমস্ত web-page এর জন্য ব্যবহারযোগ্য। localStorage সীমা সর্বাধিক ~5MB। localStorage-এ সংরক্ষণ করার আগে আমাদের অবশ্যই ডেটাটিকে স্ট্রিংয়ে রূপান্তর করতে হবে। localStorage এর প্রধান তিনটি function হলো: 1. localStorage.setItem('key', 'value') 2. localStorage.getItem('key') 3. localStorage.removeItem('key') - - session storage : sessionStorage অবজেক্ট শুধুমাত্র একটি সেশনের জন্য ডেটা সঞ্চয় করে। ব্রাউজার ট্যাব বন্ধ হয়ে গেলে ডেটা মুছে ফেলা হয়। sessionStorage এর প্রধান তিনটি fucntion হল: + - session storage : sessionStorage অবজেক্ট শুধুমাত্র একটি সেশনের জন্য ডেটা সঞ্চয় করে। ব্রাউজার ট্যাব বন্ধ হয়ে গেলে ডেটা মুছে ফেলা হয়। sessionStorage এর প্রধান তিনটি fucntion হলো: 1. sessionStorage.setItem('key', 'value') 2. sessionStorage.getItem('key') 3. sessionStorage.removeItem('key') - - IndexedDB: একটি ক্লায়েন্ট-সাইড, NoSQL ডাটাবেস যা ডেটা, ফাইল এবং ব্লব সংরক্ষণ করতে পারে। ব্রাউজারগুলির উপর নির্ভর করে প্রতি ডোমেনে কমপক্ষে 1GB পাওয়া উচিত, এবং এটি অবশিষ্ট disc-space এর 60% পর্যন্ত পৌঁছাতে পারে। IndexedDB ব্যবহার করে সঞ্চালিত অপারেশনগুলি অ্যাসিঙ্ক্রোনাসভাবে করা হয়, যাতে অ্যাপ্লিকেশনগুলিকে ব্লক না হয়। - - Cookies: Cookies হল একমাত্র স্টোরেজ যা সার্ভারের সাথে শেয়ার করা হয়। Cookies প্রতিটি HTTP request অংশ হিসাবে পাঠানো হয়. এটি আমাদের ক্লায়েন্ট এবং সার্ভারের মধ্যে একটি shared state তৈরি করতে দেয়, এবং বিভিন্ন সাবডোমেনে একাধিক অ্যাপ্লিকেশানের মধ্যে shared state তৈরি করে। একটি সতর্কতা: প্রতিটি অনুরোধের সাথে Cookies পাঠানো হয়, যার অর্থ হল একটি ছোট request আকার বজায় রাখার জন্য আমাদের কুকিগুলি ছোট রাখতে হবে। - - URL storage:URL একটি storage নয়, কিন্তু এটি একটি shared state তৈরি করার একটি ভাল উপায়। এর অর্থ current URL এ query parameters যোগ করা যাতে current state পুনরায় তৈরি করতে ব্যবহার করা যেতে পারে। - - Cache API: Cache API হল service worker স্পেসিফিকেশনের একটি অংশ, এবং resource cache করার একটি দুর্দান্ত উপায়। এটি আপনাকে URL রিসোর্স(assets, webpages, HTTP API reponses) Cache করার অনুমতি দেয়। Cache API তৈরি করা হয়েছিল Service Workder নেটওয়ার্ক request cache করতে সক্ষম করার জন্য যাতে তারা দ্রুত response প্রদান করতে পারে, নেটওয়ার্কের speed বা avilabily নির্বিশেষে। যাইহোক, Cache API একটি সাধারণ স্টোরেজ mechanism হিসাবেও ব্যবহার করা যেতে পারে। + - IndexedDB: একটি ক্লায়েন্ট-সাইড, NoSQL ডাটাবেস যা ডেটা, ফাইল এবং ব্লব সংরক্ষণ করতে পারে। ব্রাউজারগুলির উপর নির্ভর করে প্রতি ডোমেইনে কমপক্ষে 1GB পাওয়া উচিত, এবং এটি অবশিষ্ট disc-space এর 60% পর্যন্ত পৌঁছাতে পারে। IndexedDB ব্যবহার করে synchronous অপারেশনগুলি asynchronous করা হয়, যাতে অ্যাপ্লিকেশনগুলি ব্লক না হয়। + - Cookies: Cookies হলো একমাত্র স্টোরেজ যা সার্ভারের সাথে শেয়ার করা হয়। Cookies প্রতিটি HTTP request অংশ হিসাবে পাঠানো হয়. এটি আমাদের ক্লায়েন্ট এবং সার্ভারের মধ্যে একটি shared state তৈরি করতে দেয়, এবং বিভিন্ন সাব-ডোমেইনে একাধিক অ্যাপ্লিকেশনের মধ্যে shared state তৈরি করে। একটি সতর্কতা: প্রতিটি api request -এর সাথে Cookies পাঠানো হয়, অর্থাৎ একটি request -এর আকার ছোট রাখার জন্য আমাদের কুকিগুলি ছোট রাখতে হবে। + - URL storage: URL একটি storage নয়, কিন্তু এটি shared state তৈরি করার একটি ভাল উপায়। এর অর্থ current URL এ query parameters যোগ করা যাতে current state পুনরায় তৈরি করতে ব্যবহার করা যেতে পারে। + - Cache API: Cache API হলো service worker স্পেসিফিকেশনের একটি অংশ, এবং resource cache করার একটি দুর্দান্ত উপায়। এটি আপনাকে URL রিসোর্স (assets, webpages, HTTP API responses) cache করার অনুমতি দেয়। Cache API তৈরি করা হয়েছিল Service Worker নেটওয়ার্ক request cache করতে সক্ষম করার জন্য যাতে তারা দ্রুত response প্রদান করতে পারে, নেটওয়ার্কের speed বা availability নির্বিশেষে। যাইহোক, Cache API একটি সাধারণ স্টোরেজ mechanism হিসাবেও ব্যবহার করা যেতে পারে। ### Browser Caching -Caching হল ওয়েব ব্রাউজিংয়ের একটি বৈশিষ্ট্য যা সাম্প্রতিক ওয়েব page গুলিকে ওয়েব ব্রাউজারে অস্থায়ীভাবে সংরক্ষণ করার অনুমতি দেয়। এই বৈশিষ্ট্যটি গুরুত্বপূর্ণ কারণ এটি পৃষ্ঠা লোডের সময়কে উন্নত করে এবং ব্রাউজিং খরচ কমায়৷ এটি একটি resourceful কৌশল যা ডেভেলপাররা ওয়েব ব্রাউজিং অভিজ্ঞতা উন্নত করতে ব্যবহার করতে পারেন। ওয়েবসাইটগুলিকে আরও দ্রুত লোড করার জন্য ওয়েব ব্রাউজারগুলি HTML ফাইল, Javascript এবং Image গুলি cache করে৷ ওয়েব সার্ভার ওয়েবসাইট থেকে তথ্য সংগ্রহ করে এবং ওয়েব ব্রাউজারে পাঠায়। ব্যবহারকারী প্রথমবার ভিজিটর কিনা বা সাইটটি আগে ব্যবহার করেছেন তার উপর নির্ভর করে Caching করা হয়। Caching কীভাবে কাজ করে তা বোঝার জন্য আসুন এই দুটি ক্ষেত্রে দেখি: +Caching হলো ওয়েব ব্রাউজিংয়ের একটি বৈশিষ্ট্য যা সাম্প্রতিক ওয়েব page গুলিকে ওয়েব ব্রাউজারে অস্থায়ীভাবে সংরক্ষণ করার অনুমতি দেয়। এই বৈশিষ্ট্যটি গুরুত্বপূর্ণ, কারণ এটি পৃষ্ঠা লোডের সময়কে উন্নত করে এবং ব্রাউজিং খরচ কমায়৷ এটি একটি resourceful কৌশল যা ডেভেলপাররা ওয়েব ব্রাউজিং অভিজ্ঞতা উন্নত করতে ব্যবহার করতে পারেন। ওয়েবসাইটগুলিকে আরও দ্রুত লোড করার জন্য ওয়েব ব্রাউজারগুলি HTML ফাইল, Javascript এবং Image গুলি cache করে। ওয়েব সার্ভার ওয়েবসাইট থেকে তথ্য সংগ্রহ করে এবং ওয়েব ব্রাউজারে পাঠায়। ব্যবহারকারী প্রথমবার ভিজিটর কিনা বা সাইটটি আগে ব্যবহার করেছেন তার উপর নির্ভর করে Caching করা হয়। Caching কীভাবে কাজ করে তা বোঝার জন্য আসুন এই দুটি ক্ষেত্রে দেখি: **Case 1: A first-time user** -আপনি যখন প্রথমবার কোনো ওয়েবসাইট ভিজিট করেন, তখন ওয়েব ব্রাউজার ওয়েব সার্ভার থেকে ডেটা (HTML, CSS, JS) সংগ্রহ করবে। এর কারণ হল ওয়েব রিসোর্সগুলি এখনও Cache সংরক্ষণ করা হয়নি। ওয়েব ব্রাউজার তারপর ওয়েবসাইটটিতে পরবর্তী পরিদর্শনে user experince উন্নত করতে একটি Cache এ ওয়েব resource গুলি সংরক্ষণ করবে। +আপনি যখন প্রথমবার কোনো ওয়েবসাইট ভিজিট করেন, তখন ওয়েব ব্রাউজার ওয়েব সার্ভার থেকে ডেটা (HTML, CSS, JS) সংগ্রহ করবে। এর কারণ হলো ওয়েব রিসোর্সগুলি এখনও Cache সংরক্ষণ করা হয়নি। ওয়েব ব্রাউজার তারপর ওয়েবসাইটটিতে পরবর্তী পরিদর্শনে user experience উন্নত করতে একটি Cache এ ওয়েব resource গুলি সংরক্ষণ করবে। **Case 2: The user used the website before** -যদি কোনো ব্যবহারকারী একই কম্পিউটার ডিভাইস ব্যবহার করে দ্বিতীয়বার কোনো ওয়েবসাইট পরিদর্শন করেন, ওয়েবসাইটটি প্রথম দর্শনের চেয়ে দ্রুত লোড হবে। কারণ ওয়েব ব্রাউজার Cache থেকে images CSS এবং Javascript এর মতো স্ট্যাটিক ওয়েব রিসোর্স পুনরুদ্ধার করবে। +যদি কোনো ব্যবহারকারী একই কম্পিউটার ডিভাইস ব্যবহার করে দ্বিতীয়বার কোনো ওয়েবসাইট পরিদর্শন করেন, ওয়েবসাইটটি প্রথম দর্শনের চেয়ে দ্রুত লোড হবে। কারণ ওয়েব ব্রাউজার Cache থেকে images, CSS এবং Javascript এর মতো স্ট্যাটিক ওয়েব রিসোর্স পুনরুদ্ধার করবে। -HTTP response headers সাধারণত Caching এর জন্য ব্যবহৃত হয়. একটি ওয়েবসাইটের মালিকের cache policy এর উপর নিয়ন্ত্রণ থাকে। এই নিয়ন্ত্রণ HTTP Cache হেডার ব্যবহার করে ব্যবহার করা হয়. এই headers মেয়াদ শেষ হওয়ার আগে ওয়েব resource কে Cache করা যেতে পারে এমন সর্বাধিক সময় নির্ধারণ করতে ব্যবহৃত হয়। নিম্নলিখিত HTTP response headers সাধারণত Cache করার জন্য ব্যবহৃত হয়: +HTTP response headers সাধারণত Caching এর জন্য ব্যবহৃত হয়. একটি ওয়েবসাইটের মালিকের cache policy এর উপর নিয়ন্ত্রণ থাকে। এই নিয়ন্ত্রণ HTTP Cache হেডার ব্যবহার করে ব্যবহার করা হয়। এই headers মেয়াদ শেষ হওয়ার আগে ওয়েব resource কে Cache করা যেতে পারে এমন সর্বাধিক সময় নির্ধারণ করতে ব্যবহৃত হয়। নিম্নলিখিত HTTP response headers সাধারণত Cache করার জন্য ব্যবহৃত হয়: **ETag:** - এটি 'Entity tag' শব্দটির সংক্ষিপ্ত রূপ। এটি একটি Cache validation টোকেন হিসাবে কাজ করে। ক্যাশ করা ফাইলের মেয়াদ শেষ হলে এটি ব্যবহার করা হয়। ওয়েব ব্রাউজারটি তার request এ ETag ব্যবহার করে Cache এ বিদ্যমান একটি পুরানো কপি আছে কিনা তা নিশ্চিত করতে। + এটি 'Entity tag' শব্দটির সংক্ষিপ্ত রূপ। এটি একটি Cache validation টোকেন হিসাবে কাজ করে। ক্যাশ করা ফাইলের মেয়াদ শেষ হলে এটি ব্যবহার করা হয়। ওয়েব ব্রাউজারটি তার request এ ETag ব্যবহার করে Cache এ বিদ্যমান একটি পুরানো কপি আছে কিনা তা নিশ্চিত করতে ব্যবহৃত হয়। **Cache-Control:** এই header এ বিভিন্ন parameters রয়েছে যা validation, cache behavior এবং expiration নিয়ন্ত্রণ করে. এই header এর কিছু directives অন্তর্ভুক্ত: - no-cache: এই directive টি ওয়েব সার্ভারের content এর সাথে সামঞ্জস্যপূর্ণ কিনা তা পরীক্ষা করতে ব্রাউজারকে Cache এ থাকা content যাচাই করার নির্দেশ দেয়। যদি content টি fresh হয়, তাহলে ব্রাউজার Cache থেকে এটি আনতে পারে। - - public: এর মানে হল যে ব্রাউজার বা কোনো মধ্যস্থতাকারী পক্ষ (যেমন CDN বা proxies) ওয়েব রিসোর্স Cache করতে পারে। - - private: এর মানে হল যে শুধুমাত্র ব্রাউজারই ওয়েব রিসোর্স Cache করতে পারে। + - public: এর মানে হলো যে ব্রাউজার বা কোনো মধ্যস্থতাকারী পক্ষ (যেমন CDN বা proxies) ওয়েব রিসোর্স Cache করতে পারে। + - private: এর মানে হলো যে শুধুমাত্র ব্রাউজারই ওয়েব রিসোর্স Cache করতে পারে। - no-store: এই নির্দেশিকা ব্রাউজারকে Cache না করার নির্দেশ দেয়। - - Expires: এই header টি কখন Cache এ সংরক্ষিত সম্পদের মেয়াদ শেষ হবে তা define করে । মেয়াদ শেষ হওয়ার সময় পৌঁছে গেলে, ব্রাউজার কন্টেন্টটিকে পুরানো বিবেচনা করবে। যেমন, Expires: Mon, 14 June 2021 10:30:00 GMT. + - Expires: এই header টি কখন Cache এ সংরক্ষিত সম্পদের মেয়াদ শেষ হবে তা define করে। মেয়াদ শেষ হওয়ার সময় পৌঁছে গেলে, ব্রাউজার কন্টেন্টটিকে পুরানো বিবেচনা করবে। যেমন, Expires: Mon, 14 June 2021 10:30:00 GMT. - Last modified: এই header টি কখন web content পরিবর্তন করা হয়েছিল সেই সংক্রান্ত তথ্য প্রদান করে। এই paremeter টি মূল content পরিবর্তনের তারিখ এবং সময় অন্তর্ভুক্ত করে। যেমন, Last Modified: Tue, 11 February 2021 10:30:00 GMT. diff --git a/basic/11. debouncing-and-throttling/README.md b/basic/11. debouncing-and-throttling/README.md index 5c59dde..47fdcbf 100644 --- a/basic/11. debouncing-and-throttling/README.md +++ b/basic/11. debouncing-and-throttling/README.md @@ -1,20 +1,20 @@ ### Debouncing and Throttling -আমাদের আজকের আলোচনার বিষয় হল জাভাস্ক্রিপ্টের Debouncing এবং throttling. জাভাস্ক্রিপ্টের কোন Application কে অপ্টিমাইজ করার জন্য বা ব্রাউজার Performance কে আরও উন্নত করার জন্য Debouncing এবং throttling ব্যবহার করা হয়। তাহলে চলুন আলোচনা শুরু করা যাক। +আমাদের আজকের আলোচনার বিষয় হল জাভাস্ক্রিপ্টের Debouncing এবং Throttling. জাভাস্ক্রিপ্টের কোন Application কে অপ্টিমাইজ করার জন্য বা ব্রাউজার Performance কে আরও উন্নত করার জন্য Debouncing এবং Throttling ব্যবহার করা হয়। তাহলে চলুন আলোচনা শুরু করা যাক। ### Debounce ফাংশন কি? Debounce ফাংশন হল এমন একটি ফাংশন যা কোন ফাংশন কতবার কল হবে তা নিয়ন্ত্রণ করে এবং কিছু নিদিষ্ট সময় অপেক্ষা করার পর পুনরায় ওই ফাংশনটিকে কল করে। চলুন একটা উদাহরন দেখা যাক। -বেশিরভাগ ওয়েবসাইটেই Search Bar থাকে যার মাধ্যমে User কিহু Specific KeyWord দিয়ে সার্চ করে কাঙ্ক্ষিত ফলাফল পেয়ে থাকে। Ecommerce সাইটে User যখন কোন প্রোডাক্টের নাম দিয়ে সার্চ করে তখন ওই টাইপের যত প্রোডাক্ট আছে তা User এর কাছে চলে আসে। সুতরাং এখানে যা হচ্ছে তা হল, User যখন কোন একটা সার্চ Query লিখে তখন সার্চ Query এর প্রত্যেকটা Character এর জন্য API কল হয়। ঊদাহরসরুপ, User যদি "Apple Macbook Pro" লিখে সার্চ করে তবে ১৭ বার API call হবে এই সার্চের ফলাফল দেখানর জন্য। এটা কখনও একটা ভাল Approach হতে পারে না। আমরা এখানে Debounce ব্যবহার করে API call এর পরিমাণ কমিয়ে অনেক Optimization করতে পারি। +বেশিরভাগ ওয়েবসাইটেই Search Bar থাকে যার মাধ্যমে User কিছু Specific Keyword দিয়ে সার্চ করে কাঙ্খিত ফলাফল পেয়ে থাকে। Ecommerce সাইটে User যখন কোন প্রোডাক্টের নাম দিয়ে সার্চ করে তখন ওই টাইপের যত প্রোডাক্ট আছে তা User এর কাছে চলে আসে। সুতরাং এখানে যা হচ্ছে তা হলো, User যখন কোন একটা সার্চ Query লিখে তখন সার্চ Query এর প্রত্যেকটা Character এর জন্য API কল হয়। উদাহরণস্বরূপ, User যদি "Apple Macbook Pro" লিখে সার্চ করে তবে ১৭ বার API call হবে এই সার্চের ফলাফল দেখানোর জন্য। এটা কখনও একটা ভাল Approach হতে পারে না। আমরা এখানে Debounce ব্যবহার করে API call এর পরিমাণ কমিয়ে অনেক Optimization করতে পারি। চলুন, আমাদের প্রথম debounce ছাড়া আমাদের কোডটা কেমন হবে তা দেখি। -```js +```html ``` -আমরা সাধারণত Search Functionality গুলো onChange or onKeyUp event এর মাধ্যমে করে থাকি। এখন আমরা আমারদের `searchHandler` ফাংশনটা লিখে ফেলি। +আমরা সাধারণত Search Functionality গুলো onChange অথবা onKeyUp ইভেন্টের মাধ্যমে করে থাকি। এখন আমরা আমারদের `searchHandler` ফাংশনটা লিখে ফেলি। ```js function searchHandler(...args) { @@ -25,7 +25,7 @@ function searchHandler(...args) { } ``` -আশা করছি এই পর্যন্ত বুঝতে কোন সমস্যা হচ্ছে না। তাহলে চলুন আমরা একটা reusable Dubounce ফাংশন লিখে ফেলি। +আশা করছি এই পর্যন্ত বুঝতে কোন সমস্যা হচ্ছে না। তাহলে চলুন আমরা একটা reusable Debounce ফাংশন লিখে ফেলি। ```js const optimisedSearchHandler = debounceFunc(searchHandler, 500); @@ -44,7 +44,7 @@ const debounceFunc = (func, delay) => { উপরের কোডটা একটু লক্ষ্য করে দেখুন, যখন আমরা সার্চবার এ কিছু লিখার সাথে সাথে এ API কল করছে না। এটি আমাদের সার্চবার এ কিছু লিখার পর একটা নিদিষ্ট সময় অপেক্ষা করছে যদি এর মধ্যে সার্চবার এ আর নতুন কিছু টাইপ করা না হয় তবেই এটি API কে কল করছে। এতে করে আমাদের API কল এর পরিমাণ অনেকখানি কমে গেল। তাহলে চলুন, আমরা আমাদের সার্চবারের `onChange` debounce Technique টা ব্যবহার করে ফেলি। -```js +```html ``` @@ -54,7 +54,7 @@ const debounceFunc = (func, delay) => { ### Throttling আসলে কি? -Throttling এমন একটি Technique যার মাধ্যমে Event Handler এর অ্যাকশানকে Limited করা যায়। অর্থাৎ একটা Event কল হবার পর সুনিদিষ্ট টাইম এর মধ্যে ওই Event আর কল হবে না। বুঝার সুবিধার জন্য আমরা একটা উদাহরনস্বরূপ শুটিংগেমের কথা চিন্তা করতে পারি। একটি শুটিং গেমে বেশ কয়েক ধরনের অস্র থাকতে পারে। প্রতিটি অস্রেরই একটি Fire এর পর পরবর্তী Fire এর জন্য প্রস্তুত হতে কিছু টাইম লাগে। যেমন ShortGun এর ক্ষেত্রে যে সময় লাগবে MachineGun এর ক্ষেত্রে আরও কম সময় লাগবে। ধরি, shortGun এর জন্য এই সময় 500ms আর MachineGun এর জন্য এই টাইম 100ms. তাই আমাদের এমন একটা লজিক সেট করতে হবে যাতে করে User যে অস্র ব্যবহার করুক না কেন, যদি সে Threshold টাইমের মধ্যে একাধিক বার Fire করে তবে শুধুমাত্র একটা Fireই কাজ করবে। আর Fire গুলো নিদিষ্ট সময়ের পর এক এক করে Fire করবে। +Throttling এমন একটি Technique যার মাধ্যমে Event Handler এর অ্যাকশানকে Limited করা যায়। অর্থাৎ একটা Event কল হবার পর সুনিদিষ্ট টাইম এর মধ্যে ওই Event আর কল হবে না। বুঝার সুবিধার জন্য আমরা একটা উদাহরনস্বরূপ শুটিংগেমের কথা চিন্তা করতে পারি। একটি শুটিং গেমে বেশ কয়েক ধরনের অস্ত্র থাকতে পারে। প্রতিটি অস্ত্রেরই একটি Fire এর পর পরবর্তী Fire এর জন্য প্রস্তুত হতে কিছু টাইম লাগে। যেমন ShortGun এর ক্ষেত্রে যে সময় লাগবে MachineGun এর ক্ষেত্রে আরও কম সময় লাগবে। ধরি, shortGun এর জন্য এই সময় 500ms আর MachineGun এর জন্য এই টাইম 100ms. তাই আমাদের এমন একটা লজিক সেট করতে হবে যাতে করে User যে অস্ত্র ব্যবহার করুক না কেন, যদি সে Threshold টাইমের মধ্যে একাধিক বার Fire করে তবে শুধুমাত্র একটা Fireই কাজ করবে। আর Fire গুলো নিদিষ্ট সময়ের পর এক এক করে Fire করবে। চলুন তাহলে Trigger ক্লিকের একটা Event Handler তৈরি করে ফেলি। @@ -66,7 +66,7 @@ const handlerTrigger = () => { ``` উপরের কোডটি লক্ষ্য করুন, User যখনই Trigger press করছে শট Fire হচ্ছে। -তাহলে চলুন এখন আমরা Throttle ফাংশন লিখে ফেলি যার parameter এ `handlerTrigger` ফাংশন আর Time Interval কে পাঠাব। +তাহলে চলুন এখন আমরা Throttle ফাংশন লিখে ফেলি যার parameter এ `handlerTrigger` ফাংশন আর Time Interval কে পাঠাবো। ```js const optimisedTriggerHandler = throttleFunc(handlerTrigger, 100); @@ -90,8 +90,8 @@ const throttleFunc = (func, interval) => { window.addEventListener(onclick, optimisedTriggerHandler); ``` -ঠিক এইভাবে আমরা বিভিন্ন Time Interval সেট করে `optimisedTriggerHandler` কে বিভিন্ন অস্ররের জন্য ব্যবহার করতে পারি। +ঠিক এইভাবে আমরা বিভিন্ন Time Interval সেট করে `optimisedTriggerHandler` কে বিভিন্ন অস্ত্রের জন্য ব্যবহার করতে পারি। -আমারা এখন পর্যন্ত Debouncing and Throttling দুইটি Techniqueই দেখলাম। এই দুইটি পদ্ধতি concept খুব কাছাকাছি হলে মূল পার্থক্য হল, Debouncing এর ক্ষেত্রে User এর অ্যাকশান কে মনিটর করি এবং Threshold Time এর মধ্যে আবার যদি কোন নতুন অ্যাকশান আসে তবে আবার নতুন করে Threshold Time পর্যন্ত অপেক্ষা করি API কল এর জন্য। অন্যদিকে, Throttling এর ক্ষেত্রে আমরা আমাদের predetermined time interval পর API কল করে দেই। +আমরা এখন পর্যন্ত Debouncing and Throttling দুইটি Techniqueই দেখলাম। এই দুইটি পদ্ধতি concept খুব কাছাকাছি হলে মূল পার্থক্য হল, Debouncing এর ক্ষেত্রে User এর অ্যাকশান কে মনিটর করি এবং Threshold Time এর মধ্যে আবার যদি কোন নতুন অ্যাকশান আসে তবে আবার নতুন করে Threshold Time পর্যন্ত অপেক্ষা করি API কল এর জন্য। অন্যদিকে, Throttling এর ক্ষেত্রে আমরা আমাদের predetermined time interval পর API কল করে দেই। আশা করি, Debouncing and Throttling বুঝতে আর কোন সমস্যা হবার কথা না। পরবর্তীতে আবার নতুন কোন বিষয় নিয়ে আবার কথা হবে। সে পর্যন্ত হ্যাপি কোডিং। diff --git a/basic/12. use-strict/README.md b/basic/12. use-strict/README.md index bc8dcbf..81a059b 100644 --- a/basic/12. use-strict/README.md +++ b/basic/12. use-strict/README.md @@ -1,4 +1,4 @@ -প্রায় সব ল্যাংগুয়েজেরই নিজস্ব একটা ডকুমেন্ট আছে। যার মাধ্যমে আমরা ঐ ল্যাংগুয়েজের ভাল কিংবা খারাপ দিক অথবা ভাল প্র্যাকটিস এবং খারাপ প্র্যাকটিস সম্পর্কে জানতে পারি। কিন্তু জাভাস্ক্রিপ্টের এই রকম কোন কিছু নেই। যে কারণে এখানে ভুল্টা বেশি হবার সুযোগ থাকে এবং সবাই নিজের মত করে কোড লিখে সে ভুলটা করেও বটে। যেগুলো আসলে ভুল সিনট্যাক্স এবং আনসিকিউর কোড। কিন্তু আমরা যখন স্ট্রিক্ট মোড ব্যবহার করি, তখন জাভাস্ক্রিপ্ট কোড কোন ভুল সিনট্যাক্স ছাড়া এক্সিকিউট করে এবং কোড আরও সিকিউর করে। +প্রায় সব ল্যাংগুয়েজেরই নিজস্ব একটা ডকুমেন্ট আছে। যার মাধ্যমে আমরা ঐ ল্যাংগুয়েজের ভাল কিংবা খারাপ দিক অথবা ভাল প্র্যাকটিস এবং খারাপ প্র্যাকটিস সম্পর্কে জানতে পারি। কিন্তু জাভাস্ক্রিপ্টের এই রকম কোন কিছু নেই। যে কারণে এখানে ভুলটা বেশি হবার সুযোগ থাকে এবং সবাই নিজের মত করে কোড লিখে সে ভুলটা করেও বটে। যেগুলো আসলে ভুল সিনট্যাক্স এবং আনসিকিউর কোড। কিন্তু আমরা যখন স্ট্রিক্ট মোড ব্যবহার করি, তখন জাভাস্ক্রিপ্ট কোড কোন ভুল সিনট্যাক্স ছাড়া এক্সিকিউট করে এবং কোড আরও সিকিউর করে। ### “use strict” ডিরেক্টিভঃ- **“use strict”** মোডে আমাদের কোড এক্সিকিউট করতে হলে আমাদেরকে **“use strict”** ডিরেক্টিভ ব্যবহার করতে হবে। এটি একটি এক্সপ্রেশন মাত্র। এটি জাভাস্ক্রিপ্টের ১.৮.৫ (ইএস৫) থেকে সাপোর্ট করে। @@ -7,7 +7,7 @@ **“use strict”** ডিরেক্টিভকে আমরা দুইভাবে ব্যবহার করতে পারি। গ্লোবাল ডিক্লারেশন হিসাবে এবং ফাংশন ডিক্লারেশন হিসাবে। ### গ্লোবাল ডিক্লারেশনঃ- -যখন আমরা গ্লোবাল ডিক্লারেশন হিসাবে **“use strict”** ব্যবহার করি, তখন ঐ পেজের সমস্ত জাভাস্ক্রিপ্ট কোড স্ট্রিক মোডে এক্সিকিউট হয়। +যখন আমরা গ্লোবাল ডিক্লারেশন হিসাবে **“use strict”** ব্যবহার করি, তখন ঐ পেজের সমস্ত জাভাস্ক্রিপ্ট কোড স্ট্রিক্ট মোডে এক্সিকিউট হয়। ```js "use strict"; @@ -16,7 +16,7 @@ console.log("Hello JavaScript"); ``` ### ফাংশন ডিক্লারেশনঃ- -যখন আমরা ফাংশন ডিক্লারেশন হিসাবে **“use strict”** ব্যবহার করি, তখন ফাংশনের ভিতরের সমস্ত জাভাস্ক্রিপ্ট কোড স্ট্রিক মোডে এক্সিকিউট হয়। ফাংশনের বাহিরে সব কোড নর্মাল মোডে এক্সিকিউট হয়। +যখন আমরা ফাংশন ডিক্লারেশন হিসাবে **“use strict”** ব্যবহার করি, তখন ফাংশনের ভিতরের সমস্ত জাভাস্ক্রিপ্ট কোড স্ট্রিক্ট মোডে এক্সিকিউট হয়। ফাংশনের বাহিরে সব কোড নর্মাল মোডে এক্সিকিউট হয়। ```js (function() { @@ -78,7 +78,7 @@ console.log(let); // Uncaught SyntaxError: Unexpected strict mode reserved word - protected #### উদাহরন – ৩ঃ -ফাংশনের ভিতরে **“this”** এর ভ্যালু সব সময় উইন্ডো অবজেক্টক হয়। +ফাংশনের ভিতরে **“this”** এর ভ্যালু সব সময় উইন্ডো অবজেক্ট হয়। ```js function showMe() { diff --git a/basic/13. iife-in-javascript/README.md b/basic/13. iife-in-javascript/README.md index 134f8cb..1768df3 100644 --- a/basic/13. iife-in-javascript/README.md +++ b/basic/13. iife-in-javascript/README.md @@ -81,7 +81,7 @@ console.log(window.num); // 7 })(); ``` -যদি আপনি একটি কোড বান্ডলার টুল ব্যবহার করে উভয় ফাইলগুলির কোডকে একটি একক ফাইলের কোড কনকেট করতে চান সেমিকোলন (;) ছাড়া, কনকানেটেড কোডটি একটি `Uncaught TypeError: (intermediate value)(...) is not a function` সিনট্যাক্স ইরের দিবে। +যদি আপনি একটি কোড বান্ডলার টুল ব্যবহার করে উভয় ফাইলগুলির কোডকে একটি একক ফাইলের কোড কনক্যাট করতে চান সেমিকোলন (;) ছাড়া, কনক্যানেটেড কোডটি একটি `Uncaught TypeError: (intermediate value)(...) is not a function` সিনট্যাক্স ইরোর দিবে। ধরুন আপনার নিম্নলিখিত ফাংশন সহ math.js নামে একটি লাইব্রেরি আছে এবং একটি HTML ফাইলে math.js লোড করুনঃ @@ -103,7 +103,7 @@ function div(a, b) { } ``` -পরবর্তীতে, আপনি একই ফাইলে anotherLibraby.js নামে আরেকটি জাভাস্ক্রিপ্ট লাইব্রেরি লোড করতে চানঃ +পরবর্তীতে, আপনি একই ফাইলে anotherLibrary.js নামে আরেকটি জাভাস্ক্রিপ্ট লাইব্রেরি লোড করতে চানঃ ```html diff --git a/basic/3. hoisting/README.md b/basic/3. hoisting/README.md index 902cdf9..11b1793 100644 --- a/basic/3. hoisting/README.md +++ b/basic/3. hoisting/README.md @@ -27,7 +27,7 @@ hoisting(); // Ouput: undefined ১. Variable Hoisting ```js - console.log(hoistingIntro); // Outpur: undefined + console.log(hoistingIntro); // Output: undefined var hoistingIntro = "Hi there, I am a string one."; ``` @@ -52,7 +52,7 @@ hoisting(); // Ouput: undefined console.log("Hoisted."); } ``` -বিঃ দ্রঃ একটি কথা ভাল করে মনে রাখবেন যে জাভাস্ক্রিপ্ট ফানশন এক্সপ্রেশনের ক্ষেত্রে কোন Hoisting করে না। +বিঃ দ্রঃ একটি কথা ভাল করে মনে রাখবেন যে জাভাস্ক্রিপ্ট ফাংশন এক্সপ্রেশনের ক্ষেত্রে কোন Hoisting করে না। ```js hoistedFunEx(); // TypeError: hoistedFunEx is not a function diff --git a/basic/4. closure/README.md b/basic/4. closure/README.md index 6eef582..f1e4912 100644 --- a/basic/4. closure/README.md +++ b/basic/4. closure/README.md @@ -45,7 +45,7 @@ for (var i = 1; i <= 5; i++) { } ``` -**কাঙ্ক্ষিত আউটপুটঃ-** +**কাঙ্খিত আউটপুটঃ-** ``` 1 @@ -55,7 +55,7 @@ for (var i = 1; i <= 5; i++) { 5 ``` -**কিন্তু আসছে অনাকাঙ্ক্ষিত আওউটপুটঃ-** +**কিন্তু আসছে অনাকাঙ্ক্ষিত আউটপুটঃ-** ``` 6 @@ -65,9 +65,9 @@ for (var i = 1; i <= 5; i++) { 6 ``` -আসলে এই আউটপুট আসার অনেক কারণ আছে। লুপের মাঝে ভ্যারিয়াবল i হচ্ছে একটি গ্লোবাল ভ্যারিয়াবল। যখন setTimeout রান হয় তার আগেই লুপ শেষ হয়ে যায় এবং তাই i ভ্যালু 6 হয়ে যায়। সেজন্যে প্রতি এক সেকন্ড পর পর পাঁচবার 6 দেখাচ্ছে। যদি বিশ্বাস না হয় তাহলে কোডটা রান করার পর আপনার গ্লোবাল window অবজেক্টটা একবার দেখেন সেখানে i নামে একটা ভ্যারিয়াবল দেখতে পারবেন এবং তার ভ্যালু 6 হয়ে আছে। +আসলে এই আউটপুট আসার অনেক কারণ আছে। লুপের মাঝে ভ্যারিয়েবল i হচ্ছে একটি গ্লোবাল ভ্যারিয়েবল। যখন setTimeout রান হয় তার আগেই লুপ শেষ হয়ে যায় এবং তাই i ভ্যালু 6 হয়ে যায়। সেজন্যে প্রতি এক সেকেন্ড পর পর পাঁচবার 6 দেখাচ্ছে। যদি বিশ্বাস না হয় তাহলে কোডটা রান করার পর আপনার গ্লোবাল window অবজেক্টটা একবার দেখেন সেখানে i নামে একটা ভ্যারিয়াবল দেখতে পারবেন এবং তার ভ্যালু 6 হয়ে আছে। -এই সমস্যার সমাধান আমরা IIFE বা Immediately Invoked Function Expression ব্যবহার করে করতে পারি। নিচে উদাহরণ দেওয়া হলঃ- +এই সমস্যার সমাধান আমরা IIFE বা Immediately Invoked Function Expression ব্যবহার করে করতে পারি। নিচে উদাহরণ দেওয়া হলোঃ- **পদ্ধতি ১ঃ-** @@ -110,4 +110,4 @@ for (let i = 1; i <= 5; i++) { 5 ``` -অবশেষে আমাদের কাঙ্ক্ষিত আউটপুট ফেলাম। তবে আজ এই পর্যন্ত দেখা পরবর্তী অন্য টপিকে। হ্যাপি কোডিং... +অবশেষে আমাদের কাঙ্ক্ষিত আউটপুট পেলাম। তবে আজ এই পর্যন্ত দেখা পরবর্তী অন্য টপিকে। হ্যাপি কোডিং... diff --git a/basic/5. call-by-value-and-call-by-reference/README.md b/basic/5. call-by-value-and-call-by-reference/README.md index 1080e92..bd5650d 100644 --- a/basic/5. call-by-value-and-call-by-reference/README.md +++ b/basic/5. call-by-value-and-call-by-reference/README.md @@ -24,7 +24,7 @@ let newStr = str1.toUpperCase(); console.log(newStr); // HI THERE, I AM A STRING! - console.log(str1); Hi there, I am a string! + console.log(str1); // Hi there, I am a string! ``` প্রিমিটিভ ডাটা টাইপগুলো একে অপরের সাথে তাদের ভ্যালু দ্বারা তুলনা করে। @@ -58,7 +58,7 @@ ### নন-প্রিমিটিভ ডাটা টাইপ -নন-প্রিমিটিভ ডাটা mutable বা পরিবর্তনীয়। কারণ একটি নন-প্রিমিটিভ ডাটা তৈরি হয়ে যাওয়ার পরেও তার ভ্যালু পরিবর্তন হতে পারে। আমরা যখন কোন নন-প্রিমিটিভ ডাটা তৈরি করি, তখন সেই ডাটার জন্যে মেমোরিতে একটা অ্যাড্রেস তৈরি হয় এবং সেই অ্যাড্রেসটাকে মনে রেখে কোন এক জায়গায় ভ্যালুগুলোকে স্ট্রোর করে রাখে। তারপর আমাদের যখন দরকার পরে তখন সে ঐ অ্যাড্রেসকে কল করে এবং আমাদের ডাটা প্রদান করে। এটা বুঝতে হলে আপনাকে স্ট্যাক এবং হীপ মেমোরি সম্পর্কে জানতে হবে। তবে আমি যতটুকু বললাম এখন এতটুকু মনে রাখলেই হবে। +নন-প্রিমিটিভ ডাটা mutable বা পরিবর্তনীয়। কারণ একটি নন-প্রিমিটিভ ডাটা তৈরি হয়ে যাওয়ার পরেও তার ভ্যালু পরিবর্তন হতে পারে। আমরা যখন কোন নন-প্রিমিটিভ ডাটা তৈরি করি, তখন সেই ডাটার জন্যে মেমোরিতে একটা অ্যাড্রেস তৈরি হয় এবং সেই অ্যাড্রেসটাকে মনে রেখে কোন এক জায়গায় ভ্যালুগুলোকে ষ্টোর করে রাখে। তারপর আমাদের যখন দরকার পড়ে তখন সে ঐ অ্যাড্রেসকে কল করে এবং আমাদের ডাটা প্রদান করে। এটা বুঝতে হলে আপনাকে স্ট্যাক এবং হীপ মেমোরি সম্পর্কে জানতে হবে। তবে আমি যতটুকু বললাম এখন এতটুকু মনে রাখলেই হবে। ```js let arr1 = ["JavaScript", "React", "Redux", "React-Redux"]; @@ -76,8 +76,9 @@ ```js let obj1 = { - name: 'JavaScript' + name: 'JavaScript' }; + let obj2 = obj1; console.log(`${obj1.name}`); // JavaScript @@ -93,11 +94,11 @@ ```js let obj1 = { - name: 'JavaScript' + name: 'JavaScript' }; let obj2 = { - name: 'React' + name: 'JavaScript' }; console.log(obj1 === obj2); // false @@ -107,7 +108,7 @@ ```js let obj1 = { - name: 'JavaScript' + name: 'JavaScript' }; let obj2 = obj1; diff --git a/basic/7. this-keyword/README.md b/basic/7. this-keyword/README.md index 8f68e82..385f34b 100644 --- a/basic/7. this-keyword/README.md +++ b/basic/7. this-keyword/README.md @@ -36,7 +36,7 @@ let Person = { Person.sayName(); ``` -এইবার বলুন তো উপরের কোডটির আউটপুট কি হবে। যারা বলতে পারবেন তাদের জন্যে থাকবে আমার পক্ষ থেকে একটি চকোলেট। যদি উপরের বলা কথাগুলা ভাল করে পড়ে থাকেন, বুঝতে কোন অসুবিধা হওয়ার কথা না উপরের কোডের আউটপুট কি হবে। শুধু একটা কথা ভাল করে মনে রাখবেন কোন ফাংশন কল করার সময় ফাংশনের নামের ডটের আগে যে অবজেক্ট নামটা থাকবে তার ভ্যালুই দেখাবে। হ্যাঁ, আমি যদিও অবজেক্টের ভিতরে থাকা ফাংশনকে ফাংশন বলতেছি শুধু বোঝার সুবিধার জন্যে। এটা ফাংশন হবে না, কারণ অবজেক্টের ভিতরে থাকা সব ফাংশনকে বলা হয় মেথড। উপরের কোডের আউটপুট হবে নিচের দেওয়া স্নিপেটের মত। +এইবার বলুন তো উপরের কোডটির আউটপুট কি হবে। যারা বলতে পারবেন তাদের জন্যে থাকবে আমার পক্ষ থেকে একটি চকলেট। যদি উপরের বলা কথাগুলা ভালো করে পড়ে থাকেন, বুঝতে কোন অসুবিধা হওয়ার কথা না উপরের কোডের আউটপুট কি হবে। শুধু একটা কথা ভালো করে মনে রাখবেন কোন ফাংশন কল করার সময় ফাংশনের নামের ডটের আগে যে অবজেক্ট নামটা থাকবে তার ভ্যালুই দেখাবে। হ্যাঁ, আমি যদিও অবজেক্টের ভিতরে থাকা ফাংশনকে ফাংশন বলতেছি শুধু বোঝার সুবিধার জন্যে। এটা ফাংশন হবে না, কারণ অবজেক্টের ভিতরে থাকা সব ফাংশনকে বলা হয় মেথড। উপরের কোডের আউটপুট হবে নিচের দেওয়া স্নিপেটের মত। ``` {name: "Shahan's Diary", sayName: f} @@ -59,4 +59,4 @@ person1.sayInfo(); // Hi there, Welcome to Shahan's Diary ``` -আশা করি, আপনাদের “this” এর বেসিক ধারণটা এখন পরিষ্কার হয়েছে। এখন থেকে দেখলেই বুঝবেন যে “this” কি কাজ করছে। হ্যাঁ, এই লেখাটা পড়েই আপনি “this” এর মাস্টার হয়ে যাবেন না। এর আরেকটু অ্যাডভান্সড ব্যবহার রয়েছে। সেটা আপনাদের জন্যে রেখে দিলাম। একটু কষ্ট করে নিজ দায়িত্বে দেখে নিবেন। এরপরেও, যদি মাথার উপর দিয়ে যায় তাহলে কমেন্ট বক্সে কমেন্ট করে উড়াই দিবেন, আমি ধরে নিবো। হ্যাপি কোডিং.... \ No newline at end of file +আশা করি, আপনাদের “this” এর বেসিক ধারণাটা এখন পরিষ্কার হয়েছে। এখন থেকে দেখলেই বুঝবেন যে “this” কি কাজ করছে। হ্যাঁ, এই লেখাটা পড়েই আপনি “this” এর মাস্টার হয়ে যাবেন না। এর আরেকটু অ্যাডভান্সড ব্যবহার রয়েছে। সেটা আপনাদের জন্যে রেখে দিলাম। একটু কষ্ট করে নিজ দায়িত্বে দেখে নিবেন। এরপরেও, যদি মাথার উপর দিয়ে যায় তাহলে কমেন্ট বক্সে কমেন্ট করে উড়াই দিবেন, আমি ধরে নিবো। হ্যাপি কোডিং.... \ No newline at end of file diff --git a/basic/8. event-capturing-and-bubbling/README.md b/basic/8. event-capturing-and-bubbling/README.md index c5663cd..216b8fc 100644 --- a/basic/8. event-capturing-and-bubbling/README.md +++ b/basic/8. event-capturing-and-bubbling/README.md @@ -1,11 +1,11 @@ ### Event capturing and bubbling -ইভেন্ট bubbling এবং ক্যাপচারিং HTML DOM API-এ ইভেন্ট প্রচারের দুটি উপায়, যখন একটি event অন্য element এর ভিতরে একটি element এ ঘটে, এবং উভয় element সেই ইভেন্টের জন্য একটি হ্যান্ডেল নিবন্ধিত করেছে. ইভেন্ট propagation মোড নির্ধারণ করে কোন ক্রমে elements গুলি ইভেন্টটি গ্রহণ করে. bubbling এ, event টি প্রথমে অন্তরতম element দ্বারা বন্দী এবং পরিচালনা করা হয় এবং তারপরে বাইরের element গুলিতে প্রচার করা হয়. Capturing এ, event টি সর্বপ্রথম বাইরের element দ্বারা ধারণ করা হয় এবং ভিতরের element গুলিতে প্রচার করা হয়. আমরা ব্যবহার করতে পারি addEventListener(type, listener, useCapture) bubbling(ডিফল্ট) বা ক্যাপচারিং মোডে ইভেন্ট হ্যান্ডলারদের নিবন্ধন করতে. ক্যাপচারিং মডেল ব্যবহার করতে তৃতীয় যargument টিকে true হিসাবে পাস করুন. +ইভেন্ট bubbling এবং ক্যাপচারিং HTML DOM API-এ ইভেন্ট প্রচারের দুটি উপায়, যখন একটি event অন্য element এর ভিতরে একটি element এ ঘটে, এবং উভয় element সেই ইভেন্টের জন্য একটি হ্যান্ডেল নিবন্ধিত করেছে. ইভেন্ট propagation মোড নির্ধারণ করে কোন ক্রমে elements গুলি ইভেন্টটি গ্রহণ করে. bubbling এ, event টি প্রথমে অন্তরতম element দ্বারা বন্দী এবং পরিচালনা করা হয় এবং তারপরে বাইরের element গুলিতে প্রচার করা হয়. Capturing এ, event টি সর্বপ্রথম বাইরের element দ্বারা ধারণ করা হয় এবং ভিতরের element গুলিতে প্রচার করা হয়. আমরা ব্যবহার করতে পারি addEventListener(type, listener, useCapture) bubbling(ডিফল্ট) বা ক্যাপচারিং মোডে ইভেন্ট হ্যান্ডলারদের নিবন্ধন করতে. ক্যাপচারিং মডেল ব্যবহার করতে তৃতীয় argument টিকে true হিসাবে পাস করুন. -উদাহরণ -``` +উদাহরণঃ +```html
- +
``` উপরের কাঠামোতে, অনুমান করুন যে button element টিতে একটি ক্লিক ইভেন্ট ঘটেছে। @@ -16,7 +16,7 @@ bubbling মডেলে, বিপরীত ঘটবে: ইভেন্টট ইভেন্ট ক্যাপচারিং-এ, একটি ইভেন্ট সবচেয়ে বাইরের element থেকে target এ চলে যায়. ইভেন্ট bubbling করার আগে ইভেন্ট ক্যাপচারিং করা হয় কিন্তু ক্যাপচারিং খুব কমই ব্যবহার করা হয় কারণ ইভেন্ট bubbling ইভেন্ট ফ্লো পরিচালনা করার জন্য যথেষ্ট। ইভেন্ট ক্যাপচারিং এর কাজ বোঝার জন্য একটি উদাহরণ কোড দেখি: -``` +```html
@@ -28,7 +28,8 @@ bubbling মডেলে, বিপরীত ঘটবে: ইভেন্টট parent.addEventListener('click', function(){ console.log("Parent is invoked"); - },true); + }, true); + child.addEventListener('click', function(){ console.log("Child is invoked"); }); @@ -52,23 +53,24 @@ bubbling মডেলে, বিপরীত ঘটবে: ইভেন্টট ![image](https://user-images.githubusercontent.com/712313/142607966-a0227a6c-f5aa-4077-a694-6874fd34fe5c.png) #### Evnet Bubbling: -ইভেন্ট bubling এর কাজের ধারণাটি বোঝার জন্য আসুন নীচের উদাহরণটি দেখি: -``` +ইভেন্ট bubbling এর কাজের ধারণাটি বোঝার জন্য আসুন নীচের উদাহরণটি দেখি: +```html
``` @@ -76,17 +78,17 @@ bubbling মডেলে, বিপরীত ঘটবে: ইভেন্টট ![image](https://user-images.githubusercontent.com/712313/142606233-d0f93544-18dc-49e1-83e5-4d636f61d46e.png) -- আমরা div id = p1 সহ একটি div ট্যাগ ব্যবহার করেছি এবং div-এর মধ্যে আমরা একটি button নেস্ট করেছি যার বাটন id = c1 আছে। -- এখনে আমরা querySelector () ফাংশন ব্যবহার করে html element গুলি (p1 এবং c1) ভেরিয়েবল প্যারেন্ট এবং চাইল্ডকে assign করেছি। -- এর পরে, আমরা একটি ইভেন্ট তৈরি করেছি এবং অন্তর্ভুক্ত করেছি যা div এলিমেন্ট এবং চাইল্ড button উভয়ের জন্য ক্লিক ইভেন্ট। এছাড়াও দুটি ফাংশন তৈরি করেছে যা আমাদের paent এবং child execution এর order জানতে সাহায্য করবে। এর অর্থ হল যদি চাইল্ড ইভেন্টটি প্রথমে invoke হয়, "Child is invoked" প্রিন্ট করা হবে অন্যথায় "parent is invoked" print হবে। -- এইভাবে, button টি ক্লিক করা হলে, এটি প্রথমে প্রিন্ট করবে "Child is invoked" যার মানে হল যে child ইভেন্ট হ্যান্ডলারের মধ্যে ফাংশনটি প্রথমে কার্যকর করে। তারপর এটি ডিভ প্যারেন্ট ফাংশনের invoke এ চলে যায়। +- আমরা div id = p1 সহ একটি div ট্যাগ ব্যবহার করেছি এবং div-এর মধ্যে আমরা একটি button নেস্ট করেছি যার id = c1 আছে। +- এখনে আমরা querySelector() ফাংশন ব্যবহার করে html element গুলিকে (p1 এবং c1) যথাক্রমে parent এবং child নামক দুটি ভেরিয়েবলে assign করেছি। +- এর পরে, আমরা div ও button উভয়ের জন্য একটি করে ক্লিক ইভেন্ট তৈরি করেছি এবং কলব্যাক ফাংশন হিসেবে দুটি ফাংশন তৈরি করেছি যা আমাদের parent এবং child execution এর order জানতে সাহায্য করবে। এর অর্থ হল যদি চাইল্ড ইভেন্টটি প্রথমে কল হয়, "Child is invoked" লেখাটি ব্রাউজারের console -এ প্রিন্ট হবে অন্যথায় "Parent is invoked" প্রিন্ট হবে। +- এখন button টি ক্লিক করা হলে এটি প্রথমে "Child is invoked" প্রিন্ট করবে এবং পরে "Parent is invoked" প্রিন্ট করবে, অর্থাৎ প্রথমে button এর ইভেন্ট হ্যান্ডলার কাজ করবে তারপর div এর ইভেন্ট হ্যান্ডলারটি কাজ করবে। -ইভেন্ট bubling এর কারণে sequence টি ঘটেছে। সুতরাং, এই ভাবে event bubling সঞ্চালিত হয়. এর মানে ব্যবহারকারী যখন button এ ক্লিক করেন, ক্লিক ইভেন্ট এই ক্রমে নীচে থেকে উপরে প্রবাহিত হয়। নিচের ফ্লো চার্টের সাহায্যে আমরা ইভেন্টের প্রবাহও বুঝতে পারি: +ইভেন্ট bubbling এর কারণে এই ধরনের sequence টি ঘটেছে আর এভাবেই event bubbling সঞ্চালিত হয়। এর মানে ব্যবহারকারী যখন button এ ক্লিক করেন, ক্লিক ইভেন্ট এই ক্রমে নীচে থেকে উপরে প্রবাহিত হয়। নিচের ফ্লো চার্টের সাহায্যে আমরা ইভেন্টের প্রবাহ বুঝতে পারি: ![image](https://user-images.githubusercontent.com/712313/142606596-d3f2f583-6c89-41d7-b51a-17896f57a89e.png) -নীচের diagram টি ইভেন্ট প্রবাহের সম্পাদন দেখায়: +একটি ইভেন্টের সম্পূর্ণ প্রবাহ কিভাবে সম্পাদন হয় নীচের diagram টি দ্বারা সেটি দেখানো হলো: ![image](https://user-images.githubusercontent.com/712313/142607997-8b6caa69-3d3d-446c-a223-724218ff532e.png) diff --git a/basic/9. event-delegation-and-propagation/README.md b/basic/9. event-delegation-and-propagation/README.md index 6045c5e..1d67549 100644 --- a/basic/9. event-delegation-and-propagation/README.md +++ b/basic/9. event-delegation-and-propagation/README.md @@ -5,7 +5,8 @@ ### Event propagation আপনি যখন নিম্নলিখিত HTML এর button টি ক্লিক করেনঃ -``` + +```html
@@ -25,14 +26,16 @@ ![image](https://user-images.githubusercontent.com/712313/143814244-4e801a09-f50f-4d87-8503-2686d5f0f1db.png) নিম্নলিখিত ইভেন্ট হ্যান্ডলার element এ সংঘটিত ক্যাপচার পর্বে ক্লিক ইভেন্টের জন্য শোনে - ``` + + ```javascript document.body.addEventListener('click', () => { console.log('Body click event in capture phase'); }, true); ``` নিচের method এর তৃতীয় আর্গুমেন্ট হল `captureOrOptions` আপনাকে বিভিন্ন পর্যায় থেকে ইভেন্টগুলি ধরতে দেয়: -``` + +```javascript element.addEventListener(eventType, handler, [captureOrOptions]); ``` @@ -46,7 +49,7 @@ element.addEventListener(eventType, handler, [captureOrOptions]); ### Event delegation আসুন একাধিক button এ ক্লিকগুলি ধরতে ইভেন্ট delegation ব্যবহার করি: - ``` + ```html
@@ -65,29 +68,26 @@ element.addEventListener(eventType, handler, [captureOrOptions]); -ইভেন্ট delegation mechanism টি অনেক সহজ. ইভেন্ট listener দের সরাসরি button গুলিতে সংযুক্ত করার পরিবর্তে, আপনি parent
listen delegate করেন। যখন একটি এ ক্লিক করা হয়, তখন মূল element টির listener bubble ইভেন্টটি ধরে। +ইভেন্ট delegation mechanism টি অনেক সহজ, ইভেন্ট listener দের সরাসরি button গুলিতে সংযুক্ত করার পরিবর্তে, আপনি parent element `
` -এ ইভেন্ট listen delegate করেন। যখন একটি ক্লিক করা হয়, তখন মূল element টির listener (parent element টির listener) bubble ইভেন্টটি ধরে। ইভেন্ট delegation ব্যবহার করার জন্য 3টি পদক্ষেপ প্রয়োজন: -**Step 1. ইভেন্টগুলি দেখার জন্য element গুলির parent নির্ধারণ করুন৷** -উপরের উদাহরণে,
হল button গুলির parent element +**Step 1. ইভেন্টগুলি ধরার জন্য element গুলির parent নির্ধারণ করুন**
+(উপরের উদাহরণে, `
` হল button গুলির parent element) **Step 2. ইভেন্ট listener কে মূল element এর সাথে সংযুক্ত করুন** - -```document.getElementById('buttons').addEventListener('click', handler)``` +`document.getElementById('buttons').addEventListener('click', handler)` ইভেন্টটি লিসেনারকে button এর parent element এর সাথে সংযুক্ত করে। এই listener button ক্লিকে প্রতিক্রিয়া দেখায় কারণ button ক্লিক ইভেন্ট ancestor এর মাধ্যমে bubble করে event propagation এর কারণে। -**Step 3. target element নির্বাচন করতে event.target ব্যবহার করুন** - -যখন একটি button ক্লিক করা হয়, হ্যান্ডলার ফাংশন একটি event object argument এর সঙ্গে invoke হয়. event.target.property হল সেই element যার উপর ইভেন্টটি পাঠানো হয়েছে, যা উদাহরণে একটি button -``` + +**Step 3. target element নির্বাচন করতে event.target ব্যবহার করুন**
+যখন একটি button ক্লিক করা হয়, হ্যান্ডলার ফাংশন একটি event object argument এর সঙ্গে invoke হয়, event.target.property হল সেই element যার উপর ইভেন্টটি পাঠানো হয়েছে, যা উদাহরণে একটি button + +```javascript .addEventListener('click', event => { if (event.target.className === 'buttonClass') { console.log('Click!'); } }); -``` - - `event.currentTarget` সেই element টিকে নির্দেশ করে যেখানে ইভেন্ট listener সরাসরি সংযুক্ত থাকে। উদাহরণে, `event.currentTarget` হল `
`। - - - +``` + +`event.currentTarget` সেই element টিকে নির্দেশ করে যেখানে ইভেন্ট listener সরাসরি সংযুক্ত থাকে। উদাহরণে, `event.currentTarget` হল `
`। diff --git a/projects/README.md b/projects/README.md index 243b4ee..de4d671 100644 --- a/projects/README.md +++ b/projects/README.md @@ -2,8 +2,9 @@ This repository contains all the projects for VivaSoft Javascript Bootcamp. -| # | Project | Live Demo | -| :-: | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | -| 01 | [Expanding Cards](expanding-cards) | [Live Demo](https://blackbox47.github.io/expanding-cards/) | -| 02 | [Modal](modal) | [Live Demo](https://saroarshahan.github.io/modal/) | -| 03 | [Big Bang](big-bang) | [Live Demo](https://blackbox47.github.io/big-bang/) | +| # | Project | Live Demo | +| :-: | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | +| 01 | [Expanding Cards](https://github.com/vivasoft-ltd/javascript-bootcamp/tree/develop/projects/expanding-cards) | [Live Demo](https://blackbox47.github.io/expanding-cards/) | +| 02 | [Big Bang](https://github.com/vivasoft-ltd/javascript-bootcamp/tree/develop/projects/big-bang) | [Live Demo](https://blackbox47.github.io/big-bang/) | +| 03 | [Snake Eye](https://github.com/vivasoft-ltd/javascript-bootcamp/tree/develop/projects/snake-eye) | [Live Demo](https://blackbox47.github.io/snake-eye/) | +| 03 | [Blurry Loading](https://github.com/vivasoft-ltd/javascript-bootcamp/tree/develop/projects/blurry-loading) | [Live Demo](https://blackbox47.github.io/blurry-loading/) | diff --git a/projects/blurry-loading/index.html b/projects/blurry-loading/index.html index e69de29..99ff943 100644 --- a/projects/blurry-loading/index.html +++ b/projects/blurry-loading/index.html @@ -0,0 +1,15 @@ + + + + + + + Blurry Loading + + +
+
0%
+ + + + diff --git a/projects/blurry-loading/script.js b/projects/blurry-loading/script.js index e69de29..20e75ec 100644 --- a/projects/blurry-loading/script.js +++ b/projects/blurry-loading/script.js @@ -0,0 +1,22 @@ +const loadText = document.querySelector('.loading-text') +const bg = document.querySelector('.bg') + +let load = 0 + +let int = setInterval(blurring, 30) + +function blurring() { + load++ + + if (load > 99) { + clearInterval(int) + } + + loadText.innerText = `${load}%` + loadText.style.opacity = scale(load, 0, 100, 1, 0) + bg.style.filter = `blur(${scale(load, 0, 100, 30, 0)}px)` +} + +const scale = (num, in_min, in_max, out_min, out_max) => { + return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min +} \ No newline at end of file diff --git a/projects/blurry-loading/style.css b/projects/blurry-loading/style.css index e69de29..1aebd3d 100644 --- a/projects/blurry-loading/style.css +++ b/projects/blurry-loading/style.css @@ -0,0 +1,32 @@ +@import url('https://fonts.googleapis.com/css?family=Ubuntu'); + +* { + box-sizing: border-box; +} + +body { + font-family: 'Ubuntu', sans-serif; + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + overflow: hidden; + margin: 0; +} + +.bg { + background: url('https://images.unsplash.com/photo-1657839368752-00f5f6dd8592?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80') + no-repeat center center/cover; + position: absolute; + top: -30px; + left: -30px; + width: calc(100vw + 60px); + height: calc(100vh + 60px); + z-index: -1; + filter: blur(0px); +} + +.loading-text { + font-size: 50px; + color: #fff; +} \ No newline at end of file diff --git a/projects/snake-eye/index.html b/projects/snake-eye/index.html new file mode 100644 index 0000000..6505751 --- /dev/null +++ b/projects/snake-eye/index.html @@ -0,0 +1,15 @@ + + + + + + + Snake Eye + + + + + + + + diff --git a/projects/snake-eye/index.js b/projects/snake-eye/index.js new file mode 100644 index 0000000..f21ddc0 --- /dev/null +++ b/projects/snake-eye/index.js @@ -0,0 +1,127 @@ +const canvas = document.querySelector("canvas"); +canvas.width = innerWidth; +canvas.height = innerHeight; + +let canvasW, canvasH; +canvasW = canvas.width; +canvasH = canvas.height; + +let eyes = [], + delta, + numberOfEyes = 300; +const ctx = canvas.getContext("2d"); + +console.log(canvas); + +const mouse = { + x: undefined, + y: undefined, +}; + +window.addEventListener("mousemove", function (e) { + mouse.x = e.x; + mouse.y = e.y; +}); + +class Eye { + constructor(eye) { + this.x = eye.x; + this.y = eye.y; + this.radius = eye.radius; + } + draw() { + ///// Eye + ctx.fillStyle = "red"; + ctx.beginPath(); + ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI); + ctx.fill(); + ctx.closePath(); + + ///// Get Angle between mouse and (Irish and Pupil) + let dx = mouse.x - this.x; + let dy = mouse.y - this.y; + delta = Math.atan2(dy, dx); + + //// Irish + let irish_x = this.x + Math.cos(delta) * (this.radius / 10); + let irish_y = this.y + Math.sin(delta) * (this.radius / 10); + let irish_radius = this.radius / 1.2; + ctx.beginPath(); + ctx.fillStyle = "white"; + ctx.arc(irish_x, irish_y, irish_radius, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.closePath(); + + //// Pupil + let pupil_x = this.x + Math.cos(delta) * (this.radius / 2); + let pupil_y = this.y + Math.sin(delta) * (this.radius / 2); + let pupil_radius = this.radius / 2.5; + ctx.beginPath(); + ctx.fillStyle = "black"; + ctx.arc(pupil_x, pupil_y, pupil_radius, 0, 2 * Math.PI); + ctx.fill(); + ctx.closePath(); + + //// pupil reflection + ctx.beginPath(); + ctx.arc( + pupil_x - pupil_radius / 3, + pupil_y - pupil_radius / 3, + pupil_radius / 2, + 0, + 2 * Math.PI + ); + ctx.fillStyle = "rgba(255,255,255,0.1)"; + ctx.fill(); + ctx.closePath(); + + //// Mouse + ctx.beginPath(); + ctx.fillStyle = "gold"; + ctx.arc(mouse.x, mouse.y, 25, 0, 2 * Math.PI); + ctx.fill(); + ctx.closePath(); + } +} + +function init() { + eyes = []; + for (let ind = 0; ; ind++) { + if (eyes.length >= numberOfEyes) break; + let eye = { + radius: Math.floor(Math.random() * 100 + 5), + x: Math.random() * canvasW, + y: Math.random() * canvasH, + }; + let flag = 0; + for (let i = 0; i < eyes.length; i++) { + let previousEye = eyes[i]; + let dx = previousEye.x - eye.x; + let dy = previousEye.y - eye.y; + let distance = Math.sqrt(dx * dx + dy * dy); + if (distance < previousEye.radius + eye.radius) { + flag = 1; + break; + } + } + if (flag === 0) eyes.push(new Eye(eye)); + } + console.log(eyes); +} + +function animate() { + requestAnimationFrame(animate); + ctx.clearRect(0, 0, canvasW, canvasH); + for (let i = 0; i < eyes.length; i++) { + eyes[i].draw(); + } +} + +window.addEventListener("resize", function (e) { + canvas.width = innerWidth; + canvas.height = innerHeight; + init(); +}); + +init(); +animate();