Repository: vivasoft-ltd/javascript-bootcamp Branch: main Commit: b3689376f7c1 Files: 226 Total size: 213.3 KB Directory structure: gitextract_xiiafr5j/ ├── .gitignore ├── README.md ├── advanced/ │ ├── 1. call-apply-bind-methods/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ ├── example5.js │ │ │ └── example6.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ └── practice2.md │ │ └── README.md │ ├── 2. factory-pattern/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ └── example5.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ ├── practice2.md │ │ │ └── practice3.md │ │ └── README.md │ ├── 3. constructor-pattern/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ ├── example5.js │ │ │ └── example6.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ ├── practice2.md │ │ │ └── practice3.md │ │ └── README.md │ ├── 4. prototype/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ ├── example5.js │ │ │ └── example6.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ ├── practice2.md │ │ │ └── practice3.md │ │ └── README.md │ ├── 5. prototypical-inheritance/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.md │ │ │ ├── example2.md │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ ├── example5.js │ │ │ └── example6.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ └── practice2.md │ │ └── README.md │ ├── 6. event-loop/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ └── example5.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ ├── practice2.md │ │ │ └── practice3.md │ │ └── README.md │ ├── 7. garbage-collector/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ ├── example5.js │ │ │ └── example6.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ ├── practice2.md │ │ │ └── practice3.md │ │ └── README.md │ └── README.md ├── basic/ │ ├── 1. execution-context/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ ├── example5.js │ │ │ ├── example6.js │ │ │ └── stackOverflow.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ └── practice2.md │ │ └── README.md │ ├── 10. browser-storage-and-caching/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ └── example2.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 11. debouncing-and-throttling/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.html │ │ │ └── example2.html │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 12. use-strict/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ └── example2.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 13. iife-in-javascript/ │ │ ├── Examples/ │ │ │ ├── example1.js │ │ │ └── example2.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 2. scope/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ └── example4.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 3. hoisting/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ ├── example5.js │ │ │ ├── example6.js │ │ │ └── example7.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 4. closure/ │ │ ├── Examples/ │ │ │ ├── Anonymous_fn_with_lexical_scope.js │ │ │ ├── Closure_In_InnerFunction.js │ │ │ ├── README.md │ │ │ ├── closure.js │ │ │ ├── closure_scope_chain.js │ │ │ ├── emulating_private_methods_with_closures.js │ │ │ ├── example_for_understand_usecase_of_closure.js │ │ │ └── solve_var_functional_scope_issue_using_closure.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 5. call-by-value-and-call-by-reference/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ ├── example3.js │ │ │ ├── example4.js │ │ │ └── example5.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ └── practice2.md │ │ └── README.md │ ├── 6. callback-and-higher-order-functions/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.js │ │ │ ├── example2.js │ │ │ └── example3.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 7. this-keyword/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── this_in_constructor_invocation.js │ │ │ ├── this_in_function_context_with_use_strict.js │ │ │ ├── this_in_function_context_without_use_strict.js │ │ │ ├── this_in_global_context.js │ │ │ ├── this_in_method_invocation.js │ │ │ └── this_in_method_invocation_with_bind.js │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ ├── 8. event-capturing-and-bubbling/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.md │ │ │ ├── example2.md │ │ │ ├── example3.md │ │ │ └── example4.md │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ ├── practice1.md │ │ │ └── practice2.md │ │ └── README.md │ ├── 9. event-delegation-and-propagation/ │ │ ├── Examples/ │ │ │ ├── README.md │ │ │ ├── example1.md │ │ │ ├── example2.md │ │ │ └── example3.md │ │ ├── Interview Questions/ │ │ │ └── README.md │ │ ├── Practices/ │ │ │ ├── README.md │ │ │ └── practice1.md │ │ └── README.md │ └── README.md └── projects/ ├── README.md ├── big-bang/ │ ├── index.html │ └── index.js ├── blurry-loading/ │ ├── index.html │ ├── script.js │ └── style.css ├── expanding-cards/ │ ├── index.html │ ├── script.js │ └── style.css ├── modal/ │ ├── app.js │ ├── index.html │ └── style.css └── snake-eye/ ├── index.html └── index.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # General .DS_Store .AppleDouble .LSOverride .idea .cloud .project tmp/ typings/ # Visual Studio Code .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json ================================================ FILE: README.md ================================================ # JavaScript Bootcamp ## উদ্দেশ্য: জাভাস্ক্রিপ্ট শেখার জন্য নতুনদের পাশাপাশি মিড লেভেল JS ডেভেলপারদের জন্য একটি রোডম্যাপ তৈরি করা। ## To get started: 1. [Basic](basic) 2. [Advanced](advanced) 3. [Projects](projects) ================================================ FILE: advanced/1. call-apply-bind-methods/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/1. call-apply-bind-methods/Examples/example1.js ================================================ const person = { firstName: "Anik", lastName: "Sajli", getFullName: function() { var fullName = this.firstName + " " + this.lastName; return fullName; } } function printName(favoriteFood) { console.log(this.getFullName() + ` loves to eat ${favoriteFood}`); } // This bind method returns a new function which has it's "this" keyword set to the // provided value in the bind method. // bind() method example: const logName = printName.bind(person, "Pine apple"); // Anik Sajli loves to eat Pine apple logName(); // * call method executes the function immediately // * doesn't make any copy of the function // * call method takes additional parameters as well // call() method example: printName.call(person, "Apple"); // Anik Sajli loves to eat Apple // the difference between call() and apply() method is call() method accepts // comma seperated arguments whereas apply method expects the parameters in an array // apply() method example: printName.apply(person, ["Orange"]); // Anik Sajli loves to eat Orange ================================================ FILE: advanced/1. call-apply-bind-methods/Examples/example2.js ================================================ { /* We can achieve constructor chaining by using call() and apply(). We can pick common properties from another constructor function to be included in our new constructor function by using these methods. */ } function Food(name, price) { this.name = name; this.price = price; } function Burger(name, price) { Food.call(this, name, price); this.category = "fastfood"; } function Brownie(name, price) { Food.call(this, name, price); this.category = "dessert"; } burger = new Burger("Hamburger", "300"); brownie = new Brownie("Chocolate brownie", "200"); console.log(burger); console.log(brownie); { /* Output: { category: "fastfood" name: "Hamburger" price: "300" } { category: "dessert" name: "Chocolate brownie" price: "200" } */ } // The same behavior can also be achieved by using the apply() method function Pizza(name, price) { Food.apply(this, [name, price]); this.category = "fastfood"; } pizza = new Pizza("Pepperoni Pizza", "500"); console.log(pizza); { /* Output: { category: "fastfood" name: "Pepperoni Pizza" price: "500" } */ } ================================================ FILE: advanced/1. call-apply-bind-methods/Examples/example3.js ================================================ /* call(), bind() and apply() methods are used for several reasons. Some of them are: 1. Create custom value of "this" 2. Borrowing another objects methods which means invoking an object’s method on a totally different object */ /* call() Method - The first parameter of call() method is an object on which "this" will point to - Other parameters are variables */ let Team = { getStatistics : function(league, season){ return this.name + " are " +this.position+ " in "+ league+" with "+this.points+" points in season "+season; } } let RealMadrid = { name: "Real Madrid", position: "1st", points: 46 } let Barcelona = { name: "FC Barcelona", position: "5th", points: 31 } console.log(Team.getStatistics.call(RealMadrid, "Laliga", "2022")); // Here we set "this" of getStatistics method to RealMadrid object // Output: Real Madrid are 1st in Laliga with 46 points in season 2022 console.log(Team.getStatistics.call(Barcelona, "Laliga", "2022")); // Here we set "this" of getStatistics method to Barcelona object // Output: FC Barcelona are 5th in Laliga with 31 points in season 2022 /* apply() Method - The first parameter of apply() method is an object on which "this" will point to - The second parameter of the apply() method accepts the arguments as an array. - Which is the only difference between call() and apply() */ let others = ["Laliga", "2022"]; console.log(Team.getStatistics.apply(RealMadrid, others)); // Here we set "this" of getStatistics method to RealMadrid object // On 2nd parameter we used an array to produce the same output // Output: Real Madrid are 1st in Laliga with 46 points in season 2022 /* bind() method - bind() method is like call() method but it returns a bound function which will be invoked later */ let result = Team.getStatistics.bind(Barcelona, "Laliga", "2022"); console.log(result()) // Output: FC Barcelona are 5th in Laliga with 31 points in season 2022 // Here we stored the bound function in the result variable // Then we invoked the returned function later ================================================ FILE: advanced/1. call-apply-bind-methods/Examples/example4.js ================================================ // Here are some other use of call(), bind() and apply() methods /* We can use call() to Invoke an Anonymous Function */ const sports = [ { name: 'Cricket' }, { name: 'Football' } ]; for(let i=0;i { console.log("Student name: " + name + "\n" + "Department name: " + dept + "\n" + "Roll number: " + roll); } } return student; } const student1 = studentFactory("Anik", "Software Engineering", "2016831008"); student1.printStudentDetails(); // output: // Student name: Anik // Department name: Software Engineering // Roll number: 2016831008 ================================================ FILE: advanced/2. factory-pattern/Examples/example2.js ================================================ { /* let's say a company has three types of employees and the salary for those three positions are predefined. We can create the employee objects by using the factory pattern. Constructor pattern has also been used in this example for creating certain objects. However, the employeeFactory() function has followed the factory pattern to create employee objects. */ } function employeeFactory(employeeType, employeeName) { let employee; if (employeeType === "fulltime") { employee = new fulltimeEmployee(employeeName); } else if(employeeType === "parttime") { employee = new parttimeEmployee(employeeName); } else if (employeeType === "temporary") { employee = new temporaryEmployee(employeeName); } employee.printEmployeeDetails = () => { console.log("Name: " + employee.name + "\n" + "Salary: " + employee.salary + "\n" + "Employee Type: " + employee.employeeType) } return employee; } function fulltimeEmployee(employeeName) { this.name = employeeName; this.salary = 50000; this.employeeType = "Fulltime Employee"; } function parttimeEmployee(employeeName) { this.name = employeeName; this.salary = 30000; this.employeeType = "Parttime Employee"; } function temporaryEmployee(employeeName) { this.name = employeeName; this.salary = 25000; this.employeeType = "Temporary Employee"; } employee1 = employeeFactory("fulltime", "Fahim"); employee1.printEmployeeDetails(); // output: // Name: Fahim // Salary: 50000 // Employee Type: Fulltime Employee ================================================ FILE: advanced/2. factory-pattern/Examples/example3.js ================================================ /* Its easy to define private methods or property in a factory. We just need to include them outside of the returned object. */ function person (name) { function sayDetail(){ return name + " who loves travelling"; } return { talk: function(){ console.log('Hello, my name is '+sayDetail()) } } } /* Here in this code sayDetail() is closed inside factory. This helps us to keep our implementation details encapsulated. */ let person1 = person("Mehedi"); person1.talk() // Output: Hello, my name is Mehedi who loves travelling person1.sayDetail() // Output: TypeError: person1.sayDetail is not a function ================================================ FILE: advanced/2. factory-pattern/Examples/example4.js ================================================ //Factory Pattern মেথড ব্যাবহার করার উদাহরণ //Live: https://jsfiddle.net/rijans/zhLcbepo/5/ function makePersonalHomePage(metaTitle) { return { meta_title: metaTitle, make_html: function () { console.log('A page with the title of ' + this.meta_title + ' is made!') } } } const homePageOfJaber = makePersonalHomePage('Jaber\'s Home'); console.log(homePageOfJaber.make_html()); const homePageOfVivaSoft = makePersonalHomePage('VivaSoft\'s Home'); console.log(homePageOfVivaSoft.make_html()); //ফলাফল: //A page with the title of Jaber's Home is made!" //A page with the title of VivaSoft's Home is made!" ================================================ FILE: advanced/2. factory-pattern/Examples/example5.js ================================================ //Factory Pattern মেথড ব্যাবহার করার উদাহরণ //Live: https://jsfiddle.net/rijans/vr31aj7x/ function buildCustomPC(cpu, ram, motherBoard, others) { return { cpu: cpu, ram: ram, motherBoard: motherBoard, others: others, buildPC: function () { console.log('A PC with RAM ' + ram + ', CPU ' + cpu + ' and motherboard ' + motherBoard + ' is built!') } } } const pc1 = buildCustomPC('Core i7 11700', 'Corsair 16GB 3200GHz', 'Asus Gaming G8', {}); console.log(pc1.buildPC()); const pc2 = buildCustomPC('Apple M1 Pro', 'TSC 16GB Module', 'Foxcon M1 Mainboard', {}); console.log(pc2.buildPC()); //ফলাফল: //"A PC with RAM Corsair 16GB 3200GHz, CPU Core i7 11700 and motherboard Asus Gaming G8 is built!" //"A PC with RAM TSC 16GB Module, CPU Apple M1 Pro and motherboard Foxcon M1 Mainboard is built!" ================================================ FILE: advanced/2. factory-pattern/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/2. factory-pattern/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/2. factory-pattern/Practices/practice1.md ================================================ Consider the below code where we have created 2 Vehicle objects on the fly. How can you improve this code by using the factory design pattern? ```javascript const Vehicle1 = { manufacturer: "Toyota", PlateNO: 12345, startEngine () {console.log("Starting engine."}, drive () {console.log("Driving car...")} } const Vehicle2 = { manufacturer: "Ford", PlateNO: 13345, startEngine () {console.log("Starting engine."}, drive () {console.log("Driving car...")} } ``` ================================================ FILE: advanced/2. factory-pattern/Practices/practice2.md ================================================ What will be the output of this code? How can we access the functions inside factory function? ```javascript function person (name, sport) { function saySport(){ return " who loves "+sport; } function sayName(){ return "My name is "+ name +saySport(); } return { talk: function(){ console.log('Hello, '+sayName()) } } } let person1 = person("Mehedi", "Cricket"); console.log(person1.saySport()) ``` ================================================ FILE: advanced/2. factory-pattern/Practices/practice3.md ================================================ নিচের কোড টি খেয়াল করুন। এটাতে factory pattern ব্যাবহার করা হয়েছে। আপনি কিভাবে এটাকে আর ভাল করতে পারেন? সাথে dynamic parameters দিয়ে? ```javascript function pc1() { return { manufacturer: "ASUS", cpu: "Intel Core i9 11900", ram: "Corsair 16GB 3200 GHz", buildPC: function () { console.log('A PC with manufacturer ' + this.manufacturer + ' CPU ' + this.cpu + ' RAM ' + this.ram + ' is built!'); } } } function pc2() { return { manufacturer: "MSI", cpu: "Apple M1 Pro Max", ram: "TSC 16GB 3600GHz", buildPC: function () { console.log('A PC with manufacturer ' + this.manufacturer + ' CPU ' + this.cpu + ' RAM ' + this.ram + ' is built!'); } } } let newPC1 = pc1(); console.log(newPC1.buildPC()); let newPC2 = pc2(); console.log(newPC2.buildPC()); ``` ================================================ FILE: advanced/2. factory-pattern/README.md ================================================ ### Factory Pattern আজকের আলোচনার বিষয় হচ্ছে জাভাস্ক্রিপ্টের Factory Pattern. জাভাস্ক্রিপ্ট প্রোগ্রামার বা ডেভেলপার হিসাবে Factory Pattern সম্পর্কে পরিষ্কার ধারণা থাকা খুব প্রয়োজন। তাই চেষ্টা করবো আজকে practical উদাহরণ দিয়ে এই মেথডকে নিয়ে আলোচনা করতে। আশা করি, আজকের পর থেকে এই Factory Pattern নিয়ে কাজ করতে কখনো সমস্যা হবে না। ধরা যাক, আমাদের কাছে একটি circle নামে একটি Object আছে। circle Object টিতে draw নামে একটি মেথড এবং radius নামে একটি variable আছে। ```js const circle = { radius: 1, draw: function draw() { console.log(`Circle radius is ${this.radius}`); }, }; console.log(circle.draw()); /// output: Circle radius is 1 ``` উপরের কোড থেকে দেখতে পাচ্ছি যে, circle Object এর draw মেথডটিকে call করে আমরা circle এর radius টি print করতে পারছি। এখন আমরা যদি circle2 নামে এ একই Functionality এর আরও একটি Object create করতে চাই তাহলে ঠিক একই রকম করে আবার নতুন করে Object এর structure টা লিখতে হবে। অনেকটা এই রকম করে, ```js const circle2 = { radius: 5, draw: function draw() { console.log(`Circle2 radius is ${this.radius}`); }, }; console.log(circle2.draw()); /// output: Circle2 radius is 5 ``` circle এবং circle2 এই দুইটি Object এর কোড যদি একটু লক্ষ্য করি তবে দেখব যে, এখানে বেশ repetative কোড আছে। তাছাড়া এখানে মাত্র একটি মেথড রয়েছে কিন্তু যদি এইখানে আরও অনেক মেথড থাকত এবং প্রত্যেক মেথডে অনেক কোড থাকত তবে আমাদের একই কোড বারবার লিখতে হত। এছাড়াও যদি কোনও মেথডের লজিক পরিবর্তন করার দরকার হয় তবে একাধিক জায়গায় কোড পরিবর্তন করতে হবে যা খুবই সময় সাপেক্ষ এবং বিরক্তিকর। তাই না। সুতরাং যদি আমাদের Object এ লজিক থাকে তবে আমাদের এখন ভিন্ন একটা পদ্ধতি দরকার যার মাধ্যমে আমরা Object বানাতে পারি। ঠিক এই সময়ে আমরা Factory বা Constructor ফাংশন ব্যবহার করি। এই আলোচনাতে আমরা Factory ফাংশন নিয়ে কথা বলব। ### Factory Pattern সহজভাবে বলতে গেলে, Factory Function এমন একটি ফাংশন যা Class বা new Keyword এর জটিলতা ছাড়াই Object তৈরি করতে পারে । অন্যভাবে বলতে গেলে, জাভাস্ক্রিপ্টের যেকোন Function-ই Object return করতে পারে কিন্তু যখন কোন Function এই একই কাজ new Keyword ছাড়া করতে পারে তাকেই আমরা Factory Function বলব। Factory Function ব্যবহার করে Object তৈরি করার প্রক্রিয়াই আসলে Factory Pattern. Factory যেমন বিভিন্ন জিনিস তৈরি করতে পারে ঠিক তেমনি জাভাস্ক্রিপ্টের Factory Function বিভিন্ন Object তৈরি করতে পারে। জটিল মনে হলেও ভয় পাওয়ার কিছু নেই একটা উদাহরণ দেখলে সব ক্লিয়ার হয়ে যাবে। প্রথমে আমারা একটি Function বানাবো যার নাম হবে createCircle. ```js function createCircle(){ } ``` এরপর createCircle Factory Function এর মধ্যে আমরা আমাদের circle Object এর Defination টা বসিয়ে return করব। ```js function createCircle(){ const circle = { radius: 1, draw: function draw() { console.log(`Circle radius is ${this.radius}`); }, }; return circle; } ``` এখন যখনই আমরা createCircle Factory Function কে call করব আমরা একটা circle Object পাব। কিন্তু আমারা এখানে circle Object এর radius এর মানটা hardcoded করে রেখেছি ফলে যে circle Object তৈরি হবে তার radius সবসময় একই হবে। সুতরাং আমাদের কোডটাকে ডাইনামিক করতে হবে যাতে আমরা যে কোন radius এর circle Object তৈরি করতে পারি। এক্ষেত্রে আমরা createCircle Factory Function এ প্যারামিটার হিসেবে radius এর মানটা পাঠাতে পারি। ```js function createCircle(radius){ const circle = { radius: radius, draw: function draw() { console.log(`Circle radius is ${this.radius}`); }, }; return circle; } const circle1 = createCircle(5); console.log(circle1.draw()); // // output: Circle radius is 5 // // ``` Factory Function এর সৌন্দর্য হল আমরা আমাদের Object এর লজিকগুলো এক জায়গায় সংজ্ঞায়িত করেছি। সুতরাং আমরা এখন createCircle Factory Function কে বিভিন্ন মান বা বিভিন্ন আর্গুমেন্ট দিয়ে কল করে বিভিন্ন circle Object পেতে পারি। কিন্তু একটু লক্ষ্য করলে দেখা যাবে যে, আমরা draw মেথড শুধুমাত্র একটি জায়গায় সংজ্ঞায়িত করেছি। সুতরাং, যদি এই পদ্ধতিতে যদি কোন Bug থাকে যা ভবিষ্যতে আমাদের ঠিক করতে হবে সেখানে শুধুমাত্র একটি জায়গাতে সংশোধন করলেই হবে। নিচের উদাহরণটি দেখলে ব্যাপারটি আরও পরিষ্কার হবে। ```js function createCircle(radius){ const circle = { radius: radius, draw: function draw() { console.log(`Circle radius is ${this.radius}`); }, }; return circle; } const circle1 = createCircle(5); console.log(circle1.draw()); const circle2 = createCircle(10); console.log(circle2.draw()); // // output: // Circle radius is 5 // Circle radius is 10 // ``` উপরের কোড এর আউটপুটটা দেখুন, দুইটি circle Object তৈরি হয়েছে। এভাবে যত খুশি তত circle Object তৈরি করা যাবে। এই ছিল Factory Pattern নিয়ে আজকের লেখা। হ্যাপি কোডিং। ================================================ FILE: advanced/3. constructor-pattern/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/3. constructor-pattern/Examples/example1.js ================================================ { /* Counstructor pattern can be used to create new objects. As you may know that factory pattern can also be used for the same purpose. But the basic difference between these two process is in case of factory pattern the function returns an object but when we're using constructor pattern, we'll be using the 'new' keyword to create an empty object and then add our desired properties to that object with the help of 'this' keyword. In our code below, the 'this' keyword used in the CreateLaptop() function points to the empty object which is being created by the 'new' keyword below. */ } function CreateLaptop(brand, model, ram, storage) { this.brand = brand; this.model = model; this.ram = ram; this.storage = storage; this.toString = function(){ return `This ${this.brand} ${this.model} laptop has ${this.ram} RAM and ${this.storage} storage.` } } const laptop1 = new CreateLaptop("Dell", "Inspiron 15", "8 GB", "1 TB"); console.log(laptop1.toString()); { /* Output: This Dell Inspiron 15 laptop has 8 GB RAM and 1 TB storage. */ } ================================================ FILE: advanced/3. constructor-pattern/Examples/example2.js ================================================ { /* In the example below, we have used constructors with prototype. Just like any other objects in javascript, functions also contain 'prototype' objects. The two car objects (car1 and car2) that we created here will contain the same instance of the 'toString' property that we added to the 'prototype' object of 'Car'. */ } function Car(brand, model, price) { this.brand = brand; this.model = model; this.price = price; } Car.prototype.toString = function () { return this.brand + ' ' + this.model + " is worth " + this.price + " tk"; }; car1 = new Car('Toyota', 'Corolla', 2000000); car2 = new Car('Lamborghini', 'Silhouette', 30000000); console.log(car1.toString()); console.log(car2.toString()); { /* Output: Toyota Corolla is worth 2000000 tk Lamborghini Silhouette is worth 30000000 tk */ } ================================================ FILE: advanced/3. constructor-pattern/Examples/example3.js ================================================ /* Here 'mehedi' is an object of contructor function 'Person' and we can also add extra properties to the object which will not be property of constructor 'Person' */ function Person (firstName, lastName) { this.firstName = firstName; this.lastName = lastName; this.fullName =function () { return this.firstName + this.lastName; } } let mehedi = new Person("Mehedi", "Zamadar"); mehedi.age = 24; console.log(mehedi.age) // Output: 24 mehedi.hello = function (){ return "Hello"; } console.log(mehedi.hello()) // Output: Hello ================================================ FILE: advanced/3. constructor-pattern/Examples/example4.js ================================================ /* We know while using the constructor pattern, we need to manage the context of this by using the new keyword. There is another technique which avoids this. Which is using Closure with getters and setters. */ function Rectangle(length, width){ let _length = length; let _width = width; let rectangle = {}; rectangle.Area = function(){ return _length * _width; } // Getter/setters rectangle.Length = function(value){ if(!arguments.length) return _length; _length = value; return rectangle; } rectangle.Width = function(value){ if(!arguments.length) return _width; _width = value; return rectangle; } return rectangle; } let rectangle1 = Rectangle(10, 10); // no 'new' keyword console.log(rectangle1.Area()) // Output: 100 rectangle1.Length(100) rectangle1.Width(50) console.log(rectangle1.Area()) // Output: 5000 /* With a reference of 'rectangle1' object we can set Length and Width property to any value. */ ================================================ FILE: advanced/3. constructor-pattern/Examples/example5.js ================================================ //Example for Javascript Constructor Pattern Function //Constructor Pattern মেথড ব্যাবহার করার উদাহরণ //Live: https://jsfiddle.net/rijans/4drfo3qw/ function BuildCustomPC(cpu, ram, motherBoard, others) { this.cpu = cpu; this.ram = ram; this.motherBoard = motherBoard; this.others = others; this.buildPC = function () { console.log('A PC with RAM ' + ram + ', CPU ' + cpu + ' and motherboard ' + motherBoard + ' is built!') } } const pc1 = new BuildCustomPC('Core i7 11700', 'Corsair 16GB 3200GHz', 'Asus Gaming G8', {}); console.log(pc1.buildPC()); const pc2 = new BuildCustomPC('Apple M1 Pro', 'TSC 16GB Module', 'Foxcon M1 Mainboard', {}); console.log(pc2.buildPC()); //ফলাফল: //"A PC with RAM Corsair 16GB 3200GHz, CPU Core i7 11700 and motherboard Asus Gaming G8 is built!" //"A PC with RAM TSC 16GB Module, CPU Apple M1 Pro and motherboard Foxcon M1 Mainboard is built!" ================================================ FILE: advanced/3. constructor-pattern/Examples/example6.js ================================================ //Constructor Pattern মেথড ব্যাবহার করার উদাহরণ //Live: https://jsfiddle.net/rijans/opu1xckt/ function CreateUser(username, fName, lName, email) { this.username = username; this.fName = fName; this.lName = lName; this.email = email; this.createUser = function () { console.log('A User with username ' + this.username + ', first name ' + this.fName + ' and last name ' + this.lName + ' is created!') } } const user1 = new CreateUser('jaber', 'Jaber', 'Al Nahian', 'j@gmail.com'); console.log(user1.createUser()); const user2 = new CreateUser('tareq', 'Shafiul Hasan', 'Tareq', 't@gmail.com'); console.log(user2.createUser()); //ফলাফল: //"A User with username jaber, first name Jaber and last name Al Nahian is created!" //"A User with username tareq, first name Shafiul Hasan and last name Tareq is created!" ================================================ FILE: advanced/3. constructor-pattern/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/3. constructor-pattern/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/3. constructor-pattern/Practices/practice1.md ================================================ Consider the below code snippet. Try to guess which design pattern was used in this code. Convert this code to implement the same functionailty by using Constructor pattern. ```javascript function createVehicle(brand, model, price) { const vehicle = { brand: brand, model: model, price: price, printVehicleDetails: () => { console.log("Brand: " + brand + "\n" + "Model: " + model + "\n" + "Price: " + price + " tk"); } } return vehicle; } const vehicle1 = createVehicle("Toyota", "Corolla", "2000000"); vehicle1.printVehicleDetails(); ``` ================================================ FILE: advanced/3. constructor-pattern/Practices/practice2.md ================================================ What will be the output if we dont use 'new' keyword while creating new object of constructor function? ```javascript function Team (name, country){ this.name = name; this.country = country; } Team.prototype.detail = function (){ return this.name + " is from " + this.country; } let team1 = Team("Manchester City", "England"); console.log(team1.detail()) ``` ================================================ FILE: advanced/3. constructor-pattern/Practices/practice3.md ================================================ নিচের কোডটি লক্ষ করুন। দুটি ইউজার বানানর জন্য দুটি constructor function বানানো হয়েছে। এহাকে normalize করুন with dynamic parameters. ````javascript function CreateUser1() { this.username = 'jaber'; this.fName = 'Jaber'; this.lName = 'Al Nahian'; this.email = 'j@gmail.com'; this.createUser = function () { console.log('A User with username ' + this.username + ', first name ' + this.fName + ' and last name ' + this.lName + ' is created!') } } function CreateUser2() { this.username = 'tareq'; this.fName = 'Shaiful Hasan'; this.lName = 'Tareq'; this.email = 't@gmail.com'; this.createUser = function () { console.log('A User with username ' + this.username + ', first name ' + this.fName + ' and last name ' + this.lName + ' is created!') } } const user1 = new CreateUser1(); console.log(user1.createUser()); const user2 = new CreateUser2(); console.log(user2.createUser()); ```` ================================================ FILE: advanced/3. constructor-pattern/README.md ================================================ ### Constructor Pattern আজকের আলোচনার বিষয় হচ্ছে জাভাস্ক্রিপ্টের Constructor Pattern. গত আলোচনাতে আমারা Object তৈরি করার জন্য Factory pattern নিয়ে আলোচনা করেছি। Factory pattern এর মত Constructor Pattern ও Object তৈরি করে থাকে, তবে দুইটির মধ্যে কিছু পার্থক্য রয়েছে। আজকের আলোচনাতে Constructor Pattern কি এবং Factory pattern এর সাথে এটির পার্থক্য কি তা নিয়ে বিস্তারিত আলোচনা করব। বোঝার সুবিধার জন্য আমরা Factory pattern এ যে উদাহরণ ব্যবহার করেছিলাম সেই উদাহরণ দিয়ে Constructor Pattern কে বোঝার চেষ্টা করব। চলুন শুরু করা যাক। সহজভাবে বলতে গেলে, Constructor Function এমন একটি ফাংশন যা Object তৈরি করতে পারে। Constructor function ব্যবহার করে Object তৈরি করার প্রক্রিয়াই আসলে Constructor Pattern. যাহোক Constructor Function এর Naming Convension একটু আলাদা। এখানে আমরা ফাংশনের নামে Pascal Notation ব্যবহার করে থাকি। যদি আমারা Pascal Notation ভুলে গিয়ে থাকি তবে মনে করিয়ে দিচ্ছি। Pascal Notation এ আমরা প্রতিটি শব্দের প্রথম বর্ণটি বড় হাতের অক্ষরে লিখে থাকি। উদাহরণসরূপ, ```js function CreateCircle(){} //// CreateCircle maintain Pascel Notation. function createCircle(){} //// createCircle maintain Camel Notation. ``` সুতরাং, জাভাস্ক্রিপ্টের Convenstion অনুযায়ী, আমরা যখন Constructor Function ব্যবহার করব তখন অবশ্যই Pascal Notation ব্যবহার করব, যাতে অন্য জাভাস্ক্রিপ্টের ডেভেলপাররা নাম পড়েই বুঝতে পারে এই Function এর কাজ কি। যাহোক, এখন আমরা প্রথমে একটি Function বানাবো যার নাম হবে CreateCircle (Pascal Notation). ```js function CreateCircle(){} //// CreateCircle maintain Pascel Notation. ``` CreateCircle ফাংশনের কাজ হবে একটা circle Object তৈরি করা যেখানে circle এর radius এবং draw নামে একটা মেথড থাকবে। ঠিক Factory pattern আলোচনার উদাহরণের মত। এখানে আমরা Factory pattern মত Object Structure return করার পরিবর্তে একটু ভিন্ন পদ্ধতিতে Object কে Initialize করব জাভাস্ক্রিপ্টের ```this``` KeyWord ব্যবহার করে। জাভাস্ক্রিপ্টের একটা KeyWord আছে ```this```. এখন আমরা মনে করি যে, This একটা খালি বা Empty Object কে Reference করে। This যেহেতু খালি বা Empty Object কে Reference করছে তাই Dot Notation ব্যবহার করে আমরা This নামের খালি বা Empty Object এ Property add করতে পারি। চলুন দেখি তাহলে। ```js function CreateCircle(radius){ this.radius = radius; } ``` উপরের কোডে আমরা ```this``` নামের খালি বা Empty Object এ আমরা radius নামের একটা Property যোগ করলাম। জাভাস্ক্রিপ্টের Object হল ডাইনামিক, একবার Create করার পর এতে বিভিন্ন property বা মেথড যোগ করা যায়। চলুন আমার draw নামে একটা মেথড যোগ করি যা circle এর radius টা প্রিন্ট করবে। ```js function CreateCircle(radius){ this.radius = radius; this.draw = function () { console.log(`Circle radius is ${this.radius}`); }; } ``` এখন আমরা CreateCircle Constructor Function ব্যবহার করে circle Object তৈরি করব। ```js function CreateCircle(radius){ this.radius = radius; this.draw = function () { console.log(`Circle radius is ${this.radius}`); }; } const circle1 = new CreateCircle(5); ``` উপরের কোডে আমারা একটা নতুন Keyword ব্যবহার করেছি তা হল ```new``` নিশ্চয়ই লক্ষ্য করেছেন। এখন এই ```new``` Keyword নিয়ে কিছু কথা বলা যাক। আমারা যখন এই ```new``` Keyword টা ব্যবহার করি তখন আসলে তিনটি জিনিস ঘটে। প্রথমত, এই ```new``` Keyword একটি খালি বা empty জাভাস্ক্রিপ্ট Object তৈরি করে। অনেকটা ```const x = {} ``` এইরকম, যা আসলে Background এ কাজ করে বলে আমরা দেখতে পাই না। দ্বিতীয়ত, এইটি ```this``` টিকে সেট করবে খালি বা empty Object টিকে পয়েন্ট করার জন্য যার মধ্যমে আমরা খালি বা empty Object টিতে property বা মেথড যোগ করব। আর অবশেষে, Object টিকে ফাংশন থেকে return করবে। ```return this``` এই রকম। এই প্রক্রিয়াটিও আসলে Background এ কাজ করে বলে আমরা দেখতে পাই না। সুতরাং আমরা এখন CreateCircle Constructor Function কে বিভিন্ন মান বা বিভিন্ন আর্গুমেন্ট দিয়ে কল করে বিভিন্ন circle Object পেতে পারি। চলুন আমরা আরও কিছু circle Object তৈরি করি আমাদের লিখা Constructor Function দিয়ে। ```js function CreateCircle(radius) { this.radius = radius; this.draw = function () { console.log(`Circle radius is ${this.radius}`); }; } const circle1 = new CreateCircle(5); console.log(circle1.draw()); const circle2 = new CreateCircle(10); console.log(circle2.draw()); // // output: // Circle radius is 5 // Circle radius is 10 // ``` আমরা এখন Factory Function এবং Constructor Function দুইটি পদ্ধতিতেই Object তৈরি করতে পারি। এখন আমরা দেখব এই দুই পদ্ধতির মধ্যে আসলে পার্থক্য কি? Factory Function এ আমরা শুধু ফাংশনকে কল করি এবং ফাংশন আমাদের একটা Object রিটার্ন করে আর অন্যদিকে Constructor Function এ আমরা ```new``` keyword ব্যবহার করি এবং Object রিটার্ন না করে ```this``` keyword এর মাধ্যমে খালি বা Empty Object এ প্রপার্টি বা মেথড যোগ করি। এছাড়াও Naming Convension এর ক্ষেত্রে Factory Function এ Camel Notation এবং Constructor Function এ Pascal Notation ব্যবহার করে থাকি। এখন আমাদের মনে প্রশ্ন আসতে পারে যে, আমরা কোন approach বা pattern টা ব্যবহার করব Object তৈরি করার জন্য। যদিও দুইটি approach বা pattern ই সমান কার্যকর কিন্তু যাদের পূর্বে ডেভেলপমেন্টের অভিজ্ঞতা রয়েছে বিশেষ করে C# বা Java Developer তাদের কাছে Constructor pattern টি বেশ পরিচিত, তারা এই pattern এ বেশি Comfort Feel করে। এই ছিল Constructor pattern নিয়ে আজকের আলোচনা। হ্যাপি কোডিং। ================================================ FILE: advanced/4. prototype/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/4. prototype/Examples/example1.js ================================================ { /* In the example below, the function getFullName() will be available in every new Name object automatically because we have put this function inside the prototype object of the Name() constructor function. */ } function Name(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } Name.prototype.getFullName = function() { return `${this.firstName} ${this.lastName}`; } var name1 = new Name('Anik', 'Sajli'); console.log(name1.getFullName()); // Anik Sajli var name2 = new Name('Fahim', 'Ahmed'); console.log(name2.getFullName()); // Fahim Ahmed ================================================ FILE: advanced/4. prototype/Examples/example2.js ================================================ { /* One fun thing about prototypes is even the prototype of a function has it's own prototype. This is called prototype chaining. In the example below, the nesting of prototypes can be used to add properties to different layers of prototype objects which are accessible to us later. We have added the property 'profession' to the prototype of Person's prototype. As you can see below that we are also able to update the value of that property later. */ } function Person(name, age) { this.name = name; this.age = age; } Person.__proto__.__proto__.profession = 'Software Engineer'; person1 = new Person("Anik", 25); console.log(person1.profession); // Software Engineer person1.profession = 'Businessman'; console.log(person1.profession); // Businessman ================================================ FILE: advanced/4. prototype/Examples/example3.js ================================================ /* We know that we can access the defined method on the instances of the object. Like this one below: */ function Team(name) { this.name = name; } Team.prototype.getDetails = function() { return `${this.name} plays football`; } // In this 'team1' and 'team2' instance of Team, // we can access getDetails() method let team1 = new Team('Real Madrid'); console.log(team1.getDetails()); // Output: Real Madrid plays football let team2 = new Team('Barcelona'); console.log(team2.getDetails()); // Output: Barcelona plays football /* But if we define methods in an individual object (instances of Team) then we can only access those methods from the individual object */ team1.league = function(){ return "La Liga" } console.log(team1.league()) // Output: La Liga console.log(team2.league()) // Output: TypeError: team2.league is not a function ================================================ FILE: advanced/4. prototype/Examples/example4.js ================================================ /* Let’s add a new method to the object person1 with the same name as the method in the Person.prototype object */ function Person(name){ this.name = name; } Person.prototype.City = function(){ return `${this.name} is from Dhaka`; } let person1 = new Person("Mehedi"); person1.City = function (){ return `${this.name} is from CTG`; } console.log(person1.City()) /* Output: Mehedi is from CTG Because the person1 object has the City() method, JavaScript just executes it immediately without looking it up in the prototype chain. */ ================================================ FILE: advanced/4. prototype/Examples/example5.js ================================================ //Prototype মেথড ব্যাবহার করে object construct করার উদাহরণ //Live: https://jsfiddle.net/rijans/tumcyw5p/1/ function CustomPC(cpu, ram, board) { this.cpu = cpu; this.ram = ram; this.board = board; // this.buildPC = function () { // return 'A PC with CPU ' + this.cpu + ', RAM ' + this.ram + ' and Motherboard ' + this.board + ' is built!' // } //আমরা উপরের function কে prototype হিসাবে যোগ করব } CustomPC.prototype.buildPC = function () { return 'A PC with CPU ' + this.cpu + ', RAM ' + this.ram + ' and Motherboard ' + this.board + ' is built!' } const pc1 = new CustomPC('Intel Core i9 11900', 'Corsair 16GB 3200GHz', 'ASUS G1 Sniper'); console.log(pc1.buildPC()); //ফলাফল: A PC with CPU Apple M1 Pro Max, RAM Corsair 16GB 3200GHz and Motherboard Foxcon M1 Board is built!" const pc2 = new CustomPC('Apple M1 Pro Max', 'Corsair 16GB 3200GHz', 'Foxcon M1 Board'); console.log(pc2.buildPC()); //ফলাফল: A PC with CPU Apple M1 Pro Max, RAM Corsair 16GB 3200GHz and Motherboard Foxcon M1 Board is built!" ================================================ FILE: advanced/4. prototype/Examples/example6.js ================================================ //Prototype মেথড ব্যাবহার করে object construct করার উদাহরণ //Live: https://jsfiddle.net/rijans/z0mecdv3/ function CustomBike(cc, bikeType, headlightType) { this.cc = cc; this.bikeType = bikeType; this.headlightType = headlightType; // this.buildBike = function () { // return 'A Bike with CC ' + this.cc + ', type ' + this.bikeType + ' and Headlight ' + this.headlightType + ' is built!' // } //আমরা উপরের function কে prototype হিসাবে যোগ করব } CustomBike.prototype.buildBike = function () { return 'A Bike with CC ' + this.cc + ', type ' + this.bikeType + ' and Headlight ' + this.headlightType + ' is built!' } const pc1 = new CustomBike('150', 'Sports', 'LED Projector'); console.log(pc1.buildBike()); //ফলাফল: A Bike with CC 150, type Sports and Headlight LED Projector is built!" const pc2 = new CustomBike('150', 'Commuter', 'LED Regular'); console.log(pc2.buildBike()); //ফলাফল: A Bike with CC 150, type Commuter and Headlight LED Regular is built!" ================================================ FILE: advanced/4. prototype/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/4. prototype/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/4. prototype/Practices/practice1.md ================================================ Consider the code snippet below. Now suppose I want to create multiple car objects which might have some new properties. All the car objects must have the 'getCarBrand' and 'getCarPrice' methods as it's property. But i don't want these 2 methods to be recreated in the memory every time a car object is created. How can you achieve this? ```javascript let car = {}; car.brand = 'Toyota'; car.price = 2000000; car.getCarBrand = function () { return this.brand; } car.getCarPrice = function () { return this.price; } console.log(car.getCarBrand()); console.log(car.getCarPrice()); ``` ================================================ FILE: advanced/4. prototype/Practices/practice2.md ================================================ Consider the code below. Can the person1 object directly access the 'prototype' object? What do you think the output will be? ```javascript function Person(name){ this.name = name; } Person.prototype.City = function(){ return `${this.name} is from Dhaka`; } let person1 = new Person("Mehedi"); console.log(person1.prototype.City()) ``` ================================================ FILE: advanced/4. prototype/Practices/practice3.md ================================================ নিচের কোডটিতে prototype implement করুন: ````js function CustomPC(cpu, ram, board) { this.cpu = cpu; this.ram = ram; this.board = board; this.buildPC = function () { return 'A PC with CPU ' + this.cpu + ', RAM ' + this.ram + ' and Motherboard ' + this.board + ' is built!' } } const pc1 = new CustomPC('Intel Core i9 11900', 'Corsair 16GB 3200GHz', 'ASUS G1 Sniper'); console.log(pc1.buildPC()); const pc2 = new CustomPC('Apple M1 Pro Max', 'Corsair 16GB 3200GHz', 'Foxcon M1 Board'); console.log(pc2.buildPC()); ```` ================================================ FILE: advanced/4. prototype/README.md ================================================ ### Prototype আজকের আলোচনার বিষয় হচ্ছে জাভাস্ক্রিপ্টের Prototype. গত আলোচনাতে আমারা জাভাস্ক্রিপ্টের Factory pattern নিয়ে আলোচনা করেছি। জাভাস্ক্রিপ্ট প্রোগ্রামার বা ডেভেলপার হিসাবে Prototype সম্পর্কে পরিষ্কার ধারণা থাকা অতীব জরুরী। তাই চেষ্টা করবো আজকে কিছু ইউজফুল উদারণ দিয়ে Prototype নিয়ে একটু লেখতে। আশা করি, আজকের পর থেকে Prototype নিয়ে কাজ করতে কখনো সমস্যা হবে না। চলুন শুরু করা যাক। নিচের Constructor Function টা লক্ষ্য করুন। ```js function Car(color, name, manufactureDate) { this.color = color; this.name = name; this.manufactureDate = manufactureDate; this.getColor = function () { return this.color; }; this.getName = function (){ return this.name; } this.getManufactureDate = function(){ return this.manufactureDate; } } ``` চলুন আমরা ```firstCar``` এবং ```secondCar``` নামে দুইটি Object তৈরি করি ```Car``` Constructor Function ব্যবহার করে। ```js const firstCar = new Car("red", "Ferrari", "2020"); const secondCar = new Car("yellow", "Lamborgini", "2021"); ``` আশা করি এই পর্যন্ত বোঝতে কোন সমস্যা হয় নি। যদি কোন সমস্যা হয়ে থাকে তবে আমাদের Constructor Function এর আলোচনাটি দেখার জন্য অনুরোধ করছি। উপরের কোডটি লক্ষ্য করলে দেখা যাবে যে, জাভাস্ক্রিপ্ট ইঞ্জিন আমাদের Constructor Function ```Car``` এর দুইটি কপি তৈরি করেছে। একটি ```firstCar``` আর অন্যটি ```secondCar``` এর জন্য। এখন আমরা Constructor Function ```Car``` দিয়ে যত Object তৈরি করব Constructor Function ```Car``` এর ঠিক তত গুলা কপি তৈরি হবে। একবার ভাবুন তো, প্রত্যেকটি Object এর জন্য একটা ফাংশনের আলাদা আলাদা Instance তৈরি করা মেমোরি অপচয় ছাড়া আর কিছুই নয়। এই সমস্যা আমার খুব সহজে জাভাস্ক্রিপ্টের ```Prototype ``` এর মাধ্যমে সমাধান করতে পারি। চলুন ```Prototype ``` নিয়ে আলোচনা শুরু করা যাক। যখন জাভাস্ক্রিপ্টে একটি Object তৈরি করা হয় ঠিক তখনই জাভাস্ক্রিপ্ট ইঞ্জিন ওই Object এ ```Prototype ``` নামে একটা Property যোগ করে। মূলত, জাভাস্ক্রিপ্টে যেকোনো Object Type এর মধ্যে ```Prototype``` Property আছে। Array Type এর মধ্যে একটা ```Prototype ``` Property আছে। Date Type এর মধ্যে ```Prototype ``` Property আছে। এমনকি আমরা যদি কোন Custom Object Type তৈরি করি তবে তার মধ্যেও ```Prototype ``` Property আছে। আমরা জানি যে, জাভাস্ক্রিপ্টে ফাংশনও এক ধরনের Object. তাই ফাংশনেরও একটি ```Prototype``` Property আছে। কোন Object এর ```Prototype ``` Property টি ব্যবহার করতে হয় ``` functionName.prototype ``` দিয়ে। এখন চলুন আমরা একটি নাম্বারের Array বানাই যেখানে কিছু সংখ্যা থাকবে। যেমনঃ ```js const arr = [1, 2,3,4,5]; console.log(arr); ``` উপরের কোডটি রান করালে দেখব যে, ```arr``` এর প্রতিটি ইনডেক্সের মান ব্রাউজারে প্রিন্ট করছে। কিন্তু এর নিচে দেখব, ```__proto__``` নামে একটা Object আছে। এই Object টিকে যদি Expand করি তবে দেখব যে, এইখানে ```push```, ```concat```, ```indexOf``` এমন অনেক পরিচিত মেথড বা ফাংশন রয়েছে যা আমরা প্রায়ই Array Manipulation এর কাজ এ ব্যবহার করে থাকি। আমার যদি আরও কোন Array বানাই এবং ওই Array এর ```__proto__``` property টি দেখি তবে দেখব যে আগের মত অনেক পরিচিত মেথড বা ফাংশন এখানেও রয়েছে। কিন্তু এই মেথড বা ফাংশন গুলো কোথা থেকে এলো। আমরা তো কোথাও এইগুলা Define বা Declare করি নি। একই constructor Function ব্যবহার করে তৈরি হওয়া সমস্ত Object একই Prototype Object টিকে Share করে। সুতরাং, Array Constructor Function ব্যবহার করে তৈরি করা সব Array তাই একই Prototype Object কে Share করবে। তাই যখনই আমরা একটা Array Declare করি ঠিক তখনই Array এর জন্য নির্ধারিত Prototype Object টি Array এর ভিতর Assign হয়ে যায়। আর Array এর জন্য নির্ধারিত Prototype Object টির ভিতর ```push```, ```concat```, ```indexOf``` এর মত অনেক পরিচিত মেথড বা ফাংশন আগে থেকে লিখা আছে। তাই আমরা যত খুশি Array Type ভেরিয়েবল Declare করি না কেন, সব কয়টার ```__proto__``` ভিতর পূর্ব নির্ধারিত মেথড বা ফাংশন গুলো থাকবে। এখন তাহলে চলুন আমরা আমাদের ```Car``` Constructor Function এর মধ্যে থাকা ```getColor```, ```getName```, ```getManufactureDate``` মেথডগুলোকে সরিয়ে ```Car``` Constructor Function এর Prototype এর মধ্যে ঢোকাই; যাতে করে ```Car``` Constructor Function দিয়ে তৈরি সব Object এর মধ্যে মেথডগুলোকে automatically চলে আসে। ```js function Car(color, name, manufactureDate) { this.color = color; this.name = name; this.manufactureDate = manufactureDate; } Car.prototype.getColor = function () { return this.color; }; Car.prototype.getName = function () { return this.name; }; Car.prototype.getManufactureDate = function () { return this.manufactureDate; }; const firstCar = new Car("red", "Ferrari", "2020"); console.log(firstCar); const secondCar = new Car("Yellow", "Lamborgini", "2021"); console.log(secondCar); ``` উপরের কোডটি যদি আমরা ব্রাউজার এ গিয়ে Output দেখি তবে দেখব যে, আমাদের ```Car``` Constructor Function এর ভিতর এখন আর মেথডগুলো নেই। মেথডগুলো এখন ```__proto__``` এর ভিতর চলে গিয়েছে যা ```Car``` Constructor Function থেকে তৈরি সব Object ই automatically পেয়ে যাবে। প্রতিটি Object Instance এর ভিতর থাকলে যে মেমোরি অপচয় হওয়ার কথা ছিল টা এখন আর হচ্ছে না। এই ছিল আজকের জাভাস্ক্রিপ্টের Prototype নিয়ে যত কথা। হ্যাপি কোডিং। ================================================ FILE: advanced/5. prototypical-inheritance/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/5. prototypical-inheritance/Examples/example1.md ================================================ ```js function Animal (name, energy) { this.name = name; this.energy = energy; } Animal.prototype.eat = function (amount) { console.log(`${this.name} is eating.`); this.energy += amount; } Animal.prototype.sleep = function (length) { console.log(`${this.name} is sleeping.`); this.energy += length; } Animal.prototype.play = function (length) { console.log(`${this.name} is playing.`); this.energy -= length; } function Dog (name, energy, breed) { Animal.call(this, name, energy); this.breed = breed; } Dog.prototype = Object.create(Animal.prototype); Dog.prototype.bark = function () { console.log('Woof Woof!'); this.energy -= .1; } const charlie = new Dog('Charlie', 10, 'Goldendoodle'); console.log(charlie.constructor); ``` ================================================ FILE: advanced/5. prototypical-inheritance/Examples/example2.md ================================================ ```js function Person(firstName, lastName, age, gender, interests) { this.name = { firstName, lastName }; this.age = age; this.gender = gender; this.interests = interests; }; function Teacher(firstName, lastName, age, gender, interests, subject) { Person.call(this, firstName, lastName, age, gender, interests); this.subject = subject; } ``` ================================================ FILE: advanced/5. prototypical-inheritance/Examples/example3.js ================================================ /* We can use prototype chain to solve this kind of problems */ let user = { name: "name", email: "email", id: 00000, showAccess: true } let singleUser = { __proto__ : user, ads: true } let premiumUser = { __proto__ : singleUser, ads: false, mutiScreen : true } /* we created a new object user_me where we used three level of prototypical inheritance. we can see that user_me object has access to data throughout the chain. */ let user_me = { __proto__ : premiumUser, name : "Mehedi", email: "meheditcf@gmail.com", id: 001 } console.log(user_me.mutiScreen) // Output: true console.log(user_me.ads) // Output: false console.log(user_me.showAccess) // Output: true ================================================ FILE: advanced/5. prototypical-inheritance/Examples/example4.js ================================================ /* No matter where the method is found: in an object or its prototype. In a method call, this is always the object before the dot. */ let animal = { sleep(){ this.isSleeping = true; } } let cat = { name: "Billu", __proto__ : animal } cat.sleep() console.log(cat.isSleeping) // Output: true /* As we called the method as cat.sleep(), 'this' references to cat object. Thats why in the code below we get undefined. */ console.log(animal.isSleeping) // Output: undefined ================================================ FILE: advanced/5. prototypical-inheritance/Examples/example5.js ================================================ //Prototypical Inheritance এর একটি উদ্বাহরও দেখান হল। let smartPhone = { hasCamera: true } let nokiaPhone = { name: "Nokia 1100", __proto__ : smartPhone } console.log(nokiaPhone.hasCamera); //ফলাফল: true ================================================ FILE: advanced/5. prototypical-inheritance/Examples/example6.js ================================================ //Prototypical Inheritance এর একটি উদ্বাহরও দেখান হল। let plant = { hasLeaf: 'yes' } let cactus = { name: "Cactus", __proto__ : plant } console.log(cactus.hasLeaf); //ফলাফল: true ================================================ FILE: advanced/5. prototypical-inheritance/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/5. prototypical-inheritance/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/5. prototypical-inheritance/Practices/practice1.md ================================================ What do you think the output of this code will be? And why? ```js function House () { this.height= 100; this.width= 50; } let house1 = new House(); House.prototype.height = 200; console.log(house1.height) ``` ================================================ FILE: advanced/5. prototypical-inheritance/Practices/practice2.md ================================================ নিচের কোডটিতে Prototypical Inheritance Implement করুন ````js let plant = { hasLeaf: true } let cactus = { name: "Cactus", hasLeaf : true } console.log(cactus.hasLeaf); ```` ================================================ FILE: advanced/5. prototypical-inheritance/README.md ================================================ ### Prototypical Inheritance আজকের আলোচনার বিষয় হচ্ছে জাভাস্ক্রিপ্টের Prototypical Inheritance. গত আলোচনাতে আমারা জাভাস্ক্রিপ্টের Prototype pattern নিয়ে আলোচনা করেছি। জাভাস্ক্রিপ্ট প্রোগ্রামার বা ডেভেলপার হিসাবে Prototypical Inheritance সম্পর্কে পরিষ্কার ধারণা থাকা খুবই জরুরী। তাই চেষ্টা করবো আজকে কিছু উদাহরণ দিয়ে Prototypical Inheritance নিয়ে একটু লেখতে। চলুন শুরু করা যাক। ### Prototypical Inheritance কি? সহজভাবে বলতে গেলে Prototypical Inheritance বলতে একটি Object যখন অন্য একটি Object এর প্রপার্টিকে অ্যাক্সেস করতে পারে তাকেই বুঝায়। আমরা জানি যে, জাভাস্ক্রিপ্টের Prototype এর মধ্যে যে কোন Object এ নতুন প্রপার্টি বা মেথড যোগ করা যায়; আমারা তখন আমাদের জাভাস্ক্রিপ্ট কোডে Prototype থেকে এই প্রপার্টিগুলো Inherite করার জন্য বলে দিতে পারি। একটি Object অন্য Object এর প্রপার্টি বা মেথডগুলোকে পুনরায় ব্যবহার করতে Prototypical Inheritance সাহায্য করে। সকল জাভাস্ক্রিপ্ট Object ই কোন না কোন প্রপার্টি বা মেথড prototype থেকে Inherit করে থাকে। উদাহরণস্বরূপ, ১। Date Object, Date.prototype থেকে Inherit করে থাকে। ২। Array Object, Array.prototype theke Inherit করে থাকে। আর এই Prototype chain এর সবার উপর থাকে Object.prototype. Date Object, Array Object সবাই Object.prototype কে Inherite করে। চলুন, এখন সরাসরি Prototypical Inheritance বুঝার চেষ্টা করি কিছু practical উদাহরন এর মাধ্যমে। আসুন, একটি `Rectangle constructor` তৈরি করা যাক। ```js function Rectangle(width, height) { this.width = width; this.height = height; } ``` এখন যদি আমারা `Rectangle constructor` দিয়ে একটা Object তৈরি করতে চাই তবে কি করে করব। নিশ্চয়ই মনে আছে। ```js let rect = new Rectangle(3, 4); rect.width; // Now the width of Rectangle is 3 rect.height; // And the height of that rectangle is 4 ``` এখন আমরা এই `Rectangle constructor` এর মধ্যে একটা মেথড তৈরি করব। মেথডটির নাম `area` দেয়া যেতে পারে। ```js Rectangle.prototype.area = function () { return this.width * this.height; }; ``` এখন আমরা ইচ্ছে করলেই `Rectangle` Object এর `area` মেথডটি ব্যবহার করতে পারি। ```js var rect = new Rectangle(3, 4); rect.area(); // 12 ``` আশা করি এই পর্যন্ত বুঝতে আমাদের কোন সমস্যা হয়ে নি। চলুন আমরা `square constructor` এর মাধ্যমে একটি Object তৈরি করি। ```js function Square(length) { this.width = this.height = length; } ``` আমরা সবাই জানি যে, Square আসলে একটা বিশেষ ধরনের Rectangle। তাহলে Rectangle এর বৈশিষ্ট্যগুলোও Square এর মধ্যে থাকা উচিত। কিন্তু কি করে এই কাজটি করব? যদি আমাদের মনে থেকে থাকে তবে আমরা জানি যে, `Object.create()` দিয়ে আমারা একটি খালি বা Empty Object তৈরি করতে পারি। তাহলে একটা কাজ করলে কেমন হয়, Square এর prototype এর একটা Object তৈরি করি Reactangle এর prototype কে প্যারেন্ট ধরে। ```js Square.prototype = Object.create(Rectangle.prototype); ``` এখন Square এর prototype এর মধ্যে Rectangle.prototype এর বৈশিষ্ট্যগুলো চলে এসেছে। সুতরাং, Square এর সকল Instance এর Prototype এর মধ্যেও এই বৈশিষ্ট্যগুলো থাকবে। তাহলে চলুন দেখি সবকিছু ঠিকঠাক কাজ করছে কি না। ```js var square = new Square(4); square.area(); // 16 ``` উপরের কোডটি যদি একটু লক্ষ্য করে দেখুন তবে থেখা যাবে যে, আমরা `square` নামে যে Object টি তৈরি করেছি তার মধ্যে `area` মেথডটি চলে এসেছে। এটাই আসলে Prototypical Inheritance। এখন আমরা যদি চাই, তবে square এর মধ্যে শুধুমাত্র তার নিজের কিছু মেথড বা প্রপার্টি যোগ করতে পারি। চলুন তাহলে করা যাক, ```js Square.prototype.diagonal = function () { return Math.sqrt(this.area() * 2); }; ``` শেষ করার আগে একটা বিষয় মাথায় রাখা জরুরী, তা হল একটি Object কখনও একাধিক Prototypes Inherit করতে পারে না। তাহলে এই ছিল আজকের আলোচনা। আশা করি Prototypical Inheritance বুঝতে আর কোন সমস্যা হবে না। পরবর্তীতে অন্য কোন বিষয় নিয়ে আবার আলোচনা হবে। হ্যাপি কোডিং। ================================================ FILE: advanced/6. event-loop/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/6. event-loop/Examples/example1.js ================================================ { /* When we are putting a code block inside setTimeout() function, we're actually declaring that code to be asynchronous. JS will send that code to the setTimeout() web api and after that it will be added to the task queue/callback queue. The event loop will it's work from that point. */ } console.log("First console"); setTimeout(() => { console.log("First setTimeout"); }, 1000); console.log("Second console"); setTimeout(() => { console.log("Second setTimeout"); }, 0); { /* Output: First console Second console Second setTimeout First setTimeout */ } ================================================ FILE: advanced/6. event-loop/Examples/example2.js ================================================ { /* Promises are not added to the callback queue. Instead it gets added to the micro task queue which has a higher priority than the task queue. The tasks existing in the micro task queue get pushed to the call stack by the event loop first. */ } firstPromise = new Promise((resolve) => { resolve("First promise.") }); secondPromise = new Promise((resolve) => { resolve("Second promise.") }); console.log("First console.") setTimeout(() => console.log("First setTimeout."), 1000); setTimeout(() => console.log("Second setTimeout.")); firstPromise.then(response => console.log(response)); secondPromise.then(response => console.log(response)); { /* Output: First console. First promise. Second promise. Second setTimeout. First setTimeout. */ } ================================================ FILE: advanced/6. event-loop/Examples/example3.js ================================================ /* Event though setTimeout has a delay of 0s and while loop has 5s delay, event loop will wait until the call stack is empty. The while loop keeps on running on the call stack until 5s has elapsed */ function myFunc (){ console.log('first') setTimeout(function hello(){ console.log('second') }, 0) runforNSceconds(5) console.log('third') } myFunc() function runforNSceconds(sec){ let start = Date.now(), now = start; while(now-start< (sec*1000)){ now = Date.now() } } /* Output: first third second */ ================================================ FILE: advanced/6. event-loop/Examples/example4.js ================================================ //JS Eventloop এর উদাহরণ দেখান হয়েছে একটা URL এ request পাঠিয়ে //এটা করা হয়েছে এজ্যাক্স Request এর মাধ্যমে, যেটা Asynchronous //live: https://jsfiddle.net/rijans/v17t6qhu/10/ function main(url){ console.log('Lets get URL Headers!'); setTimeout( function (){ //get headers of an URL let req = new XMLHttpRequest(); req.open('GET', url, false); req.send(null); let headers = req.getAllResponseHeaders().toLowerCase(); console.log(headers); }, 1000); console.log('Done!'); } main('https:://vivasofltd.com'); //এটার ফলাফল এমন: // "Let get URL Headers!" // "End!" // "content-encoding: gzip // content-type: text/html; charset=utf-8 // date: thu, 13 jan 2022 17:54:06 gmt // server: nginx // vary: origin // x-request-id: 64624b39-d4ec-4d4d-b8c4-480ddabc8709 // x-runtime: 0.002067 // " //লক্ষ করে দেখুন যে header response টা পরে আসছে, event লুপ এর কারণে ================================================ FILE: advanced/6. event-loop/Examples/example5.js ================================================ //JS Eventloop এর উদাহরণ দেখান হয়েছে, নাম্বার counting এর মাধ্যমে। //live: https://jsfiddle.net/rijans/pkb3tsLg/ function main(number) { console.log('Lets count from 0 to ' + number); for (var i = 0; i <= number; i++) { setTimeout(function () { console.log(i + '\n'); }, 1000); } console.log('Done!'); } main(5); //এখানে output হবে এমন: // "Lets count from 0 to 5" // "Done!" // "6 // " // "6 // " // "6 // " // "6 // " // "6 // " // "6 // " //এটা ভার ভারিয়াবল এবং event-loop এর কারণে হয়েছে। এখানে লেট ভারিয়াবল ব্যাবহার করলে থিক ফল আসবে। ================================================ FILE: advanced/6. event-loop/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/6. event-loop/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/6. event-loop/Practices/practice1.md ================================================ What will be the output of this code snippet? ```javascript promise = new Promise((resolve) => { resolve("Promise."); }); setTimeout(() => console.log("First setTimeout."), 0); promise.then((res) => { setTimeout(() => console.log(res), 0); }); setTimeout(() => console.log("Second setTimeout."),0); console.log("First console."); ``` ================================================ FILE: advanced/6. event-loop/Practices/practice2.md ================================================ We know event loop has different priorities when it comes to promise and setTimeout. Then what will be the output of this code? ```javascript setTimeout(function(){ console.log("first message") setTimeout(function(){ console.log("second message") }, 1000) }, 0) runforNSceconds(3) console.log("third message") let promise = new Promise(function(resolve, reject){ resolve() }) promise.then(function(resolve){ console.log("fourth message from promise 1") }) .then(function(promise){ console.log("fifth message from promise 2") }) console.log("sixth message") function runforNSceconds(sec){ let start = Date.now(), now = start; while(now-start< (sec*1000)){ now = Date.now() } } ``` ================================================ FILE: advanced/6. event-loop/Practices/practice3.md ================================================ নিচের কোডটির output কি হবে? ````js function main(number) { console.log('Lets count from 0 to ' + number); for (var i = 0; i <= number; i++) { setTimeout(function () { console.log(i + '\n'); }, 1000); } console.log('Done!'); } main(3); ```` ================================================ FILE: advanced/6. event-loop/README.md ================================================ ### Event loop আজকে আমরা জাভাস্ক্রিপ্টের খুবই একটা গুরুত্বপূর্ণ বিষয় নিয়ে আলোচনা করব, তা হল Event Loop. জাভাস্ক্রিপ্ট প্রোগ্রামার বা ডেভেলপার হিসাবে Event Loop সম্পর্কে ধারণা থাকা অত্যন্ত জরুরী। তাই চেষ্টা করবো আজকে Event Loop নিয়ে একটু লেখতে। চলুন শুরু করা যাক। ### Event loop কি? Event loop জাভাস্ক্রিপ্টের একটি secret machenism যার মাধ্যমে জাভাস্ক্রিপ্ট single-threaded প্রোগ্রামিং ল্যাঙ্গুয়েজ হওয়া সত্ত্বেও বাহ্যিক ভাবে multi-threaded প্রোগ্রামিং ল্যাঙ্গুয়েজের মত কাজ করে। Event loop গভীরভাবে call stack কে পর্যবেক্ষণ করে এবং যদি call stack খালি বা empty থাকে তবে Event queue থেকে Task call stack এ পাঠায় execution সম্পন্ন করার জন্য। আমরা সকলে জানি, জাভাস্ক্রিপ্ট একটি single-threaded asynchronous প্রোগ্রামিং ল্যাঙ্গুয়েজ । এইটা বিষয় লক্ষ্য করেছেন কি, একটা ল্যাঙ্গুয়েজ কি করে একই সাথে single-threaded আবার asynchronous হতে পারে? আসলে বিষয়টা হল, জাভাস্ক্রিপ্ট একটা single-threaded ল্যাঙ্গুয়েজ; তার মানে হল জাভাস্ক্রিপ্ট একসাথে একই সময়ে একটা মাত্র কাজ ে করতে পারে। আর asynchronous বিষয়টা জাভাস্ক্রিপ্ট ল্যাঙ্গুয়েজের কোন বিষয় না, এটি নিয়ন্ত্রিত হয় ব্রাউজার Enviornment এর মাধ্যমে। কয়েকটি উদাহরন দেখলে বিষয়টা বোঝতে সুবিধা হবে। চলুন শুরু করা যাক। ```js function main() { console.log('Hi'); setTimeout(function display() { console.log('there'); }, 1000); console.log('JSConfEU'); } main(); // Output // A // C // B ``` উপরের কোডটি একটু ভাল করে লক্ষ্য করুন, এখানে প্রথম `console.log('Hi')` এই Statement টি execute হচ্ছে। এরপর একটা setTimeout ফাংশন রয়েছে, যা নিদিষ্ট সময় পর `console.log('there')` এই Statement টি execute করার কথা ছিল। কিন্তু কোন কারণে এই Statement টিকে বাদ দিয়ে তারপরের Statement `console.log('JSConfEU')` এইটিকে execute করছে। এইটির কারণ হল জাভাস্ক্রিপ্টের asynchronous ব্যবহার। জাভাস্ক্রিপ্ট যখনই setTimeout ফাংশনটিকে দেখছে, ঠিক তখনই জাভাস্ক্রিপ্ট বোঝতে পারছে এটি একটি asynchronous ফাংশন । আর আমরা জানি asynchronous ফাংশনের কাজ শেষ হতে কিছু সময়ের প্রয়োজন হয়। তাই জাভাস্ক্রিপ্ট setTimeout ফাংশনটিকে আর `call stack` এ না রেখে, `Browser API` এ পাঠিয়ে দেয়। আর এই `Browser API` তেই setTimeout ফাংশনটি তার নির্ধারিত সময় নিয়ে কাজ টি শেষ করে। কাজ শেষ হবার পর setTimeout ফাংশনটি `Event Queue` তে প্রবেশ করে। এবং পুনরায় `call stack` এ প্রবেশ করার অপেক্ষা করে। ঠিক এখানে এ `Event Loop` এর কাজ শুরু হয়। `Event Loop` এর কাজ হল Call Stack আর Event Queue এর দিকে লক্ষ্য রাখা। যখন Call Stack খালি হয়ে যায় ঠিক তখন `Event Loop` Event Queue থেকে একটি একটি করে Event call stack এ পাঠায়। এবং call stack ওই অনুযায়ী Statement Execute করতে থাকে। এই প্রোগ্রামের ক্ষেত্রে `console.log('there')`statement টি Execute হয়। আর যখন setTimeout ফাংশনটিকে যখন call stack থেকে `Browser API` তে পাঠানো হয় তখন call stack টি খালি থাকার কারণে জাভাস্ক্রিপ্ট `console.log('JSConfEU')` statement টিকে call stack এ পাঠিয়ে execute করে ফেলে যার কারণে ``console.log('JSConfEU')` statement টি console.log('there') এর আগে execute করছে। জাভাস্ক্রিপ্টে setTimeout ছাড়া আরও কিছু ফাংশন আছে যা asynchronous API রয়েছে। যেমনঃ `addEventListener`, `setTimeout`, `setInterval`, যেকোনো ধরনের API কল। নিচের Graphical Representation টা দেখলে বিষয়টি আরও পরিষ্কার হবে। ![queue-example-jsconf (1)](https://user-images.githubusercontent.com/9677372/144177972-e998b3cf-7b37-4d52-9feb-f7926ffb9eeb.gif) এই ছিল আজকের আলোচনা। পরবর্তীতে অন্য কোন বিষয় নিয়ে আবার কথা হবে। হ্যাপি কোডিং। ================================================ FILE: advanced/7. garbage-collector/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/7. garbage-collector/Examples/example1.js ================================================ const person = { name: 'Anik', age: 25 }; person = 'Anik'; // Initially, the person object is holding a bunch of internal attributes. // Then let’s assume I decided that a person could simply be represented // as a string. So now, the first person object has no references pointing // to it anymore, which makes it available for garbage collection. function circularObj() { var a = { }; var b = { }; a.prop = b; b.prop = a; }; circularObj(); // This creates a cycle. Once the function’s finished, JavaScript’s // reference-counting algorithm won’t be able to interpret that these two objects // can be collected because they still hold references to each other. // The 'Mark and sweep algorithm' can easily solve this problem. ================================================ FILE: advanced/7. garbage-collector/Examples/example2.js ================================================ // 'Reference counting garbage collection' example: var object_1 = { object_2: { object_3: 7 } }; // In the code above, two objects have been created. One of them is referred by another // as one of its properties. Currently, none can be garbage collected with the reference // counting algorithm. var object_4 = object_1; // Now the "object_4" variable is the second thing that has a reference to the object. // The objects that were originally in "object_1" has a unique reference embodied // by the "object_4" variable. object_1 = "Object 1"; var object_5 = object_4.object_2; // Reference to "object_2" property of the object. This object now has 2 references: // first one as a property, the other as the "object_5" variable. object_4 = "Object 4"; // The object that was in "object_1" has now zero references to it. It can be // garbage collected. However its "object_2" property is still referenced by the // "object_5" variable, so it cannot be freed. object_5 = null; // Now the "object_2" property has no references to it and so it can be garbage collected. ================================================ FILE: advanced/7. garbage-collector/Examples/example3.js ================================================ /* Here x is not in the scope anymore but we can still access it by using 'arr' array. That means it stays in the memory untill the reference is there. If we pop it from the array, it won't be needed anymore and can be garbage collected. */ let arr = [] function addName() { let x = {name: "Mehedi"} arr.push(x) } addName() console.log(arr[0]) // Output: { name: 'Mehedi' } arr = null; console.log(arr) // Output: null // Now the reference to properties of 'x' is null // So it is garbage collected ================================================ FILE: advanced/7. garbage-collector/Examples/example4.js ================================================ /* We know that for interlinked/circular objects Reference Counting Algorithm doesn't work. Here in this example we will see how we can manually make interlinked object garbage collectable. */ function marry(man, woman) { woman.husband = man; man.wife = woman; return { father: man, mother: woman } } let family = marry({ name: "David" }, { name: "Angela" } ) /* Function marry links two objects by giving them references to each other and returns a new object that contains them both. Now all objects are reachable */ console.log(family.father) /* Suppose we want to make "David" unreachable/garbage collected, for that we need to remove all the references of "David" */ family.father = null; family.mother.husband = null; // Now all the references to "David" are gone. So it can be garbage collected ================================================ FILE: advanced/7. garbage-collector/Examples/example5.js ================================================ let user = { name: 'Vivasoft', phone: '017' }; user = 'Vivasoft'; //জখন আমরা ইউজার ভারিয়াবল কে re-assign করলাম, JS দেখল আগের object আর ব্যাবহার হচ্ছেনা //তাই আগের object তাকে garbage হিসাবে মনে করবে function createUser() { var user1 = { }; var user2 = { }; user1.prop = user2; user2.prop = user1; }; createUser(); //যেহেতু user1 এবং user2 এখনো আগের সম্পর্ক বজায়ে রেখেছে, সেহেতু তাদেরকে reference-counting দিয়ে মুছা যাবেনা। //এখানে "Mark and Sweep Algorithm" টা ব্যাবহার করতে হবে। ================================================ FILE: advanced/7. garbage-collector/Examples/example6.js ================================================ let list = []; function addToList() { list.push({name: "Jaber"}) } addToList() console.log(list[0]) // Output: { name: 'Jaber' } list = null; console.log(list) // Output: null //এখন রেফেরেঞ্চ function একটি garbage ================================================ FILE: advanced/7. garbage-collector/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/7. garbage-collector/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: advanced/7. garbage-collector/Practices/practice1.md ================================================ Consider the following scenario. Will the 'Reference counting algorithm' be able to recognize these 2 objects as garbage? Between the two garbage collection algorithms of JS, which one will be more appropriate here and why? ```javascript function circularReference() { var one = {}; var two = {}; one.object = two; two.object = one; } ``` ================================================ FILE: advanced/7. garbage-collector/Practices/practice2.md ================================================ Consider the code below. Why 'orange' object can still access all the property even though 'fruit' is deleted? ```javascript let fruit = { name: "Mango", price: 200, extra: { weight: "2 kg", color: "red" } } let orange = fruit; let mango = fruit.extra; fruit = null; mango = null; console.log(orange.name) ``` ================================================ FILE: advanced/7. garbage-collector/Practices/practice3.md ================================================ নিচের কোডটিতে কোন garbage collection algorithm কাজ করতে পারে? ````js let list = []; function addToList() { list.push({name: "Jaber"}) } addToList() console.log(list[0]) // Output: { name: 'Jaber' } list = null; console.log(list) // Output: null ```` ================================================ FILE: advanced/7. garbage-collector/README.md ================================================ ### Garbage Collector আজকে আমাদের আলোচনার বিষয় হল জাভাস্ক্রিপ্টের Grabage Collector. আমরা জানি Grabage কি? Grabage মূলত এমন জিনিসগুলিকে বোঝায় যা আর ব্যবহারযোগ্য নয়। যখন প্রোগ্রামিংয়ের কথা আসে, Grabage Colllector মানে মেমরি স্পেসগুলি পরিষ্কার করা যাতে দরকারী ডেটা থাকে না এবং তারপর সেই ক্লিয়ার করা মেমোরিকে অন্য কিছু ডেটাতে পুনরায় বরাদ্দ বা Allocate করা হয়। সব প্রোগ্রামিং ভাষায় এটিই Garbage Collector এর প্রাথমিক প্রক্রিয়া। কিছু কিছু প্রোগ্রামিং ল্যাঙ্গুয়েজে Garbage Collector এর জন্য ডেভেলপারের স্পষ্ট হস্তক্ষেপের বা Explicit interference প্রয়োজন হয় আবার অন্য কিছু ল্যাঙ্গুয়েজ Automatically এটি করে থাকে। Low লেভেল প্রোগ্রামিং ল্যাঙ্গুয়েজ যেমন C তে, ডেভেলপারকে malloc () এবং free () এর মত পদ্ধতি ব্যবহার করে মেমরি ক্লিয়ার করার প্রয়োজন হয়। জাভাস্ক্রিপ্টের মত একটি High level প্রোগ্রামিং ল্যাঙ্গুয়েজে, মেমরি Management প্রক্রিয়া স্বয়ংক্রিয়। ব্রাউজার আমাদের জন্য এই কাজটি করে দেয়। এই আলোচনাতে আমারা Grabage Collector এর কয়েকটি বিষয় নিয়ে আলোচনা করব। ১) মেমোরি ম্যানেজমেন্ট Life Cylce. 2) Garbage Collection এলগরিদম। ৩) মেমোরি Leak ### মেমোরি ম্যানেজমেন্ট Life Cylce : চলুন আমরা প্রথমে মেমোরি ম্যানেজমেন্টে Life Cylce এর সাধারন ধাপগুলো দেখি। ১) প্রথম ধাপে আমরা যখন একটি Variable, ফাংশন বা Object declare করি ঠিক তখনই এটির জন্য একটি মেমরি Space বরাদ্দ করা হয়। ২) পরের ধাপে, বরাদ্দকৃত মেমরি রিড/রাইট অপারেশন দ্বারা ব্যবহৃত হয়। ৩) শেষের ধাপে, যখন মেমরির আর প্রয়োজন হয় না, তখন মেমরির জন্য বরাদ্দকৃত স্থানটি ছেড়ে দেয়া হয়। শেষের ধাপটিকে আমরা Garbage Collection বলতে পারি। জাভাস্ক্রিপ্টে এই কাজটি Automatically বা স্বয়ংক্রিয়ভাবে হয়ে থাকে। Garbage Collection যে বা যার মাধ্যমে এই কাজটি করে থাকে তাই হল Garbage Collector. Garbage Collector এর মূল উদ্দেশ্য হল, মেমোরি Allocation কে মনিটর করা এবং মেমরির আর প্রয়োজন আছে কিনা তা নির্ধারণ করা আর যদি মেমোরির প্রয়োজন না হয় তবে এটিকে পুনরুদ্ধার করা। ### Garbage Collection এলগরিদম জাভাস্ক্রিপ্টে Garbage Collection প্রক্রিয়াটি দুটি অ্যালগরিদম দ্বারা পরিচালিত হয় যা নীচে তালিকাভুক্ত করা হয়েছে। ১) Reference Counting Algorithm ২) Mark and Sweep Algorithm আসুন এই অ্যালগরিদমগুলোকে বোঝার চেষ্টা করি। ### Reference Counting Algorithm: প্রথমে রেফারেন্স কি তা বোঝার চেষ্টা করি। একটি Object অন্য একটি Object কে রেফারেন্স করছে এটির মানে হল, প্রথম Object টি দ্বিতীয় Object এর মেথড বা প্রপার্টিগুলোকে অ্যাক্সেস করতে পারছে। চলুন এখন সরাসরি অ্যালগরিদমে যাওয়া যাক। Reference Counting অ্যালগরিদমের মূল বিষয়টি খুবই সিম্পল। এইটি লক্ষ্য করে যে একটি Object অন্য কোন Object কে রেফারেন্স করছে কিনা। যদি না করে তবে Object টিকে Garbage হিসেবে চিহ্নিত করে । একটি উদাহরন দেখা যাক। ```js var obj = { // first object created property1: { // second object created property2 : 10 } } ``` উপরের কোডটি লক্ষ্য করে দেখুন, দুইটি Object তৈরি হয়েছে একটি হল ```obj``` আর অন্যটি হল ```property1``` এবং একটি Object এর প্রপার্টি হিসেবে অন্য Object কাজ করছে। সুতরাং ```Obj``` Object টি দ্বিতীয় Object টিকে রেফারেন্স করছে তাই এখানে Garbage Collection এর কোন সুযোগ নেই। ```js var newObj = obj; // Now we have another to the existing objects. obj = 10; // Still the objects are referenced by the newObj variable. So there is no chance of Garbage Collection ``` চলুন আরেকটি Implementation দেখি। ```js var anotherObj = newObj.property1; ``` একটু লক্ষ্য করে দেখুন, এখন ```property1``` এর দুইটি Reference রয়েছে। একটি হল ```newObj``` variable এর আর অন্য Reference টি হল ```anotherObj``` variable এর। যেহেতু Reference আছে তাই Garbage Collection এর কোন সুযোগ নেই এখানে। ```js newObj = ‘Some string’; ``` এখন ```newObj``` এর কোন Reference নেই। কিন্তু ```property1``` এখনও ```anotherObj``` variable কে Reference করছে। এখানেও তাই Garbage Collection এর কোন সুযোগ নেই। ```js anotherObj = null; ``` এখন ```anotherObj``` variable ও ```property1``` এর কোন Reference নেই। এক্ষেত্রে Object টি Garbage হিসেবে Consider হবে। ```js function foo() { var obj1 = {}; var obj2 = {}; obj1.a = obj2; obj2.a = obj1; console.log(obj1); console.log(obj2); } foo(); ``` উপরের কোডটি লক্ষ্য করুন, এখানে Circular Reference হচ্ছে। একটি Object অন্য একটি Object কে Reference করছে। এক্ষেত্রে, Reference Counting Algorithm কাজ করতে পারে না। এজন্য আমদের পরবর্তী অ্যালগরিদম Mark and Sweep Algorithm এর সাহায্য নিতে হবে। তাহলে চলুন Mark and Sweep Algorithm নিয়ে আলোচনা শুরু করা যাক। ### Mark and Sweep Algorithm: এই অ্যালগরিদমটি একটু ভিন্নভাবে কাজ করে। এই অ্যালগরিদমটি Object এর কাছে পৌঁছাতে পারছে কিনা তার উপর নির্ভর করে Garbage Collection করে। একটু জটিল মনে হতে পারে কিন্তু ভয় পাওয়ার কিছু নেই। জাভাস্ক্রিপ্ট প্রথমে Root Object কে (Window Object ) চিহ্নিত করে এরপর এটি অন্য Child Object এর ট্রাভেরস করে তারপর Child Object এর Chilern কে ট্রাভেরস করে। এভাবে যদি কোন Object এ পৌঁছানো না যায় তবে জাভাস্ক্রিপ্ট এটিকে Garbage হিসেবে চিহ্নিত করে এবং Object এর জন্য বরাদ্দকৃত মেমোরি খালি করে ফেলে। এভাবে এই অ্যালগরিদমটি অনেক Efficiently Circular Reference এর সমস্যাটি যা আমরা Reference Counting অ্যালগরিদমে দেখেছিলাম তার সমাধান করতে পারে। ### মেমোরি Leak: একজন ডেভেলপার তার প্রোজেক্ট এ মেমোরি Leak প্রতিরোধ করার জন্য অনেক কিছুই করে থাকেন। তারপরও মেমোরি Leak এর কিছু সাধারন কারণ সম্পর্কে জেনে থাকা ভাল। কিছু সাধারন কারণ নিয়ে নিচে আলোচনা করা হল। ১) Globals এর অতিরিক্ত ব্যবহার। হউক সেটা অতিরিক্ত গ্লোবাল Variable ব্যবহারের জন্য বা লোকাল Scope এ ```var``` keyword এর ব্যবহার না করার জন্য। ২) Timer গুলোকে ক্লিয়ার করতে ভুলে গেলে। উদাহরনস্বরূপ: ```setInterval()```. ৩) ```closure``` এর অপ্রয়োজনীয় ব্যবহার এর জন্য। আমরা কাজ করার সময় অবশই এই বিষয়গুলো সতর্ক থাকব যাতে পরবর্তীতে মেমোরি Leak না হয়। এই ছিল Garabage Collector নিয়ে কিছু কথা। পরবর্তীতে অন্য কোন বিষয় নিয়ে আবার কথা হবে। হ্যাপি কোডিং। ================================================ FILE: advanced/README.md ================================================ ## Table of contents 1. [Call, Apply, and Bind methods (কল, এপ্লাই এবং বাইন্ড মেথডস)](1.%20call-apply-bind-methods) 2. [Factory Pattern (ফ্যাক্টরি প্যাটার্ন)](2.%20factory-pattern) 3. [Constructor Pattern (কন্সট্রাক্টর প্যাটার্ন)](3.%20constructor-pattern) 4. [Prototype (প্রোটোটাইপ)](4.%20prototype) 5. [Prototypical Inheritance (প্রোটোটাইপিক্যাল ইনহেরিটেন্স)](5.%20prototypical-inheritance) 6. [Event Loop (ইভেন্ট লুপ)](6.%20event-loop) 7. [Garbage Collector (গার্বেজ কালেক্টর)](7.%20garbage-collector) ================================================ FILE: basic/1. execution-context/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/1. execution-context/Examples/example1.js ================================================ {/* There are three types of Execution Context in javascript. 1.Global Execution Context(GEC) 2.Functional Execution Context(FEC) 3.Eval Execution Context Any JS code that gets executed within the eval function creates and holds its own execution context. However, the eval function is not used by the JavaScript developers, but it is a part of the Execution Context. At first the program will execute inside the global execution context. But if the program call a function then it will creates a new functional execution context. When function return anything then the FEC will be removed from call stack and returned value will be pass into the GEC again the */} let x = 10; function timesTen(a){ return a * 10; } let y = timesTen(x); console.log(y); {/* output: 100 */} ================================================ FILE: basic/1. execution-context/Examples/example2.js ================================================ {/* Time Tide and Javascript waits for none. The function fn has an asynchrous function setTimeout with a timer of 5 sec. As we know javascript has only a call stack to execute all code, so it never waits for the timeout. Js engine will send the function to the dom api and move on to the next line of code */} console.log('first output of global execution context') function fn(){ console.log('waiting for timeout...') setTimeout(()=>{ console.log('Output in Functions local execution contex') },5000) } fn() console.log('last output of global execution context') {/* output: first output of global execution context waiting for timeout... last output of global execution context Output in Functions local execution contex ie:Time and Js wait for none */} ================================================ FILE: basic/1. execution-context/Examples/example3.js ================================================ {/* Here we store the return value for average(10, 20) in variable x within the global execution context. So when the average function called, a functional execution context will creates for function average inside the call stack. Inside average we call function add. so Another functional execution context will create for add function in the call stack. When the add function return anything then the functional execution context will be removed from the call stack and the return value will be returned to the functional execution context of average from where the function add was called. Again when average function return anything then its functional execution context will also removed from the call stack and the return value will also returned th the global execution context from where the average function was called */} function add(a, b) { return a + b; } function average(a, b) { return add(a, b) / 2; } let x = average(10, 20); console.log(x) {/* output: 15 */} ================================================ FILE: basic/1. execution-context/Examples/example4.js ================================================ {/* Time Tide and Javascript waits for none. The function fn has an asynchrous function setTimeout with a timer of 5 sec. As we know javascript has only a call stack to execute all code, so it never waits for the timeout. Js engine will send the function to the dom api and move on to the next line of code */} onsole.log('First Output Inside the Global Execution context') function fn1(){ setTimeout(()=>{ console.log('Inside function fn1 with the SetTimeout of 3 seconds') },3000) } function fn2(){ console.log('inside function fn2') } setTimeout(()=>{ console.log('Inside the Global Execution context With SetTimeout of 10 seconds') },10000) setTimeout(()=>{ console.log('Inside the Global Execution context With SetTimeout of 3 seconds') },3000) fn1() fn2() fn3() function fn3(){ console.log('Inside function fn3') } console.log('Last line Output of Global Execution Context') {/* output: First Output Inside the Global Execution context inside function fn2 Inside function fn3 Last line Output of Global Execution Context Inside the Global Execution context With SetTimeout of 3 seconds Inside function fn1 with the SetTimeout of 3 seconds Inside the Global Execution context With SetTimeout of 10 seconds */} ================================================ FILE: basic/1. execution-context/Examples/example5.js ================================================ /* Global Execution Context GEC / Global Execution Context is also called the base/default execution. Any JavaScript code which does not reside in any function will be present in the global execution context. The reason behind its name 'default execution context' where the code begins its execution when the file first loads in the web browser. GEC performs the two following tasks: Firstly, it creates a global object where it is for Node.js and Window object for the browsers. Secondly, reference the Windows object to 'this' keyword. Create a memory heap in order to store variables and function references. Then it stores all the functions declarations in the memory heap area and the variables in the GEC with initial values as 'undefined'. Function statement is hoisted , so we can called a function statent before the declarations */ } let globalVar = "Variable from Global skope"; function a() { console.log("Inside a"); console.log(globalVar); console.log(); let x = "functional skope of function a"; b(); function b() { console.log("Inside b"); let y = "functional skope of function b"; console.log(globalVar); console.log(x); console.log(); c(); function c() { console.log("Inside c"); let y = "functional skope of function b"; console.log("value of x : ", x); console.log(globalVar); console.log(y); var x = "functional skope of function c"; console.log("value of x : ", x); } } } a(); { /* output: Inside a Variable from Global skope Inside b Variable from Global skope functional skope of function a Inside c value of x : undefined Variable from Global skope functional skope of function b value of x : functional skope of function c */ } ================================================ FILE: basic/1. execution-context/Examples/example6.js ================================================ /* এক্সিকিউশন স্ট্যাকের কাজের প্রক্রিয়াটি বোঝার জন্য, নীচে দেওয়া একটি উদাহরণ কোড বিবেচনা করুন: ব্যাখ্যা: * প্রথমত, সমস্ত কোড ব্রাউজারে লোড করা হয়। * এর পরে, JS ইঞ্জিন এক্সিকিউশন স্ট্যাকের শীর্ষে GEC push/insert করে। * যত তাড়াতাড়ি JS ইঞ্জিন প্রথম ফাংশন কলের সম্মুখীন হয়, এটি এটির জন্য একটি নতুন FEC সেট করে এবং এটি বর্তমান এক্সিকিউশন স্ট্যাকের শীর্ষে যোগ করে। * তারপর আমরা দেখতে পারি যে এটি প্রথম ফাংশনের মধ্যে দ্বিতীয় ফাংশনের Call। অতএব JS ইঞ্জিন দ্বিতীয় ফাংশনের জন্য একটি নতুন FEC সেটআপ করে এবং এটি স্ট্যাকের শীর্ষে যোগ করে। * যখন দ্বিতীয় ফাংশন সম্পন্ন হয়, এক্সিকিউশন ফাংশনটি স্ট্যাকের বাইরে চলে যায় এবং নিয়ন্ত্রণগুলি স্ট্যাকের মধ্যে উপস্থিত পরবর্তী এক্সিকিউশন প্রসঙ্গে চলে যায়, যা শুধুমাত্র প্রথম ফাংশন এক্সিকিউশন প্রসঙ্গ। * যখন প্রথম ফাংশনটি সম্পূর্ণভাবে সম্পন্ন হয়, তখন প্রথম ফাংশনের এক্সিকিউশন স্ট্যাক, স্ট্যাক থেকে বেরিয়ে আসে। অতএব, নিয়ন্ত্রণটি কোডের GECতে ফিরে আসে। * শেষ পর্যন্ত, যখন সম্পূর্ণ কোডের এক্সিকিউশন সম্পন্ন হয়, JS ইঞ্জিন GEC কে বর্তমান স্ট্যাক থেকে সরিয়ে দেয়। */ let x = "Hello Execution context!"; function a() { console.log("This is the first function execution"); function b() { console.log("This is the second function execution"); } b(); } a(); console.log("It is GEC. " + x); /* Output: This is the first function execution This is the second function execution It is GEC. Hello Execution context! */ ================================================ FILE: basic/1. execution-context/Examples/stackOverflow.js ================================================ {/* Here foo function called itself again and again. So the call stack will store the same copy of foo for each function call And a functional execution context will create for every call inside the call stack. These cause the stack overflow. Because Call stack also has an specific memory limit */} function foo() { foo(); } foo(); {/* Uncaught RangeError: Maximum call stack size exceeded at foo (:2:5) at foo (:2:5) at foo (:2:5) at foo (:2:5) at foo (:2:5) at foo (:2:5) at foo (:2:5) at foo (:2:5) at foo (:2:5) at foo (:2:5) */} ================================================ FILE: basic/1. execution-context/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/1. execution-context/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/1. execution-context/Practices/practice1.md ================================================ নিচের কোড দেখুন। ভেরিয়েবল a এর মান check() ফাংশনের মধ্যে পরিবর্তন করা কি সম্ভব? check() ফাংশনের বাইরে ভেরিয়েবল b কে একসেস করা কি সম্ভব? এক্সিকিউশন কন্টেক্সট এর উপর ভিত্তি করে হ্যাঁ অথবা না উভয় ক্ষেত্রে আপনার যুক্তি ব্যাখ্যা করুন। ```javascript let a = 12; function check() { let b = 23; a = 44; // Will it change the value of the variable a? } console.log(a); check(); console.log(a); b = 55; // Is it possible? ``` একটি প্রোগ্রামে কয়টি গ্লোবাল এক্সিকিউশন কন্টেক্সট ও কয়টি ফাংশনাল এক্সিকিউশন কন্টেক্সট থাকতে পারে? নীচের প্রোগ্রামটি রান করলে কয়টি গ্লোবাল ও ফাংশনাল এক্সিকিউশন কন্টেক্সট তৈরী করবে? ```javascript function a() { console.log('Function a() executed'); function b() { console.log('Function b() executed'); } function c() { console.log('Function c() executed'); function cc() { console.log('Function cc() executed'); } } } function d() { console.log('Function d() executed'); function e() { console.log('Function e() executed'); function ee() { console.log('Function ee() executed'); } } e(); } a(); d(); ``` ================================================ FILE: basic/1. execution-context/Practices/practice2.md ================================================ ```JavaScript let num = 5; const changeNum = () => { let num; num = 72; console.log(num); } changeNum(); console.log(num); ``` উপরের কোডের আউটপুট কি হবে? যদি changeNum() ফাংশনের ভেতরে গ্লোবাল ভ্যারিয়েবল num -এর মান পরিবর্তন না হয় তাহলে আমরা কিভাবে সেটা করতে পারবো? ================================================ FILE: basic/1. execution-context/README.md ================================================ ### এক্সিকিউশন কন্টেক্সট কি? > এক্সিকিউশন কন্টেক্সট একটি এনভাইরনমেন্ট যেখানে জাভাস্ক্রিপ্ট কোড এক্সিকিউট করা হয়। যখনই জাভাস্ক্রিপ্টে কোন কোড রান করা হয়, এটি একটি এক্সিকিউশন কন্টেক্সটের মধ্যে রান করা হয়। ### জাভাস্ক্রিপ্টে তিন ধরনের এক্সিকিউশন কন্টেক্সট আছেঃ- - **গ্লোবাল এক্সিকিউশন কন্টেক্সট -** এটি ডিফল্ট এক্সিকিউশন কন্টেক্সট। যে কোডটি কোন ফাংশনের ভিতরে নেই তা গ্লোবাল এক্সিকিউশন কন্টেক্সটে আছে। এটি দুটি জিনিস সম্পন্ন করেঃ - এটি একটি গ্লোবাল অবজেক্ট তৈরি করে যা ব্রাউজারের ক্ষেত্রে **window** অবজেক্ট এবং নোডের ক্ষেত্রে **global** অবজেক্ট নামে পরিচিত। - **this** এর ভ্যালু হিসাবে গ্লোবাল অবজেক্টকে সেট করে। একটি প্রোগ্রামে শুধুমাত্র একটি গ্লোবাল এক্সিকিউশন কন্টেক্সট থাকতে পারে। - **ফাংশন এক্সিকিউশন কন্টেক্সট -** যখনই কোন ফাংশন কল করা হয়, সেই ফাংশনের জন্য জেএস ইঞ্জিন একটি নতুন এক্সিকিউশন কন্টেক্সট তৈরি করে। প্রতিটি ফাংশনের নিজস্ব এক্সিকিউশন কন্টেক্সট আছে। একাধিক সংখ্যক ফাংশন এক্সিকিউশন কন্টেক্সট হতে পারে। ফাংশন এক্সিকিউশন কন্টেক্সটের গ্লোবাল এক্সিকিউশন কন্টেক্সটের সকল কোড অ্যাক্সেস আছে যদিও গ্লোবাল কন্টেক্সটের ফাংশন এক্সিকিউশন কন্টেক্সটের কোডের অ্যাক্সেস নেই। গ্লোবাল এক্সিকিউশন কন্টেক্সটের কোড এক্সিকিউট করার সময় যদি জেএস ইঞ্জিন কোন ফাংশন কল পায়, এটি সেই ফাংশনের জন্য একটি নতুন ফাংশন এক্সিকিউশন কন্টেক্সট তৈরি করে। ব্রাউজার কন্টেক্সটে, যদি কোড strict মোডে এক্সিকিউট করা হয়, তাহলে **this** এর ভ্যালু **undefined** অন্যথায় **window** অবজেক্ট হবে ফাংশন এক্সিকিউশন কন্টেক্সট। - **ইভাল এক্সিকিউশন কন্টেক্সট -** ইভাল ফাংশনের ভিতরে এক্সিকিউশন কন্টেক্সট। **নিম্নলিখিত কোড দেখুনঃ** ```js let a = 7; const multByTen = (a) => a * 10; let results = multByTen(a); console.log(results); // 70 ``` **উপরের কোডে লক্ষ্য করুনঃ** - প্রথমে, a ভ্যারিয়েবলে 7 অ্যাসাইন করা হয়েছে। - দ্বিতীয়ত, একটি ফাংশন multByTen() ডিক্লেয়ার করা হয়েছে যা 10 এর সাথে তার আর্গুমেন্ট কে গুণ করে। - তৃতীয়ত, একটি প্যারামিটার হিসাবে a পাস করে multByTen() ফাংশনকে কল করে এবং ভ্যারিয়েবল results - এ রিটার্ন মান অ্যাসাইন করা হয়েছে। - পরিশেষে, কনসোলে ভ্যারিয়েবল results আউটপুট করা হয়েছে। অনেক সহজ কোডটা তাই না? যাইহোক, বিহাইন্ড দ্যা সিন জাভাস্ক্রিপ্ট অনেক কিছু করে। ইতিমধ্যে আমরা এক্সিকিউশন কন্টেক্সট সম্পর্কে জেনে গেছি। কিন্তু প্রতিটি এক্সিকিউশন কন্টেক্সটে দুটি করে phases আছেঃ ১। creation phase এবং ২। execution phase। ### ১। Creation phase - একটি গ্লোবাল অবজেক্ট তৈরি করে অর্থাৎ, ওয়েব ব্রাউজারে **window** বা নোড জেএসে **global**। - **this** নামে একটি গ্লোবাল ভ্যারিয়েবল তৈরি করে যা গ্লোবাল অবজেক্টকে নির্দেশ করে। - সকল ভ্যারিয়েবল এবং ফাংশনের জন্য একটি মেমোরি স্পেস সেটআপ করে। - ভ্যারিয়েবলের ডিফল্ট ভ্যালু হিসাবে **undefined** অ্যাসাইন করে এবং ফাংশন ডিক্লেয়ারেশনগুলি হীপ মেমোরিতে স্টোর করে। আমাদের উদাহরণে, creation phase - এ জাভাস্ক্রিপ্ট ইঞ্জিন গ্লোবাল এক্সিকিউশন কন্টেক্সটে ভ্যারিয়েবল a ও results এবং ফাংশন ডিক্লেয়ারেশন multByTen() স্টোর করে। এছাড়াও, এটি ভ্যারিয়েবল a এবং results কে undefined হিসাবে ইনিশিয়ালাইজ করে। > #### Global Execution Context (Creation Phase Browser) > > - **window**: Global Object > - **this**: window > - **a**: undefined > - **multByTen**: fn() > - **results**: undefined Creation phase এর পর, গ্লোবাল এক্সিকিউশন কন্টেক্সট execution phase শুরু করে। ### ২। Execution phase Execution phase - এ, জাভাস্ক্রিপ্ট ইঞ্জিন লাইন বাই লাইন কোড এক্সিকিউট করে। এই phase -এ, এটি ভ্যারিয়েবলের মান অ্যাসাইন করে এবং ফাংশন কল এক্সিকিউট করে। > #### Global Execution Context (Execution Phase Browser) > > - **window**: Global Object > - **this**: window > - **a**: 7 > - **multByTen**: fn() > - **results**: multByTen(a) আমরা আগেই জেনেছি প্রতিটি ফাংশন কলের জন্য জাভাস্ক্রিপ্ট ইঞ্জিন একটি নতুন ফাংশন এক্সিকিউশন কন্টেক্সট তৈরি করে। ফাংশন এক্সিকিউশন কন্টেক্সট গ্লোবাল এক্সিকিউশন কন্টেক্সটের মতই কিন্তু ফাংশন এক্সিকিউশন কন্টেক্সট গ্লোবাল অবজেক্ট তৈরি করার পরিবর্তে এটি **arguments** অবজেক্ট তৈরি করে যা ফাংশনে পাস করা সকল প্যারামিটারের একটি রেফারেন্স ধারণ করে: > #### Function Execution Context (Creation Phase Browser) > > - **arguments**: Local Object > - **this**: window > - **a**: undefined আমাদের উদাহরণে, ফাংশন এক্সিকিউশন কন্টেক্সট **arguments** অবজেক্ট তৈরি করে যা ফাংশনে পাস করা সকল প্যারামিটারকে নির্দেশ করে, **this** এর মান হিসাবে গ্লোবাল অবজেক্টে **window** কে সেট করে এবং **a** প্যারামিটার কে **undefined** হিসাবে ইনিশিয়ালাইজ করে। > #### Function Execution Context (Execution Phase Browser) > > - **arguments**: Local Object > - **this**: window > - **a**: 7 ফাংশন এক্সিকিউশন কন্টেক্সটে **Execution phase** চলার সময়, এটি **a** প্যারামিটারে **7** অ্যাসাইন করে এবং ফলাফল **(70)** গ্লোবাল এক্সিকিউশন কন্টেক্সটের **results** ভ্যারিয়েবলে রিটার্ন করেঃ > #### Global Execution Context (Execution Phase Browser) > > - **window**: Global Object > - **this**: window > - **a**: 7 > - **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) ================================================ FILE: basic/10. browser-storage-and-caching/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/10. browser-storage-and-caching/Examples/example1.js ================================================ /* In this example, we will learn about localStorage of a browser. As we already know, in localStorage the data is persisted until the user manually clears the browser cache or until your web app clears the data. */ // To create a entity we need to use a function named setItem // which takes key and value as parameters localStorage.setItem("item1", "Football") // we can read this by using getItem localStorage.getItem("item1") // we can also update the existing item by using setItem localStorage.setItem("item1", "Cricket") // we can delete the item using removeItem localStorage.removeItem("item1") // we can also clear everything that stored in localStorage by using this localStorage.clear() /* We can also use these 4 methods in sessionStorage. like, sessionStorage.setItem(), sessionStorage.getItem(), sessionStorage.removeItem() and sessionStorage.clear() */ ================================================ FILE: basic/10. browser-storage-and-caching/Examples/example2.js ================================================ /* Only strings can be stored with localStorage or sessionStorage, but we can use JSON.stringify to store more complex objects. */ // Create item let person = {name: "mehedi", designation: "Front End Developer"} localStorage.setItem("person1", JSON.stringify(person)) // Read item let item = JSON.parse(localStorage.getItem("person1")) ================================================ FILE: basic/10. browser-storage-and-caching/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/10. browser-storage-and-caching/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/10. browser-storage-and-caching/Practices/practice1.md ================================================ Consider the object below. Suppose we want to store this object in the localStorage and sessionStorage of our browser. How can we do that? Also how can you can read this object from the localStorage and sessionStorage? ```javascript let team = { name: "Real Madrid", ucl: 13, laliga: 33 } ``` ================================================ FILE: basic/10. browser-storage-and-caching/README.md ================================================ ### Browser Storage ওয়েব অ্যাপস/সাইটগুলিতে অফলাইন/Cache মেকানিজম প্রদান করার জন্য Browser Storage ব্যবহার করে: - 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 হলো: 1. sessionStorage.setItem('key', 'value') 2. sessionStorage.getItem('key') 3. sessionStorage.removeItem('key') - 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 কীভাবে কাজ করে তা বোঝার জন্য আসুন এই দুটি ক্ষেত্রে দেখি: **Case 1: A first-time user** আপনি যখন প্রথমবার কোনো ওয়েবসাইট ভিজিট করেন, তখন ওয়েব ব্রাউজার ওয়েব সার্ভার থেকে ডেটা (HTML, CSS, JS) সংগ্রহ করবে। এর কারণ হলো ওয়েব রিসোর্সগুলি এখনও Cache সংরক্ষণ করা হয়নি। ওয়েব ব্রাউজার তারপর ওয়েবসাইটটিতে পরবর্তী পরিদর্শনে user experience উন্নত করতে একটি Cache এ ওয়েব resource গুলি সংরক্ষণ করবে। **Case 2: The user used the website before** যদি কোনো ব্যবহারকারী একই কম্পিউটার ডিভাইস ব্যবহার করে দ্বিতীয়বার কোনো ওয়েবসাইট পরিদর্শন করেন, ওয়েবসাইটটি প্রথম দর্শনের চেয়ে দ্রুত লোড হবে। কারণ ওয়েব ব্রাউজার Cache থেকে images, CSS এবং Javascript এর মতো স্ট্যাটিক ওয়েব রিসোর্স পুনরুদ্ধার করবে। HTTP response headers সাধারণত Caching এর জন্য ব্যবহৃত হয়. একটি ওয়েবসাইটের মালিকের cache policy এর উপর নিয়ন্ত্রণ থাকে। এই নিয়ন্ত্রণ HTTP Cache হেডার ব্যবহার করে ব্যবহার করা হয়। এই headers মেয়াদ শেষ হওয়ার আগে ওয়েব resource কে Cache করা যেতে পারে এমন সর্বাধিক সময় নির্ধারণ করতে ব্যবহৃত হয়। নিম্নলিখিত HTTP response headers সাধারণত Cache করার জন্য ব্যবহৃত হয়: **ETag:** এটি '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 করতে পারে। - no-store: এই নির্দেশিকা ব্রাউজারকে Cache না করার নির্দেশ দেয়। - 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. ================================================ FILE: basic/11. debouncing-and-throttling/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/11. debouncing-and-throttling/Examples/example1.html ================================================ Throttling ================================================ FILE: basic/11. debouncing-and-throttling/Examples/example2.html ================================================ Debouncing Example ================================================ FILE: basic/11. debouncing-and-throttling/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/11. debouncing-and-throttling/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/11. debouncing-and-throttling/Practices/practice1.md ================================================ Consider this scenario. If someone moves his mouse on the map, we are displaying the location coordinates of the mouse pointer. In this scenario, which formula we should use? Debouncing or Throttling? ================================================ FILE: basic/11. debouncing-and-throttling/README.md ================================================ ### Debouncing and 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 করতে পারি। চলুন, আমাদের প্রথম debounce ছাড়া আমাদের কোডটা কেমন হবে তা দেখি। ```html ``` আমরা সাধারণত Search Functionality গুলো onChange অথবা onKeyUp ইভেন্টের মাধ্যমে করে থাকি। এখন আমরা আমারদের `searchHandler` ফাংশনটা লিখে ফেলি। ```js function searchHandler(...args) { /* Here we are capturing the search query entered by customer */ const { value } = args[0].target; /* Make an API call with search query */ getSearchResults(value); } ``` আশা করছি এই পর্যন্ত বুঝতে কোন সমস্যা হচ্ছে না। তাহলে চলুন আমরা একটা reusable Debounce ফাংশন লিখে ফেলি। ```js const optimisedSearchHandler = debounceFunc(searchHandler, 500); const debounceFunc = (func, delay) => { let timer; return function (...args) { const context = this; clearTimeOut(timer); timer = setTimeOut(() => { func.apply(context, args); }, delay); }; }; ``` উপরের কোডটা একটু লক্ষ্য করে দেখুন, যখন আমরা সার্চবার এ কিছু লিখার সাথে সাথে এ API কল করছে না। এটি আমাদের সার্চবার এ কিছু লিখার পর একটা নিদিষ্ট সময় অপেক্ষা করছে যদি এর মধ্যে সার্চবার এ আর নতুন কিছু টাইপ করা না হয় তবেই এটি API কে কল করছে। এতে করে আমাদের API কল এর পরিমাণ অনেকখানি কমে গেল। তাহলে চলুন, আমরা আমাদের সার্চবারের `onChange` debounce Technique টা ব্যবহার করে ফেলি। ```html ``` চলুন, এবার `Throttling` নিয়ে আলোচনা করা যাক। ### Throttling ### Throttling আসলে কি? Throttling এমন একটি Technique যার মাধ্যমে Event Handler এর অ্যাকশানকে Limited করা যায়। অর্থাৎ একটা Event কল হবার পর সুনিদিষ্ট টাইম এর মধ্যে ওই Event আর কল হবে না। বুঝার সুবিধার জন্য আমরা একটা উদাহরনস্বরূপ শুটিংগেমের কথা চিন্তা করতে পারি। একটি শুটিং গেমে বেশ কয়েক ধরনের অস্ত্র থাকতে পারে। প্রতিটি অস্ত্রেরই একটি Fire এর পর পরবর্তী Fire এর জন্য প্রস্তুত হতে কিছু টাইম লাগে। যেমন ShortGun এর ক্ষেত্রে যে সময় লাগবে MachineGun এর ক্ষেত্রে আরও কম সময় লাগবে। ধরি, shortGun এর জন্য এই সময় 500ms আর MachineGun এর জন্য এই টাইম 100ms. তাই আমাদের এমন একটা লজিক সেট করতে হবে যাতে করে User যে অস্ত্র ব্যবহার করুক না কেন, যদি সে Threshold টাইমের মধ্যে একাধিক বার Fire করে তবে শুধুমাত্র একটা Fireই কাজ করবে। আর Fire গুলো নিদিষ্ট সময়ের পর এক এক করে Fire করবে। চলুন তাহলে Trigger ক্লিকের একটা Event Handler তৈরি করে ফেলি। ```js window.addEventListener(onclick, handlerTrigger); const handlerTrigger = () => { fireShot(); }; ``` উপরের কোডটি লক্ষ্য করুন, User যখনই Trigger press করছে শট Fire হচ্ছে। তাহলে চলুন এখন আমরা Throttle ফাংশন লিখে ফেলি যার parameter এ `handlerTrigger` ফাংশন আর Time Interval কে পাঠাবো। ```js const optimisedTriggerHandler = throttleFunc(handlerTrigger, 100); const throttleFunc = (func, interval) => { let shouldFire = true; return function () { if (shouldFire) { func(); shouldFire = false; setTimeOut(() => { shouldFire = true; }, interval); } }; }; ``` তাহলে চলুন, এখন আমরা আমাদের Event Listener ফাংশনটি আপডেট করে ফেলি। ```js window.addEventListener(onclick, optimisedTriggerHandler); ``` ঠিক এইভাবে আমরা বিভিন্ন Time Interval সেট করে `optimisedTriggerHandler` কে বিভিন্ন অস্ত্রের জন্য ব্যবহার করতে পারি। আমরা এখন পর্যন্ত Debouncing and Throttling দুইটি Techniqueই দেখলাম। এই দুইটি পদ্ধতি concept খুব কাছাকাছি হলে মূল পার্থক্য হল, Debouncing এর ক্ষেত্রে User এর অ্যাকশান কে মনিটর করি এবং Threshold Time এর মধ্যে আবার যদি কোন নতুন অ্যাকশান আসে তবে আবার নতুন করে Threshold Time পর্যন্ত অপেক্ষা করি API কল এর জন্য। অন্যদিকে, Throttling এর ক্ষেত্রে আমরা আমাদের predetermined time interval পর API কল করে দেই। আশা করি, Debouncing and Throttling বুঝতে আর কোন সমস্যা হবার কথা না। পরবর্তীতে আবার নতুন কোন বিষয় নিয়ে আবার কথা হবে। সে পর্যন্ত হ্যাপি কোডিং। ================================================ FILE: basic/12. use-strict/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/12. use-strict/Examples/example1.js ================================================ // In this example we will see some usage of "strict mode". // As we already know, "use strict" defines that JavaScript code // should be executed in "strict mode", which is safer feature set of javascript. // if we declare "use strict" at the beginning of a script, it has global scope // Deleting a variable, function or object is not allowed in strict mode "use strict"; let x = 10; delete x; // Output: // SyntaxError: Delete of an unqualified identifier in strict mode. function myFunction(){ console.log("Hello") } delete myFunction; // Output: // SyntaxError: Delete of an unqualified identifier in strict mode. let person = { name: "Mehedi", age: 24 } delete person; // Output: // SyntaxError: Delete of an unqualified identifier in strict mode. ================================================ FILE: basic/12. use-strict/Examples/example2.js ================================================ // Normally, we can use keywords such as eval, arguments as variable names // but using strict mode, we cannot do that "use strict" let eval = 10; console.log(eval) // Output: // SyntaxError: Unexpected eval or arguments in strict mode let arguments = 20; console.log(arguments) // Output: // SyntaxError: Unexpected eval or arguments in strict mode // Keywords reserved for future JavaScript versions also cant be used as variable names in strict mode. // Such as public, private, protected, static, interface, implements etc. ================================================ FILE: basic/12. use-strict/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/12. use-strict/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/12. use-strict/Practices/practice1.md ================================================ Consider this code below. Will it give an error? ```javascript let name = "Mehedi"; function printName(name){ "use strict" console.log(name); let age = 24; delete age } ``` ================================================ FILE: basic/12. use-strict/README.md ================================================ প্রায় সব ল্যাংগুয়েজেরই নিজস্ব একটা ডকুমেন্ট আছে। যার মাধ্যমে আমরা ঐ ল্যাংগুয়েজের ভাল কিংবা খারাপ দিক অথবা ভাল প্র্যাকটিস এবং খারাপ প্র্যাকটিস সম্পর্কে জানতে পারি। কিন্তু জাভাস্ক্রিপ্টের এই রকম কোন কিছু নেই। যে কারণে এখানে ভুলটা বেশি হবার সুযোগ থাকে এবং সবাই নিজের মত করে কোড লিখে সে ভুলটা করেও বটে। যেগুলো আসলে ভুল সিনট্যাক্স এবং আনসিকিউর কোড। কিন্তু আমরা যখন স্ট্রিক্ট মোড ব্যবহার করি, তখন জাভাস্ক্রিপ্ট কোড কোন ভুল সিনট্যাক্স ছাড়া এক্সিকিউট করে এবং কোড আরও সিকিউর করে। ### “use strict” ডিরেক্টিভঃ- **“use strict”** মোডে আমাদের কোড এক্সিকিউট করতে হলে আমাদেরকে **“use strict”** ডিরেক্টিভ ব্যবহার করতে হবে। এটি একটি এক্সপ্রেশন মাত্র। এটি জাভাস্ক্রিপ্টের ১.৮.৫ (ইএস৫) থেকে সাপোর্ট করে। ### “use strict” এর ব্যবহারঃ- **“use strict”** ডিরেক্টিভকে আমরা দুইভাবে ব্যবহার করতে পারি। গ্লোবাল ডিক্লারেশন হিসাবে এবং ফাংশন ডিক্লারেশন হিসাবে। ### গ্লোবাল ডিক্লারেশনঃ- যখন আমরা গ্লোবাল ডিক্লারেশন হিসাবে **“use strict”** ব্যবহার করি, তখন ঐ পেজের সমস্ত জাভাস্ক্রিপ্ট কোড স্ট্রিক্ট মোডে এক্সিকিউট হয়। ```js "use strict"; console.log("Hello JavaScript"); ``` ### ফাংশন ডিক্লারেশনঃ- যখন আমরা ফাংশন ডিক্লারেশন হিসাবে **“use strict”** ব্যবহার করি, তখন ফাংশনের ভিতরের সমস্ত জাভাস্ক্রিপ্ট কোড স্ট্রিক্ট মোডে এক্সিকিউট হয়। ফাংশনের বাহিরে সব কোড নর্মাল মোডে এক্সিকিউট হয়। ```js (function() { "use strict"; console.log("Hello JavaScript"); })(); ``` ##### উদাহরন – ১ঃ আপনি জাভাস্ক্রিপ্টে ভেরিয়েবল কি-ওয়ার্ড ডিক্লেয়ার না করেও কাজ করতে পারবেন। কারণ আমরা জানি জাভাস্ক্রিপ্টে ভেরিয়েবলের নামের আগে ভেরিয়েবল কি-ওয়ার্ড ব্যবহার না করলে এটি বাই-ডিফল্ট উইন্ডো অবজেক্টের আন্ডারে এক্সিকিউট হয়। ```js num = 10; console.log(num); // 10 ``` একই কোড যখন আমরা **“use strict”** ব্যবহার করে এক্সিকিউট করবো, আমরা একটা Uncaught ReferenceError: num is not defined পাবো। ```js "use strict"; num = 10; console.log(num); // Uncaught ReferenceError: num is not defined ``` #### উদাহরন-২ঃ জাভাস্ক্রিপ্টে আমরা রিজার্ভড কি-ওয়ার্ডগুলো ব্যবহার করতে পারি ভেরিয়েবলের নাম হিসাবে। ```js var let = 10; console.log(let); // 10 ``` কিন্তু **“use strict”** মোডে এটি সম্ভব নয়। কারণ এটি ইএস৬ এর জন্যে একটি রিজার্ভড কি-ওয়ার্ড। ```js "use strict"; var let = 10; console.log(let); // Uncaught SyntaxError: Unexpected strict mode reserved word ``` ### কিছু রিজার্ভড কি-ওয়ার্ডঃ - abstract - instanceof - super - static - package - const - implements - with - private - protected #### উদাহরন – ৩ঃ ফাংশনের ভিতরে **“this”** এর ভ্যালু সব সময় উইন্ডো অবজেক্ট হয়। ```js function showMe() { console.log(this); } showMe(); /// window ``` কিন্তু **“use strict”** মোডে ফাংশনের ভিতরে **“this”** এর ভ্যালু **undefined** হবে। ```js "use strict"; function showMe() { console.log(this); // undefined } showMe(); /// window ``` এই রকম আরও অনেক ব্যবহারের ক্ষেত্র আছে যেটি আপনারা একটু কষ্ট করে নিজ দায়িত্বে দেখে নিবেন। যাইহোক, যেহেতু জাভাস্ক্রিপ্টের জন্যে নির্দিষ্ট কোন ডকুমেন্টস নেই, তাই **“use strict”** ব্যবহার করলে আমরা আমাদের কোডের ডিবাগ করতে সুবিধা হবে। কারণ যদি আমরা কোন ভুল সিনট্যাক্স ব্যবহার করি, জাভাস্ক্রিপ্ট আমাদেরকে ইরর থ্রো করবে। যেটি জাভাস্ক্রিপ্ট সাধরণত করে না। আশা করি, ব্যাপারটা সবাই বুঝতে পারছেন। আর পারবেনই বা কেন? সিম্পল হিসাব, জাভাস্ক্রিপ্ট জিন্দাবাদ। 😛 ================================================ FILE: basic/13. iife-in-javascript/Examples/example1.js ================================================ /* IIFE follow their own scope like any other function/variable in JavaScript. It is confusing sometimes that we might expect the IIFE to execute irrespective of function scope, which is wrong. In this example where the IIFE is defined within a function and will only be immediately invoked if we call the Parent Function. */ function sayName() { console.log("Hello!"); // This will be executed after executing the previous log. (function() { console.log("Mehedi"); })(); console.log("is my name"); } // Calling the parent function. sayName(); /* Output: Hello! Mehedi is my name */ ================================================ FILE: basic/13. iife-in-javascript/Examples/example2.js ================================================ /* We can use IIFEs to create private variables and functions within the global scope, or any other function scope. */ function sayName(){ return "Hello! I am Mehedi"; } console.log(sayName()) var myNumber = 100; console.log(myNumber*2) /* If we load other JavaScript files in our browser, they also gain access to sayName() and myNumber. To prevent them from using or editing them, we encase our code in an IIFE like this code bolw: */ (function(){ function sayName(){ return "Hello! I am Mehedi"; } console.log(sayName()) var myNumber = 100; console.log(myNumber*2) })(); // It runs the same, but now sayName() and myNumber are only accessible in our script. ================================================ FILE: basic/13. iife-in-javascript/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/13. iife-in-javascript/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/13. iife-in-javascript/Practices/practice1.md ================================================ Consider the code written below. What will be the output of this code? ```javascript function sayHello() { console.log("Hello!"); (function(){ console.log("Nice to meet you"); (function(){ console.log("I want to tell you") })(); })(); console.log("something you want to hear"); } // Calling the parent function. sayHello(); ``` ================================================ FILE: basic/13. iife-in-javascript/README.md ================================================ IIFE জাভাস্ক্রিপ্টের অন্যতম জনপ্রিয় একটি ডিজাইন প্যাটার্ন। এটি ইফি বলেই উচ্চারণ করে। IIFE জাভাস্ক্রিপ্ট কমিউনিটি দীর্ঘদিন ধরে ব্যবহার করে আসছে কিন্তু এর মিসলিডিং শব্দটি ছিল "সেলফ-এক্সিকিউটিং এনোনিমাস ফাংশন" যা পরবর্তীতে [Ben Alman](http://benalman.com/) এটির একটি উপযুক্ত নাম দিয়েছেন "IIFE"। আজকে এটার সম্পর্কে বিস্তারিত লেখার চেষ্টা করবো। ### IIFE কি? > IIFE - এর পূর্ণরুপ হচ্ছে Immediately Invoked Function Expression। IIFE হল একটি ফাংশন যা একটি এক্সপ্রেশন হিসাবে ডিক্লেয়ার এবং ডিক্লেয়ারেশনের পরপরই এক্সিকিউট করা হয়। ### IIFE সিনট্যাক্সঃ নিম্নলিখিত সিনট্যাক্স দেখায় কিভাবে IIFE ডিফাইন করতে হয়ঃ ```js (function () { // code goes here... })(); ``` আপনি `arrow function` ব্যবহার করেও IIFE ডিফাইন করতে পারবেন। ```js (() => { // code goes here... })(); ``` ### IIFE কেনঃ যখন আপনি একটি ফাংশন ডিফাইন বা ডিক্লেয়ার করেন, জাভাস্ক্রিপ্ট ইঞ্জিন গ্লোবাল অবজেক্টের সাথে ফাংশনকে যোগ করে। একইভাবে, যদি আপনি ফাংশনের বাইরে একটি ভেরিয়েবল ডিক্লেয়ার করেন, জাভাস্ক্রিপ্ট ইঞ্জিন ঐ ভেরিয়েবলকে গ্লোবাল অবজেক্টের সাথে যোগ করে। নিম্নলিখিত উদাহরণ দেখুনঃ ```js var num = 7; function sum(a, b) { return a + b; } console.log(window.sum); /** ƒ sum(a,b) { return a + b; } */ console.log(window.num); // 7 ``` যদি আপনার প্রোগ্রামে অনেক গ্লোবাল ভেরিয়েবল এবং ফাংশন থাকে, তাহলে আপনার প্রোগ্রাম ইনইফিশিয়েন্টলি মেমরি ব্যবহার করতে পারে এবং আপনার গ্লোবাল ভেরিয়েবল এবং ফাংশনগুলি অন্য কোন লাইব্রেরীর সাথে কনফ্লিক্ট করতে পারে যদি ঐ লাইব্রেরীতে একই নামে ভেরিয়েবল এবং ফাংশন থাকে। ফাংশন এবং ভেরিয়েবলগুলিকে গ্লোবাল অবজেক্ট কনফ্লিক্ট করা থেকে বিরত রাখার একটি উপায় হল IIFE ব্যবহার করা। ### নেইমড ইফিঃ ```js (function domeSomeMagic() { // code goes here... })(); ``` ### IIFE সেমিকোলন দিয়েও শুরু হতে পারেঃ ```js (function () { // code goes here... })(); ``` এই সিনট্যাক্সে, দুই বা ততোধিক জাভাস্ক্রিপ্ট ফাইলকে একক ফাইলে বান্ডল করার জন্যে স্টেটমেন্টটি শেষ করতে সেমিকোলন ব্যবহার করা হয়। উদাহরণস্বরূপ, আপনার দুটি ফাইল আছে file1.js এবং file2.js যা IIFE ব্যবহার করে। ```js /** * file1.js */ (function () { // ... })(); ``` ```js /** * file2.js */ (function () { // ... })(); ``` যদি আপনি একটি কোড বান্ডলার টুল ব্যবহার করে উভয় ফাইলগুলির কোডকে একটি একক ফাইলের কোড কনক্যাট করতে চান সেমিকোলন (;) ছাড়া, কনক্যানেটেড কোডটি একটি `Uncaught TypeError: (intermediate value)(...) is not a function` সিনট্যাক্স ইরোর দিবে। ধরুন আপনার নিম্নলিখিত ফাংশন সহ math.js নামে একটি লাইব্রেরি আছে এবং একটি HTML ফাইলে math.js লোড করুনঃ ```js function add(a, b) { return a + b; } function sub(a, b) { return a - b; } function mult(a, b) { return a * b; } function div(a, b) { return a / b; } ``` পরবর্তীতে, আপনি একই ফাইলে anotherLibrary.js নামে আরেকটি জাভাস্ক্রিপ্ট লাইব্রেরি লোড করতে চানঃ ```html JavaScript IIFE ``` `anotherLibrary.js` লাইব্রেরীতেও `sub()` নামে ফাংশন রয়েছে যেটি একটি স্ট্রিং রিটার্ন করেঃ ```js function sub() { return "sub"; } ``` যখন আপনি `app.js` ফাইলে `sub()` ফাংশনটি ব্যবহার করবেন, তখন এটি দুটি সংখ্যার বিয়োগের পরিবর্তে **sub** স্ট্রিং রিটার্ন করবেঃ ```js let result = sub(30, 20); console.log(result); // sub ``` কারণ anotherLibrary.js এর sub() ফাংশন math.js লাইব্রেরির sub() ফাংশনকে ওভাররাইড করে ফেলছে। এই সমস্যা ঠিক করতে, আপনি math.js এ IIFE ব্যবহার করতে পারেনঃ ```js var math = (function () { function add(a, b) { return a + b; } function sub(a, b) { return a - b; } function mult(a, b) { return a * b; } function div(a, b) { return a / b; } return { add: add, sub: sub, mult: mult, div: div, }; })(); ``` **IIFE** `math` নামে একটি অবজেক্ট রিটার্ন করে যাতে `add`, `sub`, `mult`, এবং `div` মেথড হয়েছে। `app.js` ফাইলে, আপনি `math.js` লাইব্রেরি নিম্নলিখিতভাবে ব্যবহার করতে পারেনঃ ```js var result = math.sub(30, 20); console.log(result); // 10 console.log(sub()); // sub ``` প্রথম sub() ফাংশনকে math.sub() দিয়ে ইনভোক করা হয়েছে যেটি math.js থেকে এক্সপোর্ট করা অন্যদিকে দ্বিতীয় sub() ফাংশনকে anotherLibrary.js থেকে ইনভোক করা হয়েছে। ### IIFE এর সুবিধাঃ - অপ্রয়োজনীয় গ্লোবাল ভেরিয়েবল এবং ফাংশন তৈরি করে না। - IIFE তে ডিফাইন করা ফাংশন ও ভেরিয়েবল অন্য ফাংশন এবং ভেরিয়েবলের সাথে কনফ্লিক্ট করে না। এমনকি তাদের একই নাম থাকলেও। - জাভাস্ক্রিপ্টের কোড অর্গানাইজ করে। - জাভাস্ক্রিপ্ট কোড মেইন্টানাবল করে। ================================================ FILE: basic/2. scope/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/2. scope/Examples/example1.js ================================================ /* Function scope: জাভাস্ক্রিপ্টে ব্যাপ্তি কোডের বর্তমান প্রেক্ষাপট বোঝায়, যা জাভাস্ক্রিপ্টে ভেরিয়েবলের অ্যাক্সেসযোগ্যতা নির্ধারণ করে। Scope দুটি ধরণের local এবং global: * global ভেরিয়েবল হচ্ছে ব্লকের বাইরে ঘোষিত * local ভেরিয়েবল হচ্ছে ব্লকের ভিতরে ঘোষিত নীচের উদাহরণে, আমরা একটি global variable animal তৈরি করব। ফাংশনের মধ্যে animal নামের একই একটি local variable। কনসোলে তাদের পাঠানোর মাধ্যমে, আমরা দেখতে পাচ্ছি যে কিভাবে ভেরিয়েবলের মান scopeর উপর নির্ভর করে এবং মূল মান পরিবর্তন করা হয় না। */ // Global variable initialization var animal = "Tiger"; function transform() { // A function-scoped local variable initialization var animal = "Cangaroo"; console.log(animal); } // Global and local variable log console.log(animal); transform(); console.log(animal); /* Output: Tiger Cangaroo Tiger */ ================================================ FILE: basic/2. scope/Examples/example2.js ================================================ /* Block scope: জাভাস্ক্রিপ্টে ব্যাপ্তি কোডের বর্তমান প্রেক্ষাপট বোঝায়, যা জাভাস্ক্রিপ্টে ভেরিয়েবলের অ্যাক্সেসযোগ্যতা নির্ধারণ করে। Scope দুটি ধরণের local এবং global: * global ভেরিয়েবল হচ্ছে ব্লকের বাইরে ঘোষিত * local ভেরিয়েবল হচ্ছে ব্লকের ভিতরে ঘোষিত নীচের উদাহরণে, আমরা একটি global variable animal তৈরি করব। ব্লকের মধ্যে animal নামের একই একটি local variable। কনসোলে তাদের পাঠানোর মাধ্যমে, আমরা দেখতে পাচ্ছি যে কিভাবে ভেরিয়েবলের মান scopeর উপর নির্ভর করে এবং মূল মান পরিবর্তন করা হয় না। */ var isInZoo = true; // A global variable initialization let animal = "Tiger"; if (isInZoo) { // A block-scoped variable initialization let animal = "Cangaroo"; console.log(`Animal is currently a ${animal}.`); } console.log(`Animal is currently a ${animal}.`); /* Output: Animal is currently a Cangaroo. Animal is currently a Tiger. */ ================================================ FILE: basic/2. scope/Examples/example3.js ================================================ /* Scope যে শুধুমাত্র ফাংশনের মধ্যে তৈরী হয় বিষয়টি তেমন নয়। if-else কন্ডিশন, লুপ ইত্যাদি উপায়ে Scope তৈরী করা যায় এমনকি শুধুমাত্র দ্বিতীয় বন্ধনীর (Curly Braces) মাধ্যমেও Scope তৈরী করা যায়। নীচের প্রোগ্রাম লক্ষ্য করলে দেখতে পাবো যে আমরা প্রথম console.log(bike) এর মাধ্যমে Global Scope এর bike ভেরিয়েবলটি কনসোলে দেখিয়েছি, দ্বিতীয় console.log(bike) এর মাধ্যমে Local Scope এর bike ভেরিয়েবলটি কনসোলে দেখিয়েছি এবং সবশেষে console.log(bike) এর মাধ্যমে পুনঃরায় Global Scope এর bike ভেরিয়েবলটি কনসোলে দেখিয়েছি। */ let bike = 'Yamaha R15 v3'; console.log(bike); // Yamaha R15 v3 { let bike = 'Suzuki Gixxer SF'; console.log(bike); // Suzuki Gixxer SF } console.log(bike); // Yamaha R15 v3 /* এখানে একটি বিষয় লক্ষ্য রাখতে হবে যে, জাভাস্ক্রীপ্ট ইঞ্জিন যদি ভিন্ন Scope তৈরী না করতো তাহলে সে আমাদেরকে একই Scope এর মধ্যে একই নামে দুইটি ভিন্ন ভেরিয়েবল ব্যবহার করতে দিতো না (যদিও এই বিষয়টি var দিয়ে ডিক্লেয়ার করা ভেরিয়েবলের জন্য আলাদা হয়ে থাকে)। আরো একটি মজার বিষয় হচ্ছে যে, Global Scope ও Local Scope উভয়ের মধ্যে যদি একই নামের দুটি ভেরিয়েবল থাকে তবে Local Scope এর মধ্যে উভয় ভেরিয়েবলের এক্সেস থাকলেও Local Scope এ ডিক্লেয়ার করা ভেরিয়েবল প্রধান্য বেশি পায়। রিয়েল লাইফের ক্ষেত্রে যার এলাকা তার প্রাধান্য বেশি বিষয়টি তেমন। */ ================================================ FILE: basic/2. scope/Examples/example4.js ================================================ /* একটা Scope এর ভিতরে ডিক্লেয়ার করা সকল ভেরিয়েবল এবং ফাংশনসমূহ ঐ Scope এর ভিতের তৈরী সকল Scope (Nested Scope) এ এক্সেস করা যায় আর এক্ষেত্রে সেটা যে কোন লেভেলে ব্যবহার করা যায়। নীচের কোডটি একটু খেয়াল করিঃ */ let companyName = 'Vivasoft Ltd.'; const fn1 = () => { const fn2 = () => { console.log(companyName); // Vivasoft Ltd. } fn2(); } const fn3 = () => { fn1(); } fn3(); /* উপরের কোডটিতে Global Scope এর জন্য companyName হলো গ্লোবাল ভেরিয়েবল এবং fn1() ও fn3() হলো গ্লোবাল ফাংশন অর্থাৎ আমরা চাইলেই আমাদের কোডের যেকোন লেভেলে এগুলোকে ব্যবহার করতে পারি। আর গ্লোবাল স্কোপ যে আমাদেরকে যেকোন লোকাল স্কোপে তার ভেরিয়েবল এবং ফাংশনসমূহ ব্যবহারের সুযোগ দিচ্ছে এটাকেই আমরা Lexical Scoping (লেক্সিক্যাল স্কোপিং) বলে থাকি। */ ================================================ FILE: basic/2. scope/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/2. scope/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/2. scope/Practices/practice1.md ================================================ নীচের কোডে কোথাও ভূল আছে কিনা সেটা খুজে বের করার চেষ্টা করুন। যদি থাকে তবে সেটা কেন হচ্ছে সেটা ব্যাখ্যা করুন। ```js let myCar = 'Lamborghini Huracan Evo'; function changeCar() { let myCar = 'Ferrari SF90 Stradale'; console.log(myCar); } let myCar = 'Ford GT'; console.log(myCar); ``` নীচের কোডের আউটপুট কি হবে? ```js let secondHome = 'Canada'; function toggleHome() { let secondHome = 'Australia'; secondHome = 'USA'; } toggleHome(); console.log(secondHome); // What will be the output? ``` ================================================ FILE: basic/2. scope/README.md ================================================ ### Scope কি? > **Scope** মূলত একটা নির্দিষ্ট সীমানাকে বোঝায়। যার বাহিরে **Variable** এবং **Function**-গুলো এক্সেসিবল না। যদি এই সীমানার বাহিরে কোন **Variable** এবং **Function** কে কল করা হয় তাহলে তার কোন অস্তিত্ব থাকবে না। একটি কথা ভাল করে মাথায় সংরক্ষণ করে রাখেন যে, জাভাস্ক্রিপ্টে একমাত্র তখনই **Scope** তৈরি হয়, যখন আমরা কোন **function** ইনভোক বা কল করি। হ্যাঁ, **function** ছাড়া আর কোথাও **Scope** তৈরি হয় না। আর এই **Scope** হচ্ছে দুই প্রকার- ১. **Global Scope** এবং ২. **Local Scope**। ### ১. Global Scope জাভাস্ক্রিপ্টে বাই ডিফল্ট সব কিছু **Global Scope** - এ রান হয়। যার এক্সেসিবল সব জায়গায় থাকে। উদাহরণস্বরূপ- ```js var globalVariable = "I am global variable."; console.log(globalVariable); // I am global variable. var myFunc = function () { console.log(globalVariable); }; myFunc(); // I am global variable. ``` উপরের কোডটুকু রান করলে দেখতে পারবেন যে globalVariable নামের ভেরিয়েবলটিকে সব যায়গায় ব্যবহার করা যাচ্ছে এবং সবার আউটপুটও একই দেখাচ্ছে। ### ২. Local Scope আগেই বলেছিলাম যে, জাভাস্ক্রিপ্ট একমাত্র তখনই **Scope** তৈরি করে যখন কোন **Function** কে ইনভোক বা কল করা হয়। এই **Scope** কেই বলা হয় **Local Scope**। মানে হচ্ছে, তার ভিতরে যা কিছু থাকবে তার নিজস্ব **Scope** - এর বাহিরে এর কোন অস্তিত্ব থাকবে না। অর্থাৎ, তার **Scope** - এর ভিতরে লেখা কোন ভেরিয়েবলকে যদি আমরা বাহিরে অন্য কোথাও ব্যবহার করতে চাই তাহলে জাভাস্ক্রিপ্ট খুব সুন্দর করে একটি আনকট রেফারেন্সে ইরর দিয়ে বলে দিবে যে খোকা তুমি যাকে ব্যবহার করতে চাচ্ছ সে তো কোথাও ডিফাইন করা নেই। চলুন একটা উদাহরণ দিয়ে দেখা যাক- ```js var globalVariable = "I am global variable."; var myFunc = function () { var localVariable = "I am local variable."; console.log(globalVariable); console.log(localVariable); }; myFunc(); // I am global variable. // I am local variable. console.log(localVariable); // undefined ``` উপরের কোডটুকু রান করলে দেখতে পারবেন যে প্রথমে দেখাচ্ছে I am global variable. এবং I am local variable. তারপর অতি ভদ্রতার সাথে খুব সুন্দর করে এরর দিয়ে বলে দিছে যে **Uncaught ReferenceError: localVariable is not defined**। ### Lexical Scoping কি? এখন সবার মনে প্রশ্ন আসতে পারে যে, এই **Lexical Scoping** - টা আবার কি? একটু অপেক্ষা করেন মাথা গরম করার কোন দরকার নেই। আসলে জাভাস্ক্রিপ্টকে বলা হয় **Lexical Scoping** ল্যাঙ্গুয়েজ। আমরা ফাংশনের ভিতরে আমাদের প্রয়োজন অনুযায়ী একাধিক ফাংশন তৈরি করতে পারি এবং চাইল্ড ফাংশনগুলো তার প্যারেন্ট ফাংশনের সব ভেরিয়েবলস এবং আর্গুমেন্টেসের এক্সেস পায়। কিন্তু আউটার ফাংশনগুলো তার চাইল্ড ফাংশনের ভেরিয়াবলস এবং আর্গুমেন্টসের কোন এক্সেস পায় না। এই যে চাইল্ড ফাংশনগুলো তার প্যারেন্ট ফাংশনের ভেরিয়েবলস এবং আর্গুমেন্টেসের এক্সেস পাচ্ছে এই এক্সেস পাওয়াকেই বল হয় **Lexical Scoping**। ```js function outerFunc(a) { var outerFuncVariable = "Hi there, I am outer " + a; console.log(outerFuncVariable); // Hi there, I am outer function variable function innerFunc() { var innerFuncVariable = "Hi there, I am inner " + a; console.log(innerFuncVariable); // Hi there, I am inner function variable } innerFunc(); console.log(innerFuncVariable); // undefined } outerFunc("function variable"); ``` **নোটসঃ** - জাভাস্ক্রিপ্টের গ্লোবাল স্কোপ এবং লোকাল স্কোপ আছে। - যে কোন ফাংশনের বাইরে ডিক্লেয়ারড এবং ইনিশিয়ালাইজড ভ্যারিয়েবলগুলো গ্লোবাল ভ্যারিয়েবল হয়ে যায়। - ফাংশনের ভিতরে ডিক্লেয়ারড এবং ইনিশিয়ালাইজড ভ্যারিয়েবলগুলো সেই ফাংশনের লোকাল ভ্যারিয়েবল হয়। - গ্লোবাল ভ্যারিয়েবলগুলো প্রোগ্রামের যেকোন জায়গায় অ্যাক্সেস এবং পরিবর্তন করা যেতে পারে। - ফাংশন ডিক্লেয়ারেশনের বাইরে লোকাল ভ্যারিয়েবল সমূহ অ্যাক্সেস করা যাবে না। - গ্লোবাল ভ্যারিয়েবল এবং লোকাল ভ্যারিয়েবল একই নাম থাকতে পারে। কিন্তু একই নাম ব্যবহার না করায় ভালো। ### আরও বাংলা টিউটোরিয়াল > - [জাভাস্ক্রিপ্টঃ স্কোপ(Scope) নিয়ে ধারণা](https://js.zonayed.me/basic/post-15) > - [জাভাস্ক্রিপ্ট স্কোপ (JavaScript Scope)](http://bangla.salearningschool.com/recent-posts/জাভাস্ক্রিপ্ট-স্কোপ-javascript-scope/) ### বাংলা ভিডিও টিউটোরিয়াল > - [JavaScript Scope and Hoisting Explained | JavaScript Bangla Tutorial](https://www.youtube.com/watch?v=6_4NcQQvxmM) > - [Scope and Scope Variables | Ultimate Beginner JavaScript Course](https://www.youtube.com/watch?v=HZZ0X2Toiok&t=40s) > - [Javascript Behind The Scene Scope Chain and Lexical Scope in Bangla](https://www.youtube.com/watch?v=LPB6oT_pvu4) ================================================ FILE: basic/3. hoisting/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/3. hoisting/Examples/example1.js ================================================ console.log(x) let x = 5 {/* output: Uncaught ReferenceError: x is not defined */} console.log(x) const x = 5 {/* output: Uncaught ReferenceError: x is not defined */} console.log(x) var x = 5 {/* output: undefined */} ================================================ FILE: basic/3. hoisting/Examples/example2.js ================================================ hoistedSuccess(); // Hoisted function hoistedSuccess() { console.log("This is Function Statement and it is hoisted"); } {/* output: This is Function Statement and it is hoisted */} hoistedFailed(); // Hoisted const hoistedFailed =()=>{ console.log("This function expression so it is not hoisteed."); } {/* output: Uncaught ReferenceError: hoistedFailed is not defined */} ================================================ FILE: basic/3. hoisting/Examples/example3.js ================================================ var outerVar= "Hi , this is outer variable."; function hoistingFunc() { console.log(outerVar); var outerVar = "Hi , this is inner variable."; console.log(outerVar); } hoistingFunc(); {/* output: undefined Hi , this is inner variable. */} ================================================ FILE: basic/3. hoisting/Examples/example4.js ================================================ function codeHoist(){ a = 10; let b = 50; } codeHoist(); console.log('value of a is ',a); console.log('value of b is ',b); {/* output: value of a is 10 Uncaught ReferenceError: b is not defined */} ================================================ FILE: basic/3. hoisting/Examples/example5.js ================================================ console.log('value of a is ',a); function codeHoist(){ a = 10; } codeHoist(); {/* output: ReferenceError: a is not defined */} ================================================ FILE: basic/3. hoisting/Examples/example6.js ================================================ console.log(x); // x is undefined x = 5; // Assign 5 to x console.log(x); // x is 5 var x; // Declare x /* Output: undefined 5 */ ================================================ FILE: basic/3. hoisting/Examples/example7.js ================================================ var x = 5; // Initialize x console.log(x + " " + y); var y = 7; // Initialize y console.log(x + " " + y); /* Output: 5 undefined 5 7 */ ================================================ FILE: basic/3. hoisting/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/3. hoisting/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/3. hoisting/Practices/practice1.md ================================================ নীচের কোডের আউটপুট কি হবে? ```js sayHi(); console.log(sayHello); function sayHi() { var sayHello = 'Hi!'; console.log(sayHello); } var sayHello = 'Hello!'; ``` ================================================ FILE: basic/3. hoisting/README.md ================================================ এই লেখাটি পড়ার আগে আমার **Execution Context** এবং **Scope** নিয়ে লেখা দুটি আর্টিকেল পড়ে আসতে বলবো। তাহলে **Hoisting** বুঝতে আপনার জন্যে অনেক সহজ হয়ে যাবে। ১। [Execution Context](../1.%20execution-context/README.md) ২। [Scope](../2.%20scope/README.md) ### Hoisting কি? > **Hoisting** হচ্ছে জাভাস্ক্রিপ্ট এমন একটি পদ্ধতি যেখানে কোড এক্সিকিউশন করার আগে ভ্যারিয়েবল এবং ফাংশন ডিক্লেয়ারেশনগুলোকে তার বর্তমান **Scope** - এর শুরুতে নিয়ে যায়। উদাহরণস্বরূপঃ ```js function hoisting() { console.log(message); var message='Hi there, We are learning Hoisting!' } hoisting(); // Ouput: undefined ``` উদাহরণের ব্যাখ্যা দেওয়ার আগে Hoisting সম্পর্কে কিছু কথা বলে নেই। যখন আমরা কাউকে Hoisting বুঝায় উপরের সংজ্ঞাটা দিয়েই বুঝায়। কিন্তু আসলেই কি জাভাস্ক্রিপ্ট তার সকল ভ্যারিয়েবলস এবং ফাংশন ডিক্লেয়ারেশনগুলোকে তার স্কোপের উপরে নিয়ে যায়? না, জাভাস্ক্রিপ্ট এমনটা কখনো করে না। যদি আপনি আমার [Execution Context](https://shahansdiary.com/execution-context-in-javascript/) নিয়ে লেখাটা পড়ে থাকেন, তাহলে আপনি জানেন যে যখন আপনি জাভাস্ক্রিপ্টের কোন কোড এক্সিকিউট করেন, জাভাস্ক্রিপ্ট ইঞ্জিন গ্লোবাল এক্সিকিউশন কন্টেক্সট তৈরি করে। গ্লোবাল এক্সিকিউশন কন্টেক্সট এর দুটি phase আছে: **creation** এবং **execution**। creation phase চলার সময়, জাভাস্ক্রিপ্ট ইঞ্জিন সকল ভ্যারিয়েবলকে **undefined** হিসাবে ইনিশিয়ালাইজ করে। এবার চলুন আমরা **Hoisting**-এ ফিরে যাই। জাভাস্ক্রিপ্টে **Hoisting** হচ্ছে দুই প্রকার। ১. **Variable Hoisting** এবং ২. **Function Hoisting**। ১. Variable Hoisting ```js console.log(hoistingIntro); // Output: undefined var hoistingIntro = "Hi there, I am a string one."; ``` উপরের console.log এর আউটপুট কি হবে? একটু চিন্তা করুন সময় নিয়ে। যাইহোক, উপরের কোডে কোন ভুল নেই। কারণ আমরা জানি জাভাস্ক্রিপ্ট ইঞ্জিন **Creation phase**-এ ভ্যারিয়েবল ডিক্লেয়ারেশনকে **undefined** হিসাবে ইনিশিয়ালাইজ করে। তাই, **Execution phase**-এ আউটপুট **undefined** হচ্ছে কারণ আমরা তার ভ্যালু ইনিশিয়ালাইজ হওয়ার আগেই log করে ফেলেছি। টেকনিক্যালি, কোডটি Execution phase-এ নিম্নলিখিত কোডের মত দেখাবেঃ ```js var hoistingIntro = undefined; console.log(hoistingIntro); // output: undefined hoistingIntro = "Hi there, I am a string one."; ``` ### ২। Functions Hoisting ভ্যারিয়েবলের মত ফাংশনও Hoisted হয়। তাই আপনি আগে ফাংশন কল করে পরে ফাংশন ডিক্লেয়ার করতে পারবেন। ```js hoistedFunc(); // Hoisted function hoistedFunc() { console.log("Hoisted."); } ``` বিঃ দ্রঃ একটি কথা ভাল করে মনে রাখবেন যে জাভাস্ক্রিপ্ট ফাংশন এক্সপ্রেশনের ক্ষেত্রে কোন Hoisting করে না। ```js hoistedFunEx(); // TypeError: hoistedFunEx is not a function var hoistedFunEx = function() { console.log("Hoisted."); } ``` আপনাদের জন্যে একটি হোম টাস্ক। নিচের কোডের দুইটা console.log এর আউটপুট কি হবে? চাইলে কমেন্ট করে জানাতে পারেন। :) ```js var hoistingIntro = "Hi there, I am a string one."; function hoistingFunc() { console.log(hoistingIntro); var hoistingIntro = "Hi there, I am a string two"; console.log(hoistingIntro); } hoistingFunc(); ``` ### আরও বাংলা টিউটোরিয়াল > - [জাভাস্ক্রিপ্টঃ স্কোপ(Scope) নিয়ে ধারণা](https://js.zonayed.me/basic/post-15) > - [জাভাস্ক্রিপ্ট স্কোপ (JavaScript Scope)](http://bangla.salearningschool.com/recent-posts/জাভাস্ক্রিপ্ট-স্কোপ-javascript-scope/) ### বাংলা ভিডিও টিউটোরিয়াল > - [JavaScript Scope and Hoisting Explained | JavaScript Bangla Tutorial](https://www.youtube.com/watch?v=6_4NcQQvxmM) > - [Scope and Scope Variables | Ultimate Beginner JavaScript Course](https://www.youtube.com/watch?v=HZZ0X2Toiok&t=40s) > - [Javascript Behind The Scene Scope Chain and Lexical Scope in Bangla](https://www.youtube.com/watch?v=LPB6oT_pvu4) ================================================ FILE: basic/4. closure/Examples/Anonymous_fn_with_lexical_scope.js ================================================ {/* Here the Anonymous function (within multiply function) creates a closure with x. so when multiply function called , it returns Anonymous function. We define that function in multiplyFive variable.Although multiply function already called and remove from the call stack but multiplyFive have now the access of variable x from closure. */} const multiply = (x)=> { return function(y) { return x * y; } } let multiply10 = multiply(10); let multiplyFive = multiply10(5); console.log(multiplyFive); //Output 50 ================================================ FILE: basic/4. closure/Examples/Closure_In_InnerFunction.js ================================================ //ex:1 function add() { let counter = 0; function plus() {counter += 1;} plus(); return counter; } add() add() add() {/* output: 1 */} //ex:2 {/* Closure in self invoking function A closure is a function having access to the parent scope, even after the parent function has closed. Here the self invoking Anonymous function will create closure with counter variable. and each time the add function called , Anonymous function function will execute and increment the value of counter(closure) by 1. */} const add = (function () { let counter = 0; return function () {counter += 1; return counter} })(); add(); add(); add(); 3 {/* output: 3 */} ================================================ FILE: basic/4. closure/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/4. closure/Examples/closure.js ================================================ var langFunc = function () { var langName = "JavaScript"; // displayLangName is a inner function of langFunc function displayLangName() { console.log(langName); } return displayLangName; }; langFunc()(); /* Output: JavaScript */ ================================================ FILE: basic/4. closure/Examples/closure_scope_chain.js ================================================ {/* Every closure has three scopes: Local Scope (Own scope) Outer Functions Scope Global Scope Here's a series of nested functions, all of which have access to the outer functions' scope. In this context, we can say that closures have access to all outer function scopes. */} // global scope var e = 10; function sum(a){ return function(b){ return function(c){ // outer functions scope return function(d){ // local scope return a + b + c + d + e; } } } } console.log(sum(1)(2)(3)(4)); // log 20 ================================================ FILE: basic/4. closure/Examples/emulating_private_methods_with_closures.js ================================================ // জাভার মতো ভাষাগুলি আপনাকে method private হিসাবে declare করার অনুমতি দেয়, // অর্থাত্ তাদের একই class এর অন্যান্য methods দ্বারা call করা যেতে পারে। // জাভাস্ক্রিপ্ট এটি করার একটি native way প্রদান করে না, // কিন্তু Closure ব্যবহার করে private method অনুকরণ করা সম্ভব। // private method গুলি কেবল কোডে অ্যাক্সেস সীমাবদ্ধ করার জন্য কার্যকর নয়। // তারা আপনার global namespace পরিচালনার একটি শক্তিশালী উপায়ও প্রদান করে। var counter = (function () { var privateCounter = 0; function changeByValue(val) { privateCounter += val; } return { increment: function () { changeByValue(1); }, decrement: function () { changeByValue(-1); }, value: function () { return privateCounter; }, }; })(); // Initial call privateCounter console.log(counter.value()); // privateCounter increment by 1 counter.increment(); // again privateCounter increment by 1 counter.increment(); console.log(counter.value()); // privateCounter decrement by 1 counter.decrement(); console.log(counter.value()); /* Output: 0 2 1 */ ================================================ FILE: basic/4. closure/Examples/example_for_understand_usecase_of_closure.js ================================================ {/* This is an example that show another use case of closure. Var keyword has functional scope. so when we create variable using var keyword with the same variable name, its always point to the same variable. Here we use asynchronous function setTimeout. when settimeout asynchronously executed after timeout, the value of count has been already became 6. Because it will continue the loop upto 5 and then another increment operation increment the value of count to 6. so it will print 6 for five time We can solve these issue using closure */} for(var count = 1; count <= 5; count++) { setTimeout(() => console.log(count), 1000); } {/* Output: 6 6 6 6 6 */} ================================================ FILE: basic/4. closure/Examples/solve_var_functional_scope_issue_using_closure.js ================================================ //ex:1 {/* In these example We have solve the previous issue in two differents way. First one using Closure. Here we called an Anonymous function in every iteration. We know function create closure with its lexical scope. So These Anonymous function will creates closure with count variable. When the Timeout finished , it will print the value from closure. */} for(var count = 1; count <= 5; count++) { (function (){ var closurVar=count setTimeout(() => console.log(closurVar), 1000); })() } {/* Output: 1 2 3 4 5 */} //ex:2 {/* let has block scope and var has functional skope. so let create differents variable in every time where var point to the same variable every time. */} for(let count = 1; count <= 5; count++) { setTimeout(() => console.log(count), 1000); } {/* Output: 1 2 3 4 5 */} ================================================ FILE: basic/4. closure/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/4. closure/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/4. closure/Practices/practice1.md ================================================ নীচের প্রোগ্রামের আউটপুট কি হবে সেটা রান না করে নিজেই অনুমান করার চেষ্টা করো। তোমার অনুমানকৃত আউটপুট কোথাও লিখে রাখো। এবার প্রোগ্রামটি রান করে আউটপুট দেখো। যদি সেটা তোমার আউটপুটের সাথে মিলে যায় তাহলে তোমাকে কনগ্রাচুলেশনস, তুমি ক্লোজার বিষয়টি রপ্ত করতে পেরেছো। আর যদি তোমার আউটপুটের সাথে না মিলে তাহলে ক্লোজার টপিকটি আরেকটিবার ভালো করে পড়ো এবং প্রোগ্রামের আউটপুট কেন এমন হচ্ছে সেটা বোঝার চেষ্টা করো। ```js setTimeout(() => console.log('First Output:'), 1000); for(var i = 1; i <= 5; i++) { setTimeout(() => console.log(i), 1000); } setTimeout(() => console.log('\nSecond Output:'), 2000); for(var i = 1; i <= 5; i++) { function a(i) { setTimeout(() => console.log(i), 2000); } a(i); } ``` ================================================ FILE: basic/4. closure/README.md ================================================ ## পূর্বশর্ত ২। [Scope](../2.%20scope/README.md) ## ক্লোজার কি? > Closure কোন ফাংশন না আবার ফাংশনও কোন closure না। Closure হচ্ছে ফাংশনের এমন একটা বৈশিষ্ট্য যে বৈশিষ্ট্যের কারণে ফাংশন এক্সিকিউশন শেষ হয়ে যাবার পরেও তার lexical scope এ অবস্থিত সকল variable কে মনে রাখতে পারে। উদাহরণস্বরূপ বলা যেতে পারে যে ডম থেকে কিছু অ্যাক্সেস করার জন্যে আমরা যে ইভেন্ট ফাইয়ার করি সেটাও একটা closure। ### কিছু উদাহরণঃ ```js function add(a) { return function (b) { return a + b; }; } let addTen = add(10); let addSeven = addTen(7); console.log(addSeven); // 17 ``` কি হচ্ছে এসব?? ঠিক আছে, চলেন দেখি কোডগুলোকে ভেঙ্গেঃ- ১। যখন add ফাংশনটি কল হয় এটি আরেকটি ফাংশনকে return করে। ২। ঐ ফাংশনটির এক্সিকিউশন শেষ হয়ে যায় এবং মনে রাখে ঐ সময় তার প্যারামিটার a এর ভ্যালু কি ছিল। ৩। যখন addTen ভেরিয়েবলে add ফাংশনকে এসাইন করা হয়। এটি সব সময় মনে রাখবে a এর ভেল্যু কি ছিল যখন এটিকে ইনিশিয়ালি কল করা হয়েছিল। ৪। উপরের addTen ভেরিয়েবল একটি ফাংশনকে বোঝায় যেটি সব সময় ভেল্যু ১০ যোগ করবে যা পাঠানো হয়েছিল। ৫। তার মানে হল যখন addTen কে কল করা হয় ৭ ভেল্যু দিয়ে, এটি ১০ এর সাথে ৭ যোগ করবে এবং ১৭ রিটার্ন করবে। **সুতারং, জাভাস্ক্রিপ্ট ইঞ্জিন addTen কে যেভাবে রান করেঃ-** ```js function addTen(b) { return 10 + b; } ``` এখন একটা মজার উদাহরণ দেখবো। কিভাবে আমরা লুপের ভিতরে ক্লোজার চালাতে পারি। এটি ইন্টার্ভিউ বোর্ডের একটা কমন প্রশ্ন। নিচের কোডটা দেখেন এবং একটু মনে মনে চিন্তা করেন এটার আউটপুট কত হবে। ```js for (var i = 1; i <= 5; i++) { setTimeout(() => console.log(i), 1000); } ``` **কাঙ্খিত আউটপুটঃ-** ``` 1 2 3 4 5 ``` **কিন্তু আসছে অনাকাঙ্ক্ষিত আউটপুটঃ-** ``` 6 6 6 6 6 ``` আসলে এই আউটপুট আসার অনেক কারণ আছে। লুপের মাঝে ভ্যারিয়েবল i হচ্ছে একটি গ্লোবাল ভ্যারিয়েবল। যখন setTimeout রান হয় তার আগেই লুপ শেষ হয়ে যায় এবং তাই i ভ্যালু 6 হয়ে যায়। সেজন্যে প্রতি এক সেকেন্ড পর পর পাঁচবার 6 দেখাচ্ছে। যদি বিশ্বাস না হয় তাহলে কোডটা রান করার পর আপনার গ্লোবাল window অবজেক্টটা একবার দেখেন সেখানে i নামে একটা ভ্যারিয়াবল দেখতে পারবেন এবং তার ভ্যালু 6 হয়ে আছে। এই সমস্যার সমাধান আমরা IIFE বা Immediately Invoked Function Expression ব্যবহার করে করতে পারি। নিচে উদাহরণ দেওয়া হলোঃ- **পদ্ধতি ১ঃ-** ```js for (var i = 1; i <= 5; i++) { (function () { var val = i; setTimeout(() => console.log(val), 1000); })(); } ``` **পদ্ধতি ২ঃ-** ```js for (var i = 1; i <= 5; i++) { (function (val) { setTimeout(() => console.log(val), 1000); })(i); } ``` এখানে আমরা একটা ফাংশন লিখে একটা Scope তৈরি করেছি। ফাংশনটিকে ইমিডিয়েটলি কল করেছি এবং তার প্যারামিটারের ভেল্যু হিসাবে i কে পাস করেছি। এতে সে এখন i এর ভেল্যুকে মনে না রেখে সে এখন তার প্যারামিটারের ভেল্যুকে মনে রাখবে। মানে এখন i এর মান 1, 2 করে যাচ্ছে এবং সেটা থেকে একটা আলাদা Scope তৈরি হচ্ছে যেটাকে সে মনে রাখছে। **পদ্ধতি ৩ঃ-** ```js for (let i = 1; i <= 5; i++) { setTimeout(() => console.log(i), 1000); } ``` **আউটপুটঃ-** ``` 1 2 3 4 5 ``` অবশেষে আমাদের কাঙ্ক্ষিত আউটপুট পেলাম। তবে আজ এই পর্যন্ত দেখা পরবর্তী অন্য টপিকে। হ্যাপি কোডিং... ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Examples/example1.js ================================================ /* Call By Value of primitives types এর উদাহরণ */ function multiplyByTen(value) { value = value * 10; } var number = 7; console.log("Before call: number = " + number); // 7 multiplyByTen(number); console.log("After call: number = " + number); // 7 /* Call By Reference of non-primitives types এর উদাহরণ */ function passByReference(person) { person.name = "Alex"; } var alam = { name: "Alam" }; console.log(alam.name); // Alam passByReference(alam); console.log(alam.name); // Alex ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Examples/example2.js ================================================ /* Call By Value of primitives types এর উদাহরণ */ function cube(a) { a = a * a * a; return a; } var x = 10; var result = cube(x); console.log(x); //a = 10 which is unchanged console.log(result); // 1000 /* Call By Reference of non-primitives types এর উদাহরণ */ function switchOn(device) { device.isOn = true; } var phone = { isOn: false, }; switchOn(phone); console.log(phone.isOn); // true; ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Examples/example3.js ================================================ // Call by value for primitive type. var a = 5; var b; b = a; a = 3; console.log(a); // Output: 3 console.log(b); // Output: 5 // call by reference for object type var obj1 = { test : 'Test message 1' }; var obj2; obj2 = obj1; obj1.test = 'Test message 2'; console.log(obj1); // Output: { test: Test message 2 } console.log(obj2); // Output: { test: Test message 2 } ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Examples/example4.js ================================================ // call by value function printGreeting(greetName) { greetName = "Hello, " + greetName; console.log("New value: " + greetName); // Output: Hello, Anik } var greetName = 'Anik'; printGreeting(greetName); console.log("Old value: " + greetName); // Output: Anik // call by reference function modifyObj(person) { person.name = 'Fahim'; person.age = 26; } var person = { name: 'Anik', age: 25 }; console.log("Initial name value: " + person.name); // Initial name value: Anik modifyObj(person); console.log("Updated name value: " + person.name); // Udated name value: Fahim ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Examples/example5.js ================================================ /* Call by value বিষয়টি Primitive ডাটা টাইপের সাথে জড়িত। আবার Call by reference বিষয়টি Non-primitive বা Reference ডাটা টাইপের সাথে জড়িত। বিষয় দুটি বোঝার জন্য একটু অন্যভাবে চিন্তা করি। মনে করুন, আমি Google Doc এ একটি ফাইল খুলেছি এবং সেটাতে আপনাকেও এডিট করার পারমিশন দিয়েছি। এখন ফাইলটিতে আপনি বা আমি যেই কোন কিছু লিখি বা পরিবর্তন করি না কেন সেটা আমাদের দুজনের দিক থেকেই পরিবর্তন হবে। বিষয়টি এমন হবে না যে আপনি দেখলে এক রকম হবে আর আমি দেখলে অন্য রকম হবে। এই বিষয়টি ঠিক Call by reference এর মতো। আবার অন্যদিকে, আমার কাছে থাকা একটি ফাইলের কপি আমি আপনাকে দিলাম অর্থাৎ কপি মূলত দুটি, একটি আপনার আর অন্যটি আমার। সুতরাং আমি যদি আমার ফাইলে কোন পরিবর্তন করি তবে সেটি শুধুমাত্র আমার ফাইলেই পরিবর্তন হবে, আপনারটা যেমন ছিল বা আপনি যেভাবে পরিবর্তন করেছেন সেভাবেই থাকবে। আমাদের কারো পরিবর্তন একে অন্যের উপর কোন প্রভাব ফেলবে না। এই বিষয়টি Call by value এর মতো। আশাকরি এখন বিষয় দুটি বুঝতে কোন সমস্যা হবে না। চলুন একটা উদাহরণ দেখিঃ */ // Call By Value Part let primitiveData = 200; (function callByValue(primitiveData) { primitiveData = 404; })(primitiveData); console.log(primitiveData); // Output: 200 // Call By Reference Part let nonPrimitiveData = ['Abid', 'Shahan', 'Imrul', 'Biplob']; (function callByReference(nonPrimitiveData) { nonPrimitiveData[0] = 'Tareq'; nonPrimitiveData.push('Tajnur'); })(nonPrimitiveData); console.log(nonPrimitiveData); // Output: [ 'Tareq', 'Shahan', 'Imrul', 'Biplob', 'Tajnur' ] ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Practices/practice1.md ================================================ Here we are making a function for adding new properties and values to a specific object. What will be the console log value of 'person'? I want the function to return a new object by not changing the initial value of 'person' object sitting at the global scope. How can you do that? ```javascript const addNewProp = (key, value, object) => { object[key] = value; }; const person = { name: 'Anik' }; addNewProp('age', 25, person); console.log(person); ``` ================================================ FILE: basic/5. call-by-value-and-call-by-reference/Practices/practice2.md ================================================ নীচের প্রোগ্রামের আউটপুট কি হবে? যদি বুঝতে না পারেন তবে একটু একটু করে ডিবাগ করার চেষ্টা করুন। ```js let parentProperty = { house: ['Dhaka', 'Khulna', 'Sylhet'], car: 2 } let childProperty = parentProperty; childProperty.car = 3; childProperty.bike = ['Yamaha', 'Honda']; console.log(parentProperty === childProperty); // True or False? parentProperty = childProperty; console.log(parentProperty === childProperty); // True or False? ``` এবার নীচের কোডের আউটপুট কি হবে সেটা বের করো। ```js let num = 1100; (function changeValue(num) { num = 1011; })(num); console.log(num); ``` ================================================ FILE: basic/5. call-by-value-and-call-by-reference/README.md ================================================ আজকে আমরা আলোচনা করতে যাচ্ছি Primitive এবং Reference টাইপ ডাটার মাঝে কি পার্থক্য এবং এই ডাটা টাইপগুলো কিভাবে কাজ করে। Primitive এবং Reference টাইপকে pass by value এবং pass by reference ও বলা হয়ে থাকে। একজন জাভাস্ক্রিপ্ট প্রোগ্রামার হিসাবে এই ডাটা টাইপগুলো সম্পর্কে পরিষ্কার জ্ঞান রাখা আবশ্যক। জাভাস্ক্রিপ্টে দুই টাইপের ডাটা টাইপ আছে। 1. primitive ডাটা টাইপ এবং 2. non-primitive বা reference ডাটা টাইপ জাভাস্ক্রিপ্টে Strings, Numbers, Boolean, Null, undefined এই ডাটা টাইপগুলো প্রিমিটিভ ডাটা টাইপ হিসাবে পরিচিত এবং Arrays, Objects, Function নন-প্রিমিটিভ বা রেফারেন্স ডাটা টাইপ হিসাবে পরিচিত। এদের মাঝে মৌলিক পার্থক্য হচ্ছে যে প্রিমিটিভ ডাটা immutable বা অপরিবর্তনীয় এবং নন-প্রিমিটিভ ডাটা mutable বা পরিবর্তনীয়। ### প্রিমিটিভ ডাটা টাইপ প্রমিটিভ ডাটা immutable বা অপরিবর্তনীয় ডাটা টাইপ হিসাবে পরিচিত। কারণ এই ডাটা একবার তৈরি হয়ে গেলে এটি পরিবর্তন করার কোন পথ নেই। তাহলে চলেন আপনাদের প্রমাণ করে দেখাই। ```js let str1 = "Hi there, I am a string!"; console.log(str1[1]); // "i" str1[1] = "e"; console.log(str1); // "Hi there, I am a string!" ``` উপরের কোডটা রান করলে জাভাস্ক্রিপ্টের কারিশমা দেখতে পারবেন। সব কিছু মাথার উপর দিয়ে গেল? আচ্ছা, চলেন ব্যাপারটা ব্যাখ্যা করি। আপনি হাজার বার চাইলেও স্ট্রিং এর ভ্যালু পরিবর্তন করতে পারবেন না। কারণ স্ট্রিং একটি immutable বা অপরিবর্তনীয় ডাটা। একটি কথা মনে রাখবেন যদি স্ট্রিংকে কোন ভেরিয়েবলে অ্যাসাইন করে ফেলেন এবং অ্যাসাইন করার পর স্ট্রিংকে মডিফাই করতে চান, তাহলে আপনি একটি নতুন স্ট্রিং পাবেন। যেমন- .toUpperCase(), .slice(), .trim() ইত্যাদি। ```js let str1 = "Hi there, I am a string!"; let newStr = str1.toUpperCase(); console.log(newStr); // HI THERE, I AM A STRING! console.log(str1); // Hi there, I am a string! ``` প্রিমিটিভ ডাটা টাইপগুলো একে অপরের সাথে তাদের ভ্যালু দ্বারা তুলনা করে। ```js let str1 = "Hi there, I am a string!"; let str2 = "Hi there, I am a string!"; console.log(str1 == str2); // true let num1 = 7; let num2 = 7; console.log(num1 == num2); // true ``` প্রিমিটিভ টাইপগুলো সব সময় তাদের ভ্যালু পাস করে। যখন আমরা কোন প্রিমিটিভ ডাটা টাইপকে অন্য কোন ভেরিয়েবলে অ্যাসাইন করি, তখন তার ভ্যালু কপি হয়ে নতুন ভেরিয়েবলে অ্যাসাইন হয়। ```js let num1 = 7; let num2 = num1; console.log(num1); // 7 console.log(num2); // 7 num2 = 8; console.log(num1); // 7 console.log(num2); // 8 ``` ### নন-প্রিমিটিভ ডাটা টাইপ নন-প্রিমিটিভ ডাটা mutable বা পরিবর্তনীয়। কারণ একটি নন-প্রিমিটিভ ডাটা তৈরি হয়ে যাওয়ার পরেও তার ভ্যালু পরিবর্তন হতে পারে। আমরা যখন কোন নন-প্রিমিটিভ ডাটা তৈরি করি, তখন সেই ডাটার জন্যে মেমোরিতে একটা অ্যাড্রেস তৈরি হয় এবং সেই অ্যাড্রেসটাকে মনে রেখে কোন এক জায়গায় ভ্যালুগুলোকে ষ্টোর করে রাখে। তারপর আমাদের যখন দরকার পড়ে তখন সে ঐ অ্যাড্রেসকে কল করে এবং আমাদের ডাটা প্রদান করে। এটা বুঝতে হলে আপনাকে স্ট্যাক এবং হীপ মেমোরি সম্পর্কে জানতে হবে। তবে আমি যতটুকু বললাম এখন এতটুকু মনে রাখলেই হবে। ```js let arr1 = ["JavaScript", "React", "Redux", "React-Redux"]; let arr2 = arr1; console.log(arr1); // ["JavaScript", "React", "Redux", "React-Redux"] console.log(arr2); // ["JavaScript", "React", "Redux", "React-Redux"] arr2[3] = "Redux-Toolkit"; console.log(arr1); // ["JavaScript", "React", "Redux", "Redux-Toolkit"] console.log(arr2); // ["JavaScript", "React", "Redux", "Redux-Toolkit"] ``` নন-প্রিমিটিভ বা রেফারেন্স ডাটাগুলো সব সময় তাদের রেফারেন্স পাস করে। যখন আমরা কোন রেফারেন্স ডাটাকে অন্য কোন ভেরিয়েবলে অ্যাসাইন করি, তখন তার রেফারেন্স কপি হয়। মানে arr1 কে যখন আমরা arr2 তে অ্যাসাইন করি তখন তার রেফারেন্স বা অ্যাড্রেসটাকে কপি করে বা মনে রাখে তার ভ্যালুকে না। তাই দুইটা ভেরিয়েবলের অ্যাড্রেস একই থাকে। তাই যখন আমরা কোন একটি ভেরিয়েবলের ভ্যালু পরিবর্তন করি, তখন দুইটা ভেরিয়েবলেরই ভ্যালু পরিবর্তন হয়ে যায়। ```js let obj1 = { name: 'JavaScript' }; let obj2 = obj1; console.log(`${obj1.name}`); // JavaScript console.log(`${obj2.name}`); // JavaScript obj2.name = "React"; console.log(`${obj1.name}`); // React console.log(`${obj2.name}`); // React ``` আশা করি, উপরের কোডে কি হচ্ছে সেটা এখন খুব ভাল ভাবেই বুঝতে পারছেন। একটি কথা নন-প্রিমিটিভ ডাটা তাদের রেফারেন্স দ্বারা তুলনা করে। ```js let obj1 = { name: 'JavaScript' }; let obj2 = { name: 'JavaScript' }; console.log(obj1 === obj2); // false ``` এখানে দুইটা অবজেক্টের একই ভ্যালু কিন্তু যখন আমরা দুইটা অবজেক্টকে একে-অপরের সাথে তুলনা করছি, তখন তারা false রিটার্ন করছে। কারণ তাদের ভ্যালু একই হলেও তাদের অ্যাড্রেস এক না। ```js let obj1 = { name: 'JavaScript' }; let obj2 = obj1; console.log(obj1 === obj2); // true ``` ================================================ FILE: basic/6. callback-and-higher-order-functions/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/6. callback-and-higher-order-functions/Examples/example1.js ================================================ /* এখানে circleArea এবং squareArea ফাংশন দুটি হচ্ছে Callback ফাংশন আর areaCalculate ফাংশনটি হচ্ছে Higher Order ফাংশন */ function areaCalculate(arrayWidth, callback) { const area = arrayWidth.map((x) => callback(x)); return area; } function circleArea(radius) { return Math.PI * radius * radius; } function squareArea(side) { return side * side; } const array = [2, 6, 7, 8, 3, 1, 5]; var circleAreaArray = areaCalculate(array, circleArea); console.log(circleAreaArray); var squareAreaArray = areaCalculate(array, squareArea); console.log(squareAreaArray); console.log(array); /* Output: [12.566370614359172, 113.09733552923255, 153.93804002589985, 201.06192982974676, 28.274333882308138, 3.141592653589793, 78.53981633974483] [4, 36, 49, 64, 9, 1, 25] [2, 6, 7, 8, 3, 1, 5] */ ================================================ FILE: basic/6. callback-and-higher-order-functions/Examples/example2.js ================================================ // Dummy object const object = [ { framework: 'React.JS', website: 'Paypal' }, { framework: 'React.JS', website: 'Tesla' }, { framework: 'Angular', website: 'Google' }, { framework: 'Vue.JS', website: 'Vue' }, { framework: 'JavaScript', website: 'inblack67' }, ] // Higher Order Function function modifyArray(arr, callback) { return callback(arr); } // Callback function which add element to existing array function addElemToArray(item, arr) { return [ ...arr, item ]; } // Callback function for counting the occurences of a particular object key like, 'framework' function keyOccurence(key, arr) { const obj = {}; arr.forEach((data) => { if(data.hasOwnProperty(key)){ if(obj[data[key]]){ obj[data[key]]++; } else{ obj[data[key]] = 1; } } }) const occurenceCountObj = Object.keys(obj).map(k => ({ [key]: k, count: obj[k] })) return occurenceCountObj; } // Common bind wrapper for the callback function function bindWrapper(func, ...restArgs) { return func.bind(null, ...restArgs); } console.log(modifyArray(object, bindWrapper(keyOccurence, 'framework'))); /* Output: [ { framework: 'React.JS', count: 2 }, { framework: 'Angular', count: 1 }, { framework: 'Vue.JS', count: 1 }, { framework: 'JavaScript', count: 1 } ] */ console.log(modifyArray(object, bindWrapper(addElemToArray, { framework: 'Gats by', website: 'gatsby' }))); /* Output: [ { framework: 'React.JS', website: 'Paypal' }, { framework: 'React.JS', website: 'Tesla' }, { framework: 'Angular', website: 'Google' }, { framework: 'Vue.JS', website: 'Vue' }, { framework: 'JavaScript', website: 'inblack67' }, { framework: 'Gats by', website: 'gatsby' } ] */ ================================================ FILE: basic/6. callback-and-higher-order-functions/Examples/example3.js ================================================ /* আমরা সাধারণত একটি ফাংশনের আর্গুমেন্ট হিসেবে ভেরিয়েবল, অ্যারে, অবজেক্ট ইত্যাদি পাঠিয়ে থাকি। যদি কোন ফাংশনকে আমরা অন্য ফাংশনের আর্গুমেন্ট হিসেবে পাঠায় তাহলে যে ফাংশনকে আর্গুমেন্ট হিসেবে পাঠাচ্ছি সেটাই Callback Function আর যে ফাংশন Callback Function কে আর্গুমেন্ট হিসেবে গ্রহন করছে সেটাই Higher Order Function. এছাড়াও যে ফাংশন তার রিটার্ন ভ্যালু হিসেবে কোন ফাংশনকে পাস করে তাকেও Higher Order Function বলে। একটু উদাহরণ দেখিঃ */ // Callback Function function sayHi(name) { console.log('Hi, ' + name + '!'); } // Higher Order Function function greetings(process, name) { process(name); console.log('Welcome to Callback and Higher Order function tutorial.'); } let student = 'Ahnaf'; greetings(sayHi, student); /** * Output: * Hi, Ahnaf! * Welcome to Callback and Higher Order function tutorial. */ // Another Higher Order Function function company() { let companyName = 'Vivasoft Ltd.'; let companyType = 'Software Company'; let companyEmail = 'contact@vivasoftltd.com'; function viewDetails() { console.log('Company Name:', companyName); console.log('Type:', companyType); console.log('Email:', companyEmail); } return viewDetails; } let myCompanyDetails = company(); myCompanyDetails(); /** * Output: * Company Name: Vivasoft Ltd. * Type: Software Company * Email: contact@vivasoftltd.com */ ================================================ FILE: basic/6. callback-and-higher-order-functions/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/6. callback-and-higher-order-functions/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/6. callback-and-higher-order-functions/Practices/practice1.md ================================================ নীচের কোডে higherOrderFunction() ফাংশনটি আসলে কোন ধরনের ফাংশন সেটি যাচাই করার চেষ্টা করুন। এবার নীচের কোডের আউটপুট কি হবে সেটা বের করার চেষ্টা করুন। ```js function higherOrderFunction() { let myName = 'Robindranath Thagore'; function displayName() { console.log(myName); } return displayName(); } let viewName = higherOrderFunction(); viewName(); ``` আসলে উপরের কোডের higherOrderFunction() ফাংশনটি একটি সাধারণ ফাংশন, এটি আসলে Higher-Order Function নয়। এমতাবস্থায় higherOrderFunction() ফাংশনটিকে Higher-Order Function বানাতে হলে কোথায় পরিবর্তন করতে হবে সেটার সমাধান করুন। ================================================ FILE: basic/6. callback-and-higher-order-functions/README.md ================================================ কলব্যাক ব্যাপারটি আমাদের জীবনের সাথে ব্যাপকভাবে জড়িয়ে আছে। যদি “সে” কলব্যাক না করে আপনি হয়তো “অ” হয়ে যান! ইয়ে মানে বলতে চাচ্ছিলাম যে অভিমানী নয়তো অস্থির হয়ে যান ;) আর যদি আপনার লাইফে “সে” না থাকে তবে তো কোন কথাই নেই। আমার মত বিন্দাস? । যাইহোক, আপনি “অ” হোন আর না হোন, “সে” কলব্যাক করুক আর না করুক আজকে আমরা কলব্যাক নিয়ে আলোচনা করবোই। চলুন তাহলে শুরু থেকেই শুরু করি… জাভাস্ক্রিপ্টে ফাংশন হচ্ছে একটি ফার্স্ট-ক্লাস অবজেক্ট। এই কারণে, ফাংশন ভেরিয়েবলের মাঝে এসাইন হতে পারে, অন্য একটি ফাংশনকে আর্গুমেন্ট হিসাবে নিতে পারে, ফাংশনের ভিতরেও কাজ করতে পারে এবং ফাংশন দ্বারা রিটার্নও হতে পারে। ### কলব্যাক ফাংশন কি? > সহজ কথায়, কলব্যাক ফাংশন হচ্ছে এমন একটি ফাংশন যেটি অন্য একটি ফাংশনে আর্গুমেন্ট হিসাবে পাস করা ফাংশন, যেটি কোন কাজ সম্পন্ন করার জন্যে আউটার ফাংশনের ভিতরে ইনভোক হয়। ### হাইয়ার অর্ডার ফাংশন কি? > যে ফাংশনে অন্য কোন ফাংশনকে আর্গুমেন্ট হিসাবে পাস করা হয় বা কোন ফাংশন অন্য কোন ফাংশনকে রিটার্ন করে তাকে হাইয়ার অর্ডার ফাংশন বলা হয়। বাংলায় এটাকে ঊচ্চমার্গীয় ফাংশন হিসেবে ভেবে নিতে পারেন। ঊচ্চমার্গীয় কথাবার্তা মাথার উপর দিয়ে গেলেও ঊচ্চমার্গীয় ফাংশন মাথার নিচ দিয়েই যাবে ইনশাআল্লাহ্‌, নিশ্চিত থাকুন। আমাদের এমন একটি ফাংশন আছে যেটি আর্গুমেন্ট হিসেবে একটি অ্যারে নিবে এবং সেটি কে মডিফাই করে একটি নতুন অ্যারে রিটার্ন করবে। এক্ষেত্রে, আমাদের ফাংশনটিকে যে অ্যারে দেওয়া হবে তার সাথে দুই যোগ করে নতুন একটি অ্যারে রিটার্ন করবে। ```js function modifyBy2(arr) { let output = []; for(let i = 0; i < arr.length; i++) { output.push(arr[i] + 2); } return output; } const newArr = modifyBy2([1,2,3,4,5,6]); console.log(newArr); // [3, 4, 5, 6, 7, 8] ``` এখন আমাদের আরেকটি ফাংশন আছে যেটি আর্গুমেন্ট হিসেবে একটি অ্যারে নিবে এবং যে অ্যারে দেওয়া হবে তার সাথে দুই গুণ করে নতুন একটি অ্যারে রিটার্ন করবে। ```js function multifyBy2(arr) { let output = []; for(let i = 0; i < arr.length; i++) { output.push(arr[i] * 2); } return output; } const newArr = modifyBy2([1,2,3,4,5,6]); console.log(newArr); // [2, 4, 6, 8, 10, 12] ``` এখন যদি আমরা বিয়োগ বা ভাগ করতে চাই? তাহলে আমাদেরকে আরও দুটি ফাংশন লিখতে হবে তাই না? ব্যাপারটা তাহলে কি ভাল কিছু হচ্ছে? কোড রিপিটেশন হয়ে যাচ্ছে। একটি বিষয় লক্ষ্য করেন আমাদের লেখা দুটি ফাংশনেই শুধু অপারেশনগুলা ছাড়া একই কোড লিখেছি। আমরা যদি এমন কিছু করতে পারি যে আমাদের ফাংশনে যোগ, বিয়োগ যে কাজই করুক না কেন সেটি আমরা বলে দিবো, তাহলে কেমন হয়? এখন আমরা সে কাজটাই করবো। তার জন্যে আমাদেরকে আমাদের ফাংশনের সাথে আরেকটি আর্গুমেন্ট পাস করতে হবে। যেটি আসলে আমাদের অপারেশনটা হ্যান্ডেল করবে। ```js function modifyArray(arr, fn) { let output = []; for(let i = 0; i < arr.length; i++) { output.push(fn(arr[i])); } return output; } function modifyBy2(elem) { return elem + 2; } const newArr = modifyArray([1,2,3,4,5,6], modifyBy2); console.log(newArr); // [3, 4, 5, 6, 7, 8] ``` উপরের কোডে লক্ষ্য করুন, আমরা **modifyArray** নামে একটি ফাংশন ডিফাইন করেছি যেটি দুটি আর্গুমেন্টস নিচ্ছে। একটি অ্যারে এবং অন্যটি একটি ফাংশন। সে ফাংশনে আমরা বলে দিচ্ছি তার কাজ কি হবে। সে তার কাজ সম্পন্ন করে output অ্যারেতে তার ভ্যালুটা পুশ করে দিচ্ছে এবং modifyArray ফাংশনটি কাজ সম্পন্ন করে একটি নতুন অ্যারে রিটার্ন করতেছে। এখন যদি আমরা বিয়োগ, গুণ বা ভাগ করতে চাই সেটিও খুব সহজেই করতে পারবো এই ফাংশন দিয়ে। আমাদেরকে নতুন করে কোন লজিক লেখা লাগবে না শুধু আমরা একটি নতুন ফাংশন দিয়ে দিবো এবং সেখানে বলে দিবো তাকে কি করতে হবে। তাহলে চলুন দেখি আমাদের কাজ করতে পারি কিনা। ```js function modifyArray(arr, callback) { let output = []; for(let i = 0; i < arr.length; i++) { output.push(callback(arr[i])); } return output; } function addBy2(elem) { return elem + 2; } function multifyBy2(elem) { return elem * 2; } const additionArr = modifyArray([1,2,3,4,5,6], addBy2); const multiArr = modifyArray([1,2,3,4,5,6], multifyBy2); console.log(additionArr); // [3, 4, 5, 6, 7, 8] console.log(multiArr); // [2, 4, 6, 8, 10, 12] ``` **modifyArray** ফাংশনটিতে আর্গুমেন্ট হিসাবে যে ফাংশনটিকে পাস করতেছি ওই ফাংশনটিই হচ্ছে একটি কলব্যাক ফাংশন এবং **modifyArray** ফাংশনটি হচ্ছে একটি **হাইয়ার অর্ডার ফাংশন**। ================================================ FILE: basic/7. this-keyword/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/7. this-keyword/Examples/this_in_constructor_invocation.js ================================================ /* নিম্নলিখিত Bike ফাংশনের */ function Bike(brand) { this.brand = brand; } Bike.prototype.getBrand = function () { return this.brand; }; /* এক্সপ্রেশন new Bike("TVS") হল Bike ফাংশনের একটি constructor invocation। */ var bike = new Bike("TVS"); console.log(bike.getBrand()); // TVS /* এখন, আপনি একটি function বা constructor হিসাবে Bike() invoke করতে পারেন। আপনি যদি new কীওয়ার্ডটি বাদ দেন তাহলে: */ var discover = Bike("Discover"); console.log(discover.brand); // Uncaught TypeError: Cannot read properties of undefined (reading 'brand') /* এই সমস্যার সমাধান: Bike() ফাংশন সবসময় কনস্ট্রাক্টর call করা হয়েছে তা নিশ্চিত করার জন্য, আপনি Bike() ফাংশনের শুরুতে একটি চেক যোগ করুন নিম্নরূপ: */ function Bike(brand) { if (!(this instanceof Bike)) { throw Error("Must use the new operator to call the Bike function"); } this.brand = brand; } ================================================ FILE: basic/7. this-keyword/Examples/this_in_function_context_with_use_strict.js ================================================ /* Function context এ this with 'use strict' mode */ function show() { "use strict"; console.log(this === undefined); // true function display() { console.log(this === undefined); // true } display(); } show(); ================================================ FILE: basic/7. this-keyword/Examples/this_in_function_context_without_use_strict.js ================================================ /* Function context এ this without 'use strict' mode */ function show() { console.log(this === window); // true } show(); // true window.show(); //true ================================================ FILE: basic/7. this-keyword/Examples/this_in_global_context.js ================================================ /* Global context এ this */ console.log(this === window); // true this.color = "Green"; console.log(this.color); // 'Green' console.log(window.color); // 'Green' ================================================ FILE: basic/7. this-keyword/Examples/this_in_method_invocation.js ================================================ /* this সেই object কে উল্লেখ করে ফাংশনটি যার একটি property. অন্য কথায়, this সেই object কে refer করে যা বর্তমানে ফাংশনটিকে কল করছে। ধরুন আপনার counter নামক একটি object আছে। এই counter object এ next() নামে একটি method আছে। যখন আপনি next() method কল করেন, আপনি এই object টি অ্যাক্সেস করতে পারেন। */ const counter = { count: 0, next: function () { return ++this.count; }, }; counter.next(); // 1 counter.next(); // 2 counter.next(); // 3 ================================================ FILE: basic/7. this-keyword/Examples/this_in_method_invocation_with_bind.js ================================================ "use strict"; let bike = { brand: "TVS", getBrand: function () { return this.brand; }, }; console.log(bike.getBrand()); // TVS // নিচের comment এর ফলাফল undefined। কারণ globally এটি strict মোডে undefined এবং non-strict মোডে global object। /* let brand = bike.getBrand; console.log(brand()); // undefined. */ // এই সমস্যা সমাধানের জন্য আমাদের বাইন্ড ব্যবহার করতে হবে let brand1 = bike.getBrand.bind(bike); console.log(brand1()); // TVS let bike2 = { brand: "SINGER", }; let brand2 = bike.getBrand.bind(bike2); console.log(brand2()); // SINGER let bike3 = { brand: "DISCOVER", }; let brand3 = bike.getBrand.bind(bike3); console.log(brand3()); // DISCOVER ================================================ FILE: basic/7. this-keyword/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/7. this-keyword/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/7. this-keyword/Practices/practice1.md ================================================ নীচের কোডের আউটপুট কি হবে? ```js function Mathematician(id, name) { this.id = id; this.name = name; } let muslimMtcn = Mathematician('101', 'Al-Khwarizmi'); console.log(muslimMtcn.name); ``` উপরের কোডটিতে যদি কোন ভূল থাকে সেক্ষেত্রে ঠিকঠাক আউটপুট পেতে হলে কি করতে হবে? ================================================ FILE: basic/7. this-keyword/README.md ================================================ আজকে আলোচনা করতে যাচ্ছি “this” কিওয়ার্ড নিয়ে। জাভাস্ক্রিপ্টে একটি মারাত্মক ভয়ের নাম হচ্ছে “this”। এটি খুবই গুরুত্বপূর্ণ একটা টার্মস যার সম্পর্কে পরিষ্কার ধারণা থাকা উচিত বলে আমি মনে করি। শুরুর দিকে এটা নিয়ে প্রায় সবাই একটু কনফিউশনে ভুগে। কারণ এটি এক এক সময় এক এক রকম আউটপুট দেয়। আমাদের বুঝতে হবে কেন এবং কখন কি আউটপুট দেয়। আমি চেষ্টা করবো ব্যাপারটাকে যতটা সম্ভব সহজভাবে লেখার জন্যে যাতে করে এই “this” নিয়ে আজকের পর থেকে কারোর কোন প্রকার কনফিউশন না থাকে এবং কারোর মাথার উপর দিয়ে না যায়। চলুন একটা উদাহরণ দিয়ে শুরু করা যাকঃ- ```js function myFunc() { console.log(this); } myFunc(); ``` একটু চিন্তা করুন তো এখানে myFunc() ফাংশনটিকে কে কল করতেছে। যদি এইটা ধরতে পারেন তাহলে myFunc() এর আউটপুট কি হবে সেইটাও বুঝতে পারবেন। একটু চিন্তা করুন সময় নিয়ে। আশা করি, চিন্তা করেছেন এবং ধরতেও পেরেছেন। যদি না পারেন তাহলে কোন সমস্যা নেই। একটা ব্যাপার সব সময় মাথায় রাখবেন যে “this” এর ভ্যালু কি হবে সেটা নির্ভর করে কোথায় এবং কিভাবে কল হচ্ছে তার উপর ভিত্তি করে। উপরের কোডে myFunc() কে কল করতেছে window অবজেক্ট। কারণ ব্রাউজারে সব কিছু বাই ডিফল্ট window অবজেক্টের আন্ডারে রান হয়। তার মানে হচ্ছে যে যার মাধ্যমে কল হবে “this” তাকে দেখাবে আউটপুট হিসাবে। ```js window.myFunc(); ``` যেহেতু myFunc() কে window কল করতেছে তাই myFunc() এর ভিতরে থাকা “this” - window এর সব ভ্যালুকে আউটপুট হিসাবে দেখাচ্ছে। আমরা না অনেক ভাল প্রোগ্রামার। তাই ‘use strict’; মোডে উপরের কোডটি আবার রান করুন এবং দেখুন কি হয়। **এইবার চলুন আরেকটি উদাহরণ দেখিঃ-** ```js let Person = { name: "Shahan's Diary", sayName: function() { console.log(this); } }; Person.sayName(); ``` এইবার বলুন তো উপরের কোডটির আউটপুট কি হবে। যারা বলতে পারবেন তাদের জন্যে থাকবে আমার পক্ষ থেকে একটি চকলেট। যদি উপরের বলা কথাগুলা ভালো করে পড়ে থাকেন, বুঝতে কোন অসুবিধা হওয়ার কথা না উপরের কোডের আউটপুট কি হবে। শুধু একটা কথা ভালো করে মনে রাখবেন কোন ফাংশন কল করার সময় ফাংশনের নামের ডটের আগে যে অবজেক্ট নামটা থাকবে তার ভ্যালুই দেখাবে। হ্যাঁ, আমি যদিও অবজেক্টের ভিতরে থাকা ফাংশনকে ফাংশন বলতেছি শুধু বোঝার সুবিধার জন্যে। এটা ফাংশন হবে না, কারণ অবজেক্টের ভিতরে থাকা সব ফাংশনকে বলা হয় মেথড। উপরের কোডের আউটপুট হবে নিচের দেওয়া স্নিপেটের মত। ``` {name: "Shahan's Diary", sayName: f} ``` এখন দেখবো কনস্ট্রাক্টর ফাংশনে “this” নিয়ে কিভাবে কাজ করা যায়। ```js let Person = function(fName, lName) { this.fName = fName; this.lName = lName; this.sayInfo = function() { return console.log("Hi there, Welcome to " + this.fName + " " + this.lName); } }; let person1 = new Person("Shahan's", "Diary"); person1.sayInfo(); // Hi there, Welcome to Shahan's Diary ``` আশা করি, আপনাদের “this” এর বেসিক ধারণাটা এখন পরিষ্কার হয়েছে। এখন থেকে দেখলেই বুঝবেন যে “this” কি কাজ করছে। হ্যাঁ, এই লেখাটা পড়েই আপনি “this” এর মাস্টার হয়ে যাবেন না। এর আরেকটু অ্যাডভান্সড ব্যবহার রয়েছে। সেটা আপনাদের জন্যে রেখে দিলাম। একটু কষ্ট করে নিজ দায়িত্বে দেখে নিবেন। এরপরেও, যদি মাথার উপর দিয়ে যায় তাহলে কমেন্ট বক্সে কমেন্ট করে উড়াই দিবেন, আমি ধরে নিবো। হ্যাপি কোডিং.... ================================================ FILE: basic/8. event-capturing-and-bubbling/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/8. event-capturing-and-bubbling/Examples/example1.md ================================================ We already know the basics of event capturing and bubbling. In this example, we will dive a little deeper. The third argument of 'addEventListener' function tell whether the event will be in the capture phase or in the bubbling phase. By default it is in bubbling phase (if we provide no parameter) ```html Event Bubbling and Capturing
Grandparent
Parent
Child
``` Run the code. now click on the child div. We can see that the output will be. Output: Parent clicked Child clicked Grandparent clicked We can see that the event capturing of event listeners happened first and then the event bubbling happened. This means the propagation of event listeners first goes from outside to inside and then from inside to outside in the DOM. As 'parent' div is propagated, it prints to the console first, then by follwing event capturing rules, 'child' div is clicked and 'grandparent' div is clicked. I hope things are clear now. We can play with this code as we want and see different output. ================================================ FILE: basic/8. event-capturing-and-bubbling/Examples/example2.md ================================================ We can stop event capturing and bubbling if we want. We can use a parameter "e" in the callback function of addEventListener function. It is an event object which has a function called stopPropagation() which helps to stop event capturing and bubbling. ```html How to stop Event Capturing and Bubbling
Grandparent
Parent
Child
``` Output: Child clicked Parent clicked If we clicked on child div, the propagation is stopped on parent div and does not move to grandparent div. Hence, the event bubbling is prevented. We can also stop capturing the same way. ================================================ FILE: basic/8. event-capturing-and-bubbling/Examples/example3.md ================================================ ইফেক্ট বুঝতে হলে প্রথমে এই HTML ফাইলটি আপনার ব্রাউজারে ওপেন করে মাউসের রাইট বাটন ক্লিক করে Inspect এ ক্লিক করুন। অতঃপর Console ট্যাবে ক্লিক করুন। এখন Event Bubbling ও Event Capturing কিভাবে হচ্ছে সেটা বুঝতে বক্সগুলোতে ক্লিক করে দেখুন। ```html Event Bubbling and Capturing

Event Bubbling
Click Me

Event Capturing
Click Me

``` addEventListener() ফাংশনের তৃতীয় argument হিসেবে আমরা যে true/false ভ্যালু দিয়েছি সেটা বাই ডিফল্ট false থাকে অর্থাৎ nested element ক্লিক করার ক্ষেত্রে সেটা বাই ডিফল্ট event bubbling করে থাকে। বিষয়টি যদি অন্যভাবে বলি তাহলে বলা যায় যে তৃতীয় আর্গুমেন্টে জিজ্ঞাসা করা থাকে এই event টি প্রথমে capture করা হবে নাকি হবে না। ================================================ FILE: basic/8. event-capturing-and-bubbling/Examples/example4.md ================================================ ইফেক্ট বুঝতে হলে প্রথমে এই HTML ফাইলটি আপনার ব্রাউজারে ওপেন করে মাউসের রাইট বাটন ক্লিক করে Inspect এ ক্লিক করুন। অতঃপর Console ট্যাবে ক্লিক করুন। এখন Event Bubbling ও Event Capturing কিভাবে হচ্ছে সেটা বুঝতে বক্সগুলোতে ক্লিক করে দেখুন। ```html Event Bubbling and Capturing

Event Bubbling
Click Me

Event Capturing
Click Me

``` এই উদাহরণে আমরা তেমন কোন নতুন কাজ করি নাই। এই উদাহরণে আমরা শুধুমাত্র প্রোসেস দুটি কিভাবে হচ্ছে সেটার একটা ভিজুয়াল ইফেক্ট তৈরী করেছি। ================================================ FILE: basic/8. event-capturing-and-bubbling/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/8. event-capturing-and-bubbling/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/8. event-capturing-and-bubbling/Practices/practice1.md ================================================ নীচের কোডটি কোন HTML ডকুমেন্ট হিসেবে সংরক্ষণ করুন এবং আপনার ব্রাউজারে ওপেন করুন। কোডটি ব্রাউজারে ওপেন করলে চারটি কালারের (লাল-সোনালী-সবুজ-আকাশি) বক্স দেখতে পাবেন। মাঝের Skyblue (আকাশি) কালারের বক্সে ক্লিক করলে ইভেন্টের সিরিয়াল কেমন হবে? ```html Event Bubbling and Capturing
Click Me
``` ================================================ FILE: basic/8. event-capturing-and-bubbling/Practices/practice2.md ================================================ What will be the output we will get on the console if child div is clicked? Why the output was like that? ```html
Grandparent
Parent
Child
``` ================================================ FILE: basic/8. event-capturing-and-bubbling/README.md ================================================ ### 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 হিসাবে পাস করুন. উদাহরণঃ ```html
``` উপরের কাঠামোতে, অনুমান করুন যে button element টিতে একটি ক্লিক ইভেন্ট ঘটেছে। ক্যাপচারিং মডেলে, ইভেন্টটি প্রথমে ডিভ দ্বারা পরিচালনা করা হবে, তারপর টার্গেট এলিমেন্ট button এ শেষ পর্যন্ত পরিচালনা করা হবে. bubbling মডেলে, বিপরীত ঘটবে: ইভেন্টটি প্রথমে button দ্বারা পরিচালনা করা হবে, তারপরে ডিভ element দ্বারা. #### Event Capturing ইভেন্ট ক্যাপচারিং-এ, একটি ইভেন্ট সবচেয়ে বাইরের element থেকে target এ চলে যায়. ইভেন্ট bubbling করার আগে ইভেন্ট ক্যাপচারিং করা হয় কিন্তু ক্যাপচারিং খুব কমই ব্যবহার করা হয় কারণ ইভেন্ট bubbling ইভেন্ট ফ্লো পরিচালনা করার জন্য যথেষ্ট। ইভেন্ট ক্যাপচারিং এর কাজ বোঝার জন্য একটি উদাহরণ কোড দেখি: ```html
``` **Output:** ![image](https://user-images.githubusercontent.com/712313/142607809-7e76f19f-021f-46c1-a2b8-2d78098b3321.png) - HTML অংশে, আমরা একটি div id ধারণ করে id = p1 তৈরি করেছি। div-এর ভিতরে, আমরা নেস্ট করেছি এবং id = c1 সহ একটি button তৈরি করেছি। - JS কোডে, প্রাথমিকভাবে, আমরা html elements গুলি assign করেছি, অর্থাৎ, p1 id, querySelector () পদ্ধতি ব্যবহার করে একটি variable parent এর কাছে এবং আমরা একই কাজ করেছি - c1 আইডি দিয়ে যেখানে আমরা এটি একটি child variable assign করেছি. - তারপরে আমরা একটি ক্লিক ইভেন্ট ব্যবহার করেছি এবং এটি p1 div এবং c1 button উভয়ের সাথে সংযুক্ত করেছি. কনসোলে উপযুক্ত message প্রিন্ট করার জন্য একটি ফাংশনও রয়েছে. এর মানে যদি চাইল্ড ইভেন্টটি প্রথমে invoke হয়, তারপর এটি প্রথমে কনসোলে "Child is invoked" message টি প্রিন্ট করবে, এবং যদি প্যারেন্ট ইভেন্ট হ্যান্ডলারকে প্রথমে invoke হয়, এটি প্রথমে কনসোলে "Parent is invoked" message দেবে। - এর পরে, আমরা প্যারেন্ট div এ ইভেন্ট ক্যাপচারিং সক্ষম করার জন্য addEventListner () এর তৃতীয় আর্গুমেন্ট যোগ করেছি। - যখন আমরা button এ ক্লিক করি, এটি প্রথমে ফাংশনটি কার্যকর করে, যা প্যারেন্ট ডিভ-এ সংযুক্ত থাকে। - এর পরে, button টির অনক্লিক () ফাংশন run করে এবং এটা event ক্যাপচারের কারণে. ইভেন্ট ক্যাপচারিংয়ের কারণে, মূল event এর event টি প্রথমে কার্যকর হয়, এব তারপর target element এর event কার্যকর করা হয়. সুতরাং, যখন আমরা button এ ক্লিক করি, ক্লিক ইভেন্ট নিম্নলিখিত sequence এ সঞ্চালিত হয়, আপনি নীচের ফ্লোচার্ট দেখতে পারেন: ![image](https://user-images.githubusercontent.com/712313/142607966-a0227a6c-f5aa-4077-a694-6874fd34fe5c.png) #### Evnet Bubbling: ইভেন্ট bubbling এর কাজের ধারণাটি বোঝার জন্য আসুন নীচের উদাহরণটি দেখি: ```html
``` **Output:** ![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) যথাক্রমে 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 এর ইভেন্ট হ্যান্ডলারটি কাজ করবে। ইভেন্ট bubbling এর কারণে এই ধরনের sequence টি ঘটেছে আর এভাবেই event bubbling সঞ্চালিত হয়। এর মানে ব্যবহারকারী যখন button এ ক্লিক করেন, ক্লিক ইভেন্ট এই ক্রমে নীচে থেকে উপরে প্রবাহিত হয়। নিচের ফ্লো চার্টের সাহায্যে আমরা ইভেন্টের প্রবাহ বুঝতে পারি: ![image](https://user-images.githubusercontent.com/712313/142606596-d3f2f583-6c89-41d7-b51a-17896f57a89e.png) একটি ইভেন্টের সম্পূর্ণ প্রবাহ কিভাবে সম্পাদন হয় নীচের diagram টি দ্বারা সেটি দেখানো হলো: ![image](https://user-images.githubusercontent.com/712313/142607997-8b6caa69-3d3d-446c-a223-724218ff532e.png) ================================================ FILE: basic/9. event-delegation-and-propagation/Examples/README.md ================================================ ### সকল উদাহরন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/9. event-delegation-and-propagation/Examples/example1.md ================================================ Event delegation takes advantage of event propagation. It allows the event listener to be set on a parent element, thus avoiding adding event listeners to all the elements. The event listener is set on a parent element which listens for click events. If parent element is clicked, the callback will compare event.target (element which was clicked) against a common property. This will be clear if we see the example below: ```html Event Delegation and Propagation
``` When a button or element is clicked, the listener of the parent element catches the bubbling event. If we click on Button 1, then the output will be: button 1 was clicked or if we click on the 'box1' div, output will be: Box 1 was clicked Here, using event delegation we dont need to add a click listener to every one of the elements like we saw in the previous topic. We just need to add a event listener to the parent div and by using event bubbling formula, we can access the clicked child element by using 'e.target' ================================================ FILE: basic/9. event-delegation-and-propagation/Examples/example2.md ================================================ Another classic example of event delegation would be this example below, which we might use regularly. Suppose we have a div on which we have many input boxes. We want to convert specific input values to uppercase. --> ```html Event Delegation & Propagation
``` ================================================ FILE: basic/9. event-delegation-and-propagation/Examples/example3.md ================================================ ইফেক্ট বুঝতে হলে প্রথমে এই HTML ফাইলটি আপনার ব্রাউজারে ওপেন করে মাউসের রাইট বাটন ক্লিক করে Inspect এ ক্লিক করুন। অতঃপর Console ট্যাবে ক্লিক করুন। এখন Event Bubbling ও Event Capturing কিভাবে হচ্ছে সেটা বুঝতে বক্সগুলোতে ক্লিক করে দেখুন। মনেকরি আমাদের কাছে নীচের কোড অনুযায়ী একটি HTML ফাইল আছে। ```html Event Delegation and Propagation

Event Delegation Example

``` এখন আমরা কোন বাটনের সাথে ক্লিক ইভেন্ট যুক্ত না করে সেন্ট্রালি তাদের কন্টেইনার 'btn-container' এর সাথে ইভেন্টটি যুক্ত করবো। একই সাথে কোন element বা button এ ক্লিক হচ্ছে সেটা দেখার জন্য আমরা উপরের কোডের জাভাস্ক্রিপ্টের ভিতরে নীচের কোড যুক্ত করবো। ```js btnConatiner.addEventListener('click', (e) => { console.log(e.target); }) ``` এখন আমরা 'btn-container' এর ভিতরে কোথায় ক্লিক করছি সেটা ব্রাউজারের console ট্যাবে খুব সুন্দর করে দেখতে পাবো। এখন আমরা চাইলে আমাদের ইচ্ছা মতো এটাকে কাজে লাগাতে পারি। এখানে আমরা বাটনের লেখা অনুযায়ী কাজ করার জন্য ইভেন্ট লিসেনারকে নীচের কোডের মতো করে লিখিঃ ```js btnConatiner.addEventListener('click', (e) => { console.log(e.target); if(e.target.id === 'green') { e.target.classList.add('btn', 'green'); } else if(e.target.id === 'blue') { e.target.classList.add('btn', 'blue'); } else if(e.target.id === 'purple') { e.target.classList.add('btn', 'purple'); } }) ``` এখন বাটনগুলোতে ক্লিক করে দেখো। আসলে 'btn-container' কিভাবে এই ক্লিক ইভেন্ট পাচ্ছে সেটা আগেই আমরা জেনেছি [event-capturing-and-bubbling](https://github.com/vivasoft-ltd/javascript-bootcamp/tree/main/basic/8.%20event-capturing-and-bubbling) পার্ট থেকে। এই ক্লিক ইভেন্টটি কিভাবে propagate হচ্ছে সেটা দেখতে চাইলে নীচের কোডের মতো করে ইভেন্ট লিসেনার যুক্ত করুন। ```js btnConatiner.addEventListener('click', (e) => { console.log(e.path); }) ``` এখন আশাকরি ইভেন্ট bubbling, propagation এবং delegation নিয়ে আর কোন সংশয় থাকবে না। হ্যাপি কোডিং ;) ================================================ FILE: basic/9. event-delegation-and-propagation/Interview Questions/README.md ================================================ ### সকল ইন্টারভিউ এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/9. event-delegation-and-propagation/Practices/README.md ================================================ ### সকল প্রাকটিস এর প্রশ্ন এই ফোল্ডারে দেখা যাবে। ================================================ FILE: basic/9. event-delegation-and-propagation/Practices/practice1.md ================================================ How can we use only one addEventListener in this code to access any element? Use Event Delegation to solve this. ```html Event Delegation and Propagation
``` ================================================ FILE: basic/9. event-delegation-and-propagation/README.md ================================================ ### Event delegation and propagation ইভেন্ট delegation ইভেন্ট propagation পদ্ধতি ব্যবহার করে। ইভেন্ট delegation কীভাবে কাজ করে তা বোঝার জন্য, আমাদেরকে প্রথমে ইভেন্ট propagation বুঝতে হবে। ### Event propagation আপনি যখন নিম্নলিখিত HTML এর button টি ক্লিক করেনঃ ```html
``` একটি ক্লিক ইভেন্ট কতগুলি element এ ট্রিগার হয়? button টি নিজেই একটি ক্লিক ইভেন্ট পায়। কিন্তু এছাড়াও ঐ button এর সকল ancestors এবং এমনকি document ও window অবজেক্ট ক্লিক ইভেন্ট পায়। একটি ক্লিক ইভেন্ট 3টি পর্যায়ে প্রচারিত হয়: 1. Capture phase — window, document এবং root element থেকে শুরু করে ইভেন্ট টার্গেট এলিমেন্টের ancestor মধ্য দিয়ে নিচে নেমে যায়। 2. Target phase — ব্যবহারকারী যে element টিতে ক্লিক করেছেন তাতে ইভেন্টটি ট্রিগার হয়। 3. Bubble phase — অবশেষে, root element, document এবং window পর্যন্ত target element এর ancestor এর মাধ্যমে event টি bubble up হয়ে যায়। ![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]); ``` - যদি captureOrOptions argument টি missing, false বা { capture: false } হয়, তাহলে listener target এবং bubble phase এর event গুলি ক্যাপচার করে - যদি argument টি true হয় বা { capture: true } হয়, তাহলে listener ক্যাপচার পর্বের ঘটনাগুলি শোনে। তাহলে, কিভাবে ইভেন্ট propagation একাধিক button এর event ক্যাপচার করতে সাহায্য করে? অ্যালগরিদম টি সহজ: ইভেন্ট লিসেনারকে button এর parent এর সাথে সংযুক্ত করুন, এবং একটি button ক্লিক করা হলে bubble ইভেন্ট ধরতে হবে। ঠিক এভাবেই ইভেন্ট delegation কাজ করে। ### Event delegation আসুন একাধিক button এ ক্লিকগুলি ধরতে ইভেন্ট delegation ব্যবহার করি: ```html
``` ইভেন্ট delegation mechanism টি অনেক সহজ, ইভেন্ট listener দের সরাসরি button গুলিতে সংযুক্ত করার পরিবর্তে, আপনি parent element `
` -এ ইভেন্ট listen delegate করেন। যখন একটি ক্লিক করা হয়, তখন মূল element টির listener (parent element টির listener) bubble ইভেন্টটি ধরে। ইভেন্ট delegation ব্যবহার করার জন্য 3টি পদক্ষেপ প্রয়োজন: **Step 1. ইভেন্টগুলি ধরার জন্য element গুলির parent নির্ধারণ করুন**
(উপরের উদাহরণে, `
` হল button গুলির parent element) **Step 2. ইভেন্ট listener কে মূল element এর সাথে সংযুক্ত করুন** `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 ```javascript .addEventListener('click', event => { if (event.target.className === 'buttonClass') { console.log('Click!'); } }); ``` `event.currentTarget` সেই element টিকে নির্দেশ করে যেখানে ইভেন্ট listener সরাসরি সংযুক্ত থাকে। উদাহরণে, `event.currentTarget` হল `
`। ================================================ FILE: basic/README.md ================================================ ## Table of contents 1. [Execution Context (এক্সিকিউশন কনটেক্সট)](1.%20execution-context) 2. [Scope (স্কোপ)](2.%20scope) 3. [Hoisting (হইস্টিং)](3.%20hoisting) 4. [Closure (ক্লোজার)](4.%20closure) 5. [Call by value and call by reference (কল বাই ভ্যালু এবং কল বাই রেফারেন্স)](5.%20call-by-value-and-call-by-reference) 6. [Callback & Higher-Order functions (কলব্যাক এবং হাইয়ার অর্ডার ফাংশন)](6.%20callback-and-higher-order-functions) 7. [This Keyword (দিস কিওয়ার্ড)](7.%20this-keyword) 8. [Event capturing and bubbling (ইভেন্ট ক্যাপচারিং এবং বাবলিং)](8.%20event-capturing-and-bubbling) 9. [Event delegation and propagation (ইভেন্ট ডেলিগেশন এবং প্রোপাগেশন)](9.%20event-delegation-and-propagation) 10. [Browser Storage and Caching (ব্রাউজার স্টোরেজ এবং ক্যাশিং)](10.%20browser-storage-and-caching) 11. [Debouncing and Throttling (ডিবাউন্সিং এবং থ্রোটলিং)](11.%20debouncing-and-throttling) 12. [Use Strict in JavaScript (ইউস স্ট্রিক্ট ইন জাভাস্ক্রিপ্ট)](12.%20use-strict) 13. [IIFE in JavaScript (আইআইএফই ইন জাভাস্ক্রিপ্ট)](13.%20iife-in-javascript) ================================================ FILE: projects/README.md ================================================ # VivaSoft JavaScript Bootcamp Projects This repository contains all the projects for VivaSoft Javascript Bootcamp. | # | 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/) | ================================================ FILE: projects/big-bang/index.html ================================================ Big Bang

0

Points

Score: 0
================================================ FILE: projects/big-bang/index.js ================================================ const canvas = document.querySelector("canvas"); const c = canvas.getContext("2d"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; const x = canvas.width / 2; const y = canvas.height / 2; let modalEL = document.getElementById("modalEl"); let finalScore = document.getElementById("finalScore"); let scoreId = document.getElementById("scoreId"); let interval; let score = 0; let animationId; const projectiles = []; const enemies = []; class Player { constructor(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; } draw() { c.beginPath(); c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); c.fillStyle = this.color; c.fill(); } } class Projectile { constructor(x, y, radius, color, velocity) { this.x = x; this.y = y; this.radius = radius; this.color = color; this.velocity = velocity; } draw() { c.beginPath(); c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); c.fillStyle = this.color; c.fill(); } update() { this.draw(); this.x = this.x + this.velocity.x; this.y = this.y + this.velocity.y; } } class Enemy { constructor(x, y, radius, color, velocity) { this.x = x; this.y = y; this.radius = radius; this.color = color; this.velocity = velocity; } draw() { c.beginPath(); c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); c.fillStyle = this.color; c.fill(); } update() { this.draw(); this.x = this.x + this.velocity.x; this.y = this.y + this.velocity.y; } } let player = new Player(x, y, 10, "white"); function drawPlayer() { player = new Player(x, y, 10, "white"); player.draw(); } function spawnEnemy() { if (!interval) { interval = setInterval(() => { const radius = Math.random() * (30 - 4) + 4; let x, y; if (Math.random() < 0.5) { x = Math.random() < 0.5 ? 0 - radius : canvas.width + radius; y = Math.random() * canvas.height; } else { x = Math.random() * canvas.width; y = Math.random() < 0.5 ? 0 - radius : canvas.height + radius; } const color = `hsl(${Math.random() * 360}, 50%, 50%)`; const angle = Math.atan2(canvas.height / 2 - y, canvas.width / 2 - x); const velocity = { x: Math.cos(angle), y: Math.sin(angle), }; enemies.push(new Enemy(x, y, radius, color, velocity)); }, 1000); } } function animate() { animationId = requestAnimationFrame(animate); c.fillStyle = "rgba(0,0,0,0.1)"; c.fillRect(0, 0, canvas.width, canvas.height); player.draw(); projectiles.forEach((projectile, index) => { projectile.update(); if ( projectile.x + projectile.radius < 0 || projectile.x - projectile.radius > canvas.width || projectile.y + projectile.radius < 0 || projectile.y - projectile.radius > canvas.height ) { projectiles.splice(index, 1); } }); enemies.forEach((enemy, index) => { enemy.update(); // End Game const dist = Math.hypot(player.x - enemy.x, player.y - enemy.y); if (dist - player.radius - enemy.radius < 1) { cancelAnimationFrame(animationId); modalEL.style.display = "block"; projectiles.splice(0, projectiles.length); enemies.splice(0, enemies.length); document.getElementById("scoreId").innerHTML = score; document.getElementById("finalScore").innerHTML = score; score = 0; clearInterval(interval); interval = null; } projectiles.forEach((projectile, projectileIndex) => { // Detect contact between projectile and enemy const dist = Math.hypot(projectile.x - enemy.x, projectile.y - enemy.y); if (dist - projectile.radius - enemy.radius < 1) { if (enemy.radius - 10 > 10) { enemy.radius -= 10; score += 5; document.getElementById("scoreId").innerHTML = score; setTimeout(() => { projectiles.splice(projectileIndex, 1); }, 0); } else { setTimeout(() => { enemies.splice(index, 1); projectiles.splice(projectileIndex, 1); score += 10; document.getElementById("scoreId").innerHTML = score; }, 0); } } }); }); } window.addEventListener("click", (event) => { const angle = Math.atan2( event.clientY - canvas.height / 2, event.clientX - canvas.width / 2 ); const velocity = { x: Math.cos(angle) * 5, y: Math.sin(angle) * 5, }; projectiles.push( new Projectile(canvas.width / 2, canvas.height / 2, 5, "white", velocity) ); }); function startGame() { modalEL.style.display = "none"; document.getElementById("scoreId").innerHTML = score; animate(); spawnEnemy(); } ================================================ FILE: projects/blurry-loading/index.html ================================================ Blurry Loading
0%
================================================ FILE: projects/blurry-loading/script.js ================================================ 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 } ================================================ FILE: projects/blurry-loading/style.css ================================================ @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; } ================================================ FILE: projects/expanding-cards/index.html ================================================ Expanding Cards

Explore The World

Wild Forest

Sunny Beach

City on Winter

Mountains - Clouds

================================================ FILE: projects/expanding-cards/script.js ================================================ const panels = document.querySelectorAll('.panel') panels.forEach(panel => { panel.addEventListener('click', () => { removeActiveClasses() panel.classList.add('active') }) }) function removeActiveClasses() { panels.forEach(panel => { panel.classList.remove('active') }) } ================================================ FILE: projects/expanding-cards/style.css ================================================ @import url('https://fonts.googleapis.com/css?family=Muli&display=swap'); * { box-sizing: border-box; } body { font-family: 'Muli', sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; overflow: hidden; margin: 0; } .container { display: flex; width: 90vw; } .panel { background-size: cover; background-position: center; background-repeat: no-repeat; height: 80vh; border-radius: 50px; color: #fff; cursor: pointer; flex: 0.5; margin: 10px; position: relative; -webkit-transition: all 700ms ease-in; } .panel h3 { font-size: 24px; position: absolute; bottom: 20px; left: 20px; margin: 0; opacity: 0; } .panel.active { flex: 5; } .panel.active h3 { opacity: 1; transition: opacity 0.3s ease-in 0.4s; } @media (max-width: 480px) { .container { width: 100vw; } .panel:nth-of-type(4), .panel:nth-of-type(5) { display: none; } } ================================================ FILE: projects/modal/app.js ================================================ (function() { function Modal() {} Modal.prototype.open = function() { const modal = document.querySelector(".modal"); console.log("hello") modal.classList.add("modal--active") } Modal.prototype.close = function() { const modal = document.querySelector(".modal"); modal.classList.remove("modal--active") } document.addEventListener("DOMContentLoaded", function() { const modal = new Modal(); const openModal = document.querySelector("#openModal"); const closeModal = document.querySelectorAll(".modal__close"); openModal.addEventListener("click", function() { modal.open() }) closeModal.forEach(function(btnClose) { btnClose.addEventListener("click", function() { modal.close() }) }) }); })() ================================================ FILE: projects/modal/index.html ================================================ Modal || Vanilla JavaScript ================================================ FILE: projects/modal/style.css ================================================ *, *::after, *::before { -webkit-box-sizing: inherit; box-sizing: inherit; } body { margin: 0; -webkit-box-sizing: border-box; box-sizing: border-box; font-family: 'Poppins', sans-serif; font-size: 16px; font-weight: 400; line-height: 1.4; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; height: 100vh; } h1, h2, h3, h4, h5, h6 { margin-top: 0; margin-bottom: 25px; } p { margin-top: 0; margin-bottom: 15px; } p:last-child { margin-bottom: 0; } .btn { padding: 15px 30px; border: none; cursor: pointer; border-radius: 4px; -webkit-transition: all .3s ease-in-out 0s; -o-transition: all .3s ease-in-out 0s; transition: all .3s ease-in-out 0s; } .btn--primary { background-color: #2D31FA; color: #fff; } .btn--primary:hover { background-color: #5D8BF4; } .btn--danger { background-color: #EB4747; color: #fff; } .btn--danger:hover { background-color: #FF8B8B; } .modal__footer--right .btn--primary { margin-right: 15px; } @-webkit-keyframes scale-up-center { 0% { -webkit-transform: scale(0.5); transform: scale(0.5); } 100% { -webkit-transform: scale(1); transform: scale(1); } } @keyframes scale-up-center { 0% { -webkit-transform: scale(0.5); transform: scale(0.5); } 100% { -webkit-transform: scale(1); transform: scale(1); } } .modal { position: fixed; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; padding: 30px; height: 100%; width: 100%; visibility: hidden; opacity: 0; } .modal.modal--active { visibility: visible; opacity: 1; } .modal.modal.modal--active .modal__container { -webkit-animation: scale-up-center 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both; animation: scale-up-center 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both; } .modal--small .modal__container { width: 600px; } .modal--full .modal__container { height: 100%; width: 100%; } .modal__container { position: relative; z-index: 1; background-color: #fff; border-radius: 4px; width: 1200px; } .modal__header { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; border-bottom: 1px solid #ddd; -webkit-box-align: center; -ms-flex-align: center; align-items: center; padding: 30px; } .modal__header--left { -webkit-box-orient: horizontal; -webkit-box-direction: reverse; -ms-flex-direction: row-reverse; flex-direction: row-reverse; } .modal__title { margin-bottom: 0; font-weight: 700; } .modal__close--icon { cursor: pointer; padding: 10px 15px; font-size: 18px; line-height: 1; background-color: transparent; border-radius: 4px; -webkit-transition: all .3s ease-in-out 0s; -o-transition: all .3s ease-in-out 0s; transition: all .3s ease-in-out 0s; } .modal__close--icon:hover { background-color: rgb(190, 46, 46); color: #fff; } .modal__body { padding: 30px; } .modal__footer { display: -webkit-box; display: -ms-flexbox; display: flex; border-top: 1px solid #ddd; padding: 30px; } .modal__footer--right { -webkit-box-pack: end; -ms-flex-pack: end; justify-content: flex-end; } .modal__footer--between { -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; } .modal__backdrop { position: absolute; left: 0; top: 0; background-color: rgba(0, 0, 0, .1); height: 100vh; width: 100vw; } ================================================ FILE: projects/snake-eye/index.html ================================================ Snake Eye ================================================ FILE: projects/snake-eye/index.js ================================================ 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();