diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md new file mode 100644 index 000000000..3561b2231 --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -0,0 +1,241 @@ +# অবজেক্ট রেফারেন্স এবং কপি করা + +অবজেক্ট এবং প্রিমিটিভ দের মধ্যে অন্যতম পার্থক্য হলো যে অবজেক্ট গুলি কপি ও সংরখ্যন হয় রেফারেন্স এর মাধ্যমে, যেখানে প্রিমিটিভ মানঃ স্ট্রিং, বুলিয়ান, ইত্যাদি -- যেগুলো সবসময় "সম্পুর্ন মান" হিসেবে কপি হয়। + +একটি মান কপি করলে কি হয় তা একটু গভীরভাবে দেখলেই আমরা এটি আরো ভালোভাবে বুঝতে পারব। + +স্ট্রিং এর মত একটি প্রিমিটিভ নিয়েই শুরু করা যাক। + +এখানে আমরা `message` এর একটি কপি কে `phrase` এ রাখলামঃ + +```js +let message = "Hello!"; +let phrase = message; +``` + +এর ফলে আমরা দুটি স্বাধীন ভেরিয়েবল আছে, প্রতিটি "হেলো" স্ট্রিংটি সংরক্ষণ করছে । + +![](variable-copy-value.svg) + +খুব স্বাবাভিক ই মনে হচ্ছে, তাই না? + +অবজেক্ট রা এমন নয়। + +**একটি অবজেক্ট এর জন্য নির্ধারিত ভেরিয়েবল সেই অবজেক্ট কে সংরক্ষণ করে না, বরং এর ঠিকানা সংরক্ষণ করে, অন্য কথায় এটির একটি "রেফারেন্স"।** + +এমন একটি ভেরিয়েবল এর উদাহরণ দেখা যাকঃ + +```js +let user = { + name: "John" +}; +``` + +এটি স্মৃতি তে কিভাবে সংরক্ষণ করা হয় তা নিচের ছবিতে দেখানো হলোঃ + +![](variable-contains-reference.svg) + +অবজেক্ট টি স্মৃতির কোথাও সংরক্ষণ করা আছে (ডানে), আর `user` ভেরিয়েবল এর কাছে এর একটি রেফারেন্স আছে। + +আমরা `user` এর মতো অবজেক্ট কে একটি কাগজের টুকরো হিসেবে ভাবতে পারি, যাতে ঠিকানা লেখা আছে । + +যখন আমরা অবজেক্ট এর উপরে কোন কাজ করি, যেমন `user.name` প্রপার্টি কে নেয়া, জাভাস্ক্রিপ্ট ইঞ্জিন ঠিকানা থেকে অবজেক্ট টি বের তার উপরে কাজ টি সম্পাদন করে । + +এটি গুরুতপুর্ন কারণ + +**যখন কোনও বস্তুর ভেরিয়েবল কপি করা হয় - রেফারেন্সটি কপি হয়, বস্তুটি নকল হয় না ।** + +যেমন : + +```js no-beautify +let user = { name: "John" }; + +let admin = user; // রেফারেন্স কপি হলো +``` + +এখন আমাদের দুটি ভেরিয়েবল রয়েছে, প্রত্যেকেই একই বস্তুর রেফারেন্স: + +![](variable-copy-reference.svg) + +আমরা দেখতে পাচ্ছি যে, অবজেক্ট একটাই আছে কিন্তু এখন একে দুটি ভেরিয়েবল রেফারেন্স করছে । + +আমরা এই দুটি ভেরিয়েবল এর যেকোনো টি ব্যাবহার করে অবজেক্ট টি এক্সেস করতে পারি ও এর ভেতরের কন্টেন্ট বা ডেটা গুলি পরিবর্তন করতে পারি। + +```js run +let user = { name: 'John' }; + +let admin = user; + +*!* +admin.name = 'Pete'; // এডমিন রেফারেন্সের এর মাধ্যমে পরিবর্তন হলো +*/!* + +alert(*!*user.name*/!*); // 'Pete', পরিবর্তন টি "user" রেফারেন্স থেকে দেখা যাচ্ছে +``` + + +উপরের উদাহরণটি প্রমাণ করে যে এখানে কেবল একটি অবজেক্ট রয়েছে। যেন আমাদের একি কক্ষের দুটি চাবি আছে আর আমরা একটি চাবি (`admin`) দিয়ে কক্ষে প্রবেশ করেছি। পরে অন্যটি (`user`) দিয়ে কক্ষের ভেতরে দেখেছি। + +## রেফারেন্স এর মাধ্যমে তুলনা + +যদি দুটি অবজেক্ট একই বস্তু হয়, শুধুমাত্র তাহলেই তারা "ইকুয়াল"। + +যেমন, এখানে `a` এবং `b` একই অবজেক্ট কে রেফারেন্স করে, সুতরাং তারা ইকুয়াল: + +```js run +let a = {}; +let b = a; // রেফারেন্স কপি হোলো + +alert( a == b ); // true, দুটি অবজেক্ট ই সমান +alert( a === b ); // true +``` + +আর এখানে দুটি অবজেক্ট সমান নয়, যদিও তারা দেখতে একই (দুজনই খালি) : + +```js run +let a = {}; +let b = {}; // দুটি স্বাধীন অবজেক্ট + +alert( a == b ); // false +``` + +`obj1 > obj2` এর মত তুলনা এর জন্য অথবা কোন প্রিমিটিভ এর সাথে তুলনা করার জন্য `obj == 5`, অবজেক্ট কে প্রিমিটিভ এ রূপান্তর করা হয়। অবজেক্ট গুলোকে কিভাবে তুলনা করা হয় তা সম্পর্কে আমরা শিগ্রই জানব, কিন্তু সত্যি বলতে এই ধরনের তুলনা খুব কমই প্রয়োজন হয়, সাধারণত এগুলি ভুলক্রমে চলে আসে। + +## ক্লোন করা ও মিলিত করা, Object.assign + +তো আমরা জানলাম অবজেক্ট ভেরিএবল কে কপি করলে তা শুধু একটি নতুন রেফারেন্স তৈরি করে। + +কিন্তু আমাদের যদি অবজেক্ট এর স্বাধীন নকল বা ক্লোন তৈরি করতে হয় তাহলে আমরা কি করব? + +তাও সম্ভব কিন্তু একটু কঠিন, কারণ এই কাজ করার জন্য জাভাস্ক্রিপ্ট এর কোন অন্তর্নির্মিত মেথড নেই। +আসলে এটি খুব কমই প্রয়োজন হয়। রেফারেন্সে কপি করাই বেশিরভাগ সময় যথেষ্ট। + +কিন্তু আমরা যদি আসলেই এটি চাই তাহলে আমাদের নতুন একটি অবজেক্ট বানাতে হবে, ও মুল অবজেক্ট টির সম্পূর্ণ কাঠামো কে নকল করে এর সকল প্রপার্টির প্রিমিটিভ স্তরে প্রতিলিতি তৈরি করতে হবে। + +যেমন: + +```js run +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = {}; // নতুন খালি অবজেক্ট + +// এখন user অবজেক্ট এর সকল প্রপার্টি কে clone অবজেক্ট এ কপি করি +for (let key in user) { + clone[key] = user[key]; +} +*/!* + + +// এখন ক্লোন হচ্ছে একটি স্বাধীন অবজেক্ট যার কন্টেন্ট ইউজার এর সমান +clone.name = "Pete"; // ডাটা পরিবর্তন করলাম + +alert( user.name ); // মুল অবজেক্ট এ এখনো John +``` + +আমরা এর জন্য [Object.assign](mdn:js/Object/assign) মেথড টিও ব্যাবহার করতে পারি। + +এর সিনট্যাক্স হলো: + +```js +Object.assign(dest, [src1, src2, src3...]) +``` + +- প্রথম আর্গুমেন্ট `dest` হলো টার্গেট অবজেক্ট । +- বাকি আর্গুমেন্ট গুলো `src1, ..., srcN` (যতো প্রয়োজন দেয়া যাবে) হলো মুল অবজেক্ট। +- এটি মুল অবজেক্ট এর সকল প্রপার্টি `src1, ..., srcN` টার্গেট `dest` এ কপি করে। অন্য কথায়, দ্বিতীয় আর্গুমেন্ট থেকে বাকি সকল আর্গুমেন্ট এর প্রপার্টি গুলো প্রথম অবজেক্ট এ কপি হয়। +- এই কল টি `dest` কে রিটার্ন করে। + +আমরা এটি ব্যাবহার করে একাধিক অবজেক্টকে একটি অবজেক্ট এ মিলিত করতে পারি: +```js +let user = { name: "John" }; + +let permissions1 = { canView: true }; +let permissions2 = { canEdit: true }; + +*!* +// permissions1 ও permissions2 এর সকল প্রপার্টি কে user এ কপি করে +Object.assign(user, permissions1, permissions2); +*/!* + +// এখন user = { name: "John", canView: true, canEdit: true } +``` + +কপি করা প্রপার্টি যদি ইতিমধ্যেই থেকে থাকে থাকলে এটি ওভাররাইট হয়ে যাবে: + +```js run +let user = { name: "John" }; + +Object.assign(user, { name: "Pete" }); + +alert(user.name); // এখন user = { name: "Pete" } +``` + +আমরা `for..in` এর জায়গায় `Object.assign` ব্যাবহার করে সাধারণ ক্লোনিং করতে পারি : + +```js +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = Object.assign({}, user); +*/!* +``` + +এটি `user` এর সকল প্রপার্টি কে খালি অবজেক্ট এ কপি করে তাকে রিটার্ন করে । + +## অভ্যন্তরীণ ক্লোনিং (Nested cloning) + +এতক্ষণ পর্যন্ত আমরা ধরে নিয়েছিলাম যে `user` এর সকল প্রপার্টি ই প্রিমিটিভ । কিন্তু প্রপার্টি গুলো তো অন্যান্য অবজেক্ট এর রেফারেন্স ও হতে পারে । সেক্ষেত্রে আমরা কি করবো? + +যেমন: +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +alert( user.sizes.height ); // 182 +``` + +এখন এটি `clone.sizes = user.sizes` কে কপি করার জন্য যথেষ্ট নয়, কারণ `user.sizes` হলো একটি অবজেক্ট, এটি রেফারেন্সের মাধ্যমে কপি হবে। সুতরাং `clone` ও `user` একই size শেয়ার করবে: + +এমন: + +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +let clone = Object.assign({}, user); + +alert( user.sizes === clone.sizes ); // true, একই অবজেক্ট + +// user এবং clone size কে শেয়ার করে +user.sizes.width++; // একটি জায়গা থেকে প্রপার্টি পরিবর্তন +alert(clone.sizes.width); // 51, অন্য জায়গায় রেসাল্ট দেখা +``` + +এটি সমাধান করার জন্য আমাদের একটি ক্লোনিং লুপ ব্যাবহার করা লাগবে যা `user[key]` এর প্রত্যেক মান কে পরীক্ষা করবে, এবং যদি এটি অবজেক্ট হয়, তাহলে এর স্ট্রাকচার কেও কপি করবে। একে বলে "ডিপ ক্লোনিং"। + +আমরা রিকার্সন ব্যাবহার করে এটি তৈরি করতে পারি অথবা ইতিমধ্যেই বাস্তবায়িত একটি ব্যাবহার করতে পারি, যেমন [lodash](https://lodash.com) এর [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) ফাংশন। + +## সংক্ষিপ্ত + +অবজেক্ট গুলো রেফারেন্স এর মাধ্যমে কপি হয়। অন্য কথায়, একটি ভেরিয়েবল অবজেক্ট এর মান সংরক্ষণ করে না , বরং একটি রেফারেন্স (মেমোরি এড্রেস) সংরক্ষণ করে। সুতরাং এই ধরনের ভেরিয়েবল কে কপি করলে অবজেক্ট কপি হয় না বরং রেফারেন্স কপি হয়। + +কপি করা রেফারেন্সে এর মাধ্যমে করে সকল কাজ (যেমন প্রপার্টি যোগ করা/মোছা) একই অবজেক্ট এ সম্পাদিত হয়। + +একটি "বাস্তব কপি" (ক্লোন) তৈরি করতে আমরা ব্যাবহার করতে পারি `Object.assign` যাকে "শ্যালো কপি"(অভ্যন্তরীণ অবজেক্ট রেফারেন্সের মাধ্যমে কপি হয়) বলা হয় অথবা আমরা ব্যাবহার করতে পারি [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) এর মত "ডিপ ক্লোনিং" ফাংশন। diff --git a/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg b/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg new file mode 100644 index 000000000..a5f057178 --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg @@ -0,0 +1 @@ +username diff --git a/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg b/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg new file mode 100644 index 000000000..18f80c2f2 --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg @@ -0,0 +1,2 @@ +useradminname + diff --git a/1-js/04-object-basics/02-object-copy/variable-copy-value.svg b/1-js/04-object-basics/02-object-copy/variable-copy-value.svg new file mode 100644 index 000000000..7435bb13f --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/variable-copy-value.svg @@ -0,0 +1,3 @@ + +"Hello!"message"Hello!"phrase + diff --git a/1-js/04-object-basics/05-constructor-new/1-two-functions-one-object/solution.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/1-two-functions-one-object/solution.md rename to 1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md diff --git a/1-js/04-object-basics/05-constructor-new/1-two-functions-one-object/task.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/1-two-functions-one-object/task.md rename to 1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md diff --git a/1-js/04-object-basics/05-constructor-new/2-calculator-constructor/_js.view/solution.js b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/2-calculator-constructor/_js.view/solution.js rename to 1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js diff --git a/1-js/04-object-basics/05-constructor-new/2-calculator-constructor/_js.view/test.js b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/test.js similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/2-calculator-constructor/_js.view/test.js rename to 1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/test.js diff --git a/1-js/04-object-basics/05-constructor-new/2-calculator-constructor/solution.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/2-calculator-constructor/solution.md rename to 1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md diff --git a/1-js/04-object-basics/05-constructor-new/2-calculator-constructor/task.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/2-calculator-constructor/task.md rename to 1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md diff --git a/1-js/04-object-basics/05-constructor-new/3-accumulator/_js.view/solution.js b/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/3-accumulator/_js.view/solution.js rename to 1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js diff --git a/1-js/04-object-basics/05-constructor-new/3-accumulator/_js.view/test.js b/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/test.js similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/3-accumulator/_js.view/test.js rename to 1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/test.js diff --git a/1-js/04-object-basics/05-constructor-new/3-accumulator/solution.md b/1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/3-accumulator/solution.md rename to 1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md diff --git a/1-js/04-object-basics/05-constructor-new/3-accumulator/task.md b/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/3-accumulator/task.md rename to 1-js/04-object-basics/06-constructor-new/3-accumulator/task.md diff --git a/1-js/04-object-basics/05-constructor-new/article.md b/1-js/04-object-basics/06-constructor-new/article.md similarity index 100% rename from 1-js/04-object-basics/05-constructor-new/article.md rename to 1-js/04-object-basics/06-constructor-new/article.md diff --git a/1-js/04-object-basics/07-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md similarity index 100% rename from 1-js/04-object-basics/07-symbol/article.md rename to 1-js/04-object-basics/08-symbol/article.md diff --git a/1-js/04-object-basics/08-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md similarity index 100% rename from 1-js/04-object-basics/08-object-toprimitive/article.md rename to 1-js/04-object-basics/09-object-toprimitive/article.md