Skip to content

Commit b2fdfbf

Browse files
author
Md. Jamal Uddin
authoredOct 24, 2020
Merge pull request #92 from tahnoonn/master
Object references and copying
2 parents d8387fe + 1935ff0 commit b2fdfbf

File tree

17 files changed

+247
-0
lines changed

17 files changed

+247
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# অবজেক্ট রেফারেন্স এবং কপি করা
2+
3+
অবজেক্ট এবং প্রিমিটিভ দের মধ্যে অন্যতম পার্থক্য হলো যে অবজেক্ট গুলি কপি ও সংরখ্যন হয় রেফারেন্স এর মাধ্যমে, যেখানে প্রিমিটিভ মানঃ স্ট্রিং, বুলিয়ান, ইত্যাদি -- যেগুলো সবসময় "সম্পুর্ন মান" হিসেবে কপি হয়।
4+
5+
একটি মান কপি করলে কি হয় তা একটু গভীরভাবে দেখলেই আমরা এটি আরো ভালোভাবে বুঝতে পারব।
6+
7+
স্ট্রিং এর মত একটি প্রিমিটিভ নিয়েই শুরু করা যাক।
8+
9+
এখানে আমরা `message` এর একটি কপি কে `phrase` এ রাখলামঃ
10+
11+
```js
12+
let message = "Hello!";
13+
let phrase = message;
14+
```
15+
16+
এর ফলে আমরা দুটি স্বাধীন ভেরিয়েবল আছে, প্রতিটি "হেলো" স্ট্রিংটি সংরক্ষণ করছে ।
17+
18+
![](variable-copy-value.svg)
19+
20+
খুব স্বাবাভিক ই মনে হচ্ছে, তাই না?
21+
22+
অবজেক্ট রা এমন নয়।
23+
24+
**একটি অবজেক্ট এর জন্য নির্ধারিত ভেরিয়েবল সেই অবজেক্ট কে সংরক্ষণ করে না, বরং এর ঠিকানা সংরক্ষণ করে, অন্য কথায় এটির একটি "রেফারেন্স"।**
25+
26+
এমন একটি ভেরিয়েবল এর উদাহরণ দেখা যাকঃ
27+
28+
```js
29+
let user = {
30+
name: "John"
31+
};
32+
```
33+
34+
এটি স্মৃতি তে কিভাবে সংরক্ষণ করা হয় তা নিচের ছবিতে দেখানো হলোঃ
35+
36+
![](variable-contains-reference.svg)
37+
38+
অবজেক্ট টি স্মৃতির কোথাও সংরক্ষণ করা আছে (ডানে), আর `user` ভেরিয়েবল এর কাছে এর একটি রেফারেন্স আছে।
39+
40+
আমরা `user` এর মতো অবজেক্ট কে একটি কাগজের টুকরো হিসেবে ভাবতে পারি, যাতে ঠিকানা লেখা আছে ।
41+
42+
যখন আমরা অবজেক্ট এর উপরে কোন কাজ করি, যেমন `user.name` প্রপার্টি কে নেয়া, জাভাস্ক্রিপ্ট ইঞ্জিন ঠিকানা থেকে অবজেক্ট টি বের তার উপরে কাজ টি সম্পাদন করে ।
43+
44+
এটি গুরুতপুর্ন কারণ
45+
46+
**যখন কোনও বস্তুর ভেরিয়েবল কপি করা হয় - রেফারেন্সটি কপি হয়, বস্তুটি নকল হয় না ।**
47+
48+
যেমন :
49+
50+
```js no-beautify
51+
let user = { name: "John" };
52+
53+
let admin = user; // রেফারেন্স কপি হলো
54+
```
55+
56+
এখন আমাদের দুটি ভেরিয়েবল রয়েছে, প্রত্যেকেই একই বস্তুর রেফারেন্স:
57+
58+
![](variable-copy-reference.svg)
59+
60+
আমরা দেখতে পাচ্ছি যে, অবজেক্ট একটাই আছে কিন্তু এখন একে দুটি ভেরিয়েবল রেফারেন্স করছে ।
61+
62+
আমরা এই দুটি ভেরিয়েবল এর যেকোনো টি ব্যাবহার করে অবজেক্ট টি এক্সেস করতে পারি ও এর ভেতরের কন্টেন্ট বা ডেটা গুলি পরিবর্তন করতে পারি।
63+
64+
```js run
65+
let user = { name: 'John' };
66+
67+
let admin = user;
68+
69+
*!*
70+
admin.name = 'Pete'; // এডমিন রেফারেন্সের এর মাধ্যমে পরিবর্তন হলো
71+
*/!*
72+
73+
alert(*!*user.name*/!*); // 'Pete', পরিবর্তন টি "user" রেফারেন্স থেকে দেখা যাচ্ছে
74+
```
75+
76+
77+
উপরের উদাহরণটি প্রমাণ করে যে এখানে কেবল একটি অবজেক্ট রয়েছে। যেন আমাদের একি কক্ষের দুটি চাবি আছে আর আমরা একটি চাবি (`admin`) দিয়ে কক্ষে প্রবেশ করেছি। পরে অন্যটি (`user`) দিয়ে কক্ষের ভেতরে দেখেছি।
78+
79+
## রেফারেন্স এর মাধ্যমে তুলনা
80+
81+
যদি দুটি অবজেক্ট একই বস্তু হয়, শুধুমাত্র তাহলেই তারা "ইকুয়াল"।
82+
83+
যেমন, এখানে `a` এবং `b` একই অবজেক্ট কে রেফারেন্স করে, সুতরাং তারা ইকুয়াল:
84+
85+
```js run
86+
let a = {};
87+
let b = a; // রেফারেন্স কপি হোলো
88+
89+
alert( a == b ); // true, দুটি অবজেক্ট ই সমান
90+
alert( a === b ); // true
91+
```
92+
93+
আর এখানে দুটি অবজেক্ট সমান নয়, যদিও তারা দেখতে একই (দুজনই খালি) :
94+
95+
```js run
96+
let a = {};
97+
let b = {}; // দুটি স্বাধীন অবজেক্ট
98+
99+
alert( a == b ); // false
100+
```
101+
102+
`obj1 > obj2` এর মত তুলনা এর জন্য অথবা কোন প্রিমিটিভ এর সাথে তুলনা করার জন্য `obj == 5`, অবজেক্ট কে প্রিমিটিভ এ রূপান্তর করা হয়। অবজেক্ট গুলোকে কিভাবে তুলনা করা হয় তা সম্পর্কে আমরা শিগ্রই জানব, কিন্তু সত্যি বলতে এই ধরনের তুলনা খুব কমই প্রয়োজন হয়, সাধারণত এগুলি ভুলক্রমে চলে আসে।
103+
104+
## ক্লোন করা ও মিলিত করা, Object.assign
105+
106+
তো আমরা জানলাম অবজেক্ট ভেরিএবল কে কপি করলে তা শুধু একটি নতুন রেফারেন্স তৈরি করে।
107+
108+
কিন্তু আমাদের যদি অবজেক্ট এর স্বাধীন নকল বা ক্লোন তৈরি করতে হয় তাহলে আমরা কি করব?
109+
110+
তাও সম্ভব কিন্তু একটু কঠিন, কারণ এই কাজ করার জন্য জাভাস্ক্রিপ্ট এর কোন অন্তর্নির্মিত মেথড নেই।
111+
আসলে এটি খুব কমই প্রয়োজন হয়। রেফারেন্সে কপি করাই বেশিরভাগ সময় যথেষ্ট।
112+
113+
কিন্তু আমরা যদি আসলেই এটি চাই তাহলে আমাদের নতুন একটি অবজেক্ট বানাতে হবে, ও মুল অবজেক্ট টির সম্পূর্ণ কাঠামো কে নকল করে এর সকল প্রপার্টির প্রিমিটিভ স্তরে প্রতিলিতি তৈরি করতে হবে।
114+
115+
যেমন:
116+
117+
```js run
118+
let user = {
119+
name: "John",
120+
age: 30
121+
};
122+
123+
*!*
124+
let clone = {}; // নতুন খালি অবজেক্ট
125+
126+
// এখন user অবজেক্ট এর সকল প্রপার্টি কে clone অবজেক্ট এ কপি করি
127+
for (let key in user) {
128+
clone[key] = user[key];
129+
}
130+
*/!*
131+
132+
133+
// এখন ক্লোন হচ্ছে একটি স্বাধীন অবজেক্ট যার কন্টেন্ট ইউজার এর সমান
134+
clone.name = "Pete"; // ডাটা পরিবর্তন করলাম
135+
136+
alert( user.name ); // মুল অবজেক্ট এ এখনো John
137+
```
138+
139+
আমরা এর জন্য [Object.assign](mdn:js/Object/assign) মেথড টিও ব্যাবহার করতে পারি।
140+
141+
এর সিনট্যাক্স হলো:
142+
143+
```js
144+
Object.assign(dest, [src1, src2, src3...])
145+
```
146+
147+
- প্রথম আর্গুমেন্ট `dest` হলো টার্গেট অবজেক্ট ।
148+
- বাকি আর্গুমেন্ট গুলো `src1, ..., srcN` (যতো প্রয়োজন দেয়া যাবে) হলো মুল অবজেক্ট।
149+
- এটি মুল অবজেক্ট এর সকল প্রপার্টি `src1, ..., srcN` টার্গেট `dest` এ কপি করে। অন্য কথায়, দ্বিতীয় আর্গুমেন্ট থেকে বাকি সকল আর্গুমেন্ট এর প্রপার্টি গুলো প্রথম অবজেক্ট এ কপি হয়।
150+
- এই কল টি `dest` কে রিটার্ন করে।
151+
152+
আমরা এটি ব্যাবহার করে একাধিক অবজেক্টকে একটি অবজেক্ট এ মিলিত করতে পারি:
153+
```js
154+
let user = { name: "John" };
155+
156+
let permissions1 = { canView: true };
157+
let permissions2 = { canEdit: true };
158+
159+
*!*
160+
// permissions1 ও permissions2 এর সকল প্রপার্টি কে user এ কপি করে
161+
Object.assign(user, permissions1, permissions2);
162+
*/!*
163+
164+
// এখন user = { name: "John", canView: true, canEdit: true }
165+
```
166+
167+
কপি করা প্রপার্টি যদি ইতিমধ্যেই থেকে থাকে থাকলে এটি ওভাররাইট হয়ে যাবে:
168+
169+
```js run
170+
let user = { name: "John" };
171+
172+
Object.assign(user, { name: "Pete" });
173+
174+
alert(user.name); // এখন user = { name: "Pete" }
175+
```
176+
177+
আমরা `for..in` এর জায়গায় `Object.assign` ব্যাবহার করে সাধারণ ক্লোনিং করতে পারি :
178+
179+
```js
180+
let user = {
181+
name: "John",
182+
age: 30
183+
};
184+
185+
*!*
186+
let clone = Object.assign({}, user);
187+
*/!*
188+
```
189+
190+
এটি `user` এর সকল প্রপার্টি কে খালি অবজেক্ট এ কপি করে তাকে রিটার্ন করে ।
191+
192+
## অভ্যন্তরীণ ক্লোনিং (Nested cloning)
193+
194+
এতক্ষণ পর্যন্ত আমরা ধরে নিয়েছিলাম যে `user` এর সকল প্রপার্টি ই প্রিমিটিভ । কিন্তু প্রপার্টি গুলো তো অন্যান্য অবজেক্ট এর রেফারেন্স ও হতে পারে । সেক্ষেত্রে আমরা কি করবো?
195+
196+
যেমন:
197+
```js run
198+
let user = {
199+
name: "John",
200+
sizes: {
201+
height: 182,
202+
width: 50
203+
}
204+
};
205+
206+
alert( user.sizes.height ); // 182
207+
```
208+
209+
এখন এটি `clone.sizes = user.sizes` কে কপি করার জন্য যথেষ্ট নয়, কারণ `user.sizes` হলো একটি অবজেক্ট, এটি রেফারেন্সের মাধ্যমে কপি হবে। সুতরাং `clone``user` একই size শেয়ার করবে:
210+
211+
এমন:
212+
213+
```js run
214+
let user = {
215+
name: "John",
216+
sizes: {
217+
height: 182,
218+
width: 50
219+
}
220+
};
221+
222+
let clone = Object.assign({}, user);
223+
224+
alert( user.sizes === clone.sizes ); // true, একই অবজেক্ট
225+
226+
// user এবং clone size কে শেয়ার করে
227+
user.sizes.width++; // একটি জায়গা থেকে প্রপার্টি পরিবর্তন
228+
alert(clone.sizes.width); // 51, অন্য জায়গায় রেসাল্ট দেখা
229+
```
230+
231+
এটি সমাধান করার জন্য আমাদের একটি ক্লোনিং লুপ ব্যাবহার করা লাগবে যা `user[key]` এর প্রত্যেক মান কে পরীক্ষা করবে, এবং যদি এটি অবজেক্ট হয়, তাহলে এর স্ট্রাকচার কেও কপি করবে। একে বলে "ডিপ ক্লোনিং"।
232+
233+
আমরা রিকার্সন ব্যাবহার করে এটি তৈরি করতে পারি অথবা ইতিমধ্যেই বাস্তবায়িত একটি ব্যাবহার করতে পারি, যেমন [lodash](https://lodash.com) এর [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) ফাংশন।
234+
235+
## সংক্ষিপ্ত
236+
237+
অবজেক্ট গুলো রেফারেন্স এর মাধ্যমে কপি হয়। অন্য কথায়, একটি ভেরিয়েবল অবজেক্ট এর মান সংরক্ষণ করে না , বরং একটি রেফারেন্স (মেমোরি এড্রেস) সংরক্ষণ করে। সুতরাং এই ধরনের ভেরিয়েবল কে কপি করলে অবজেক্ট কপি হয় না বরং রেফারেন্স কপি হয়।
238+
239+
কপি করা রেফারেন্সে এর মাধ্যমে করে সকল কাজ (যেমন প্রপার্টি যোগ করা/মোছা) একই অবজেক্ট এ সম্পাদিত হয়।
240+
241+
একটি "বাস্তব কপি" (ক্লোন) তৈরি করতে আমরা ব্যাবহার করতে পারি `Object.assign` যাকে "শ্যালো কপি"(অভ্যন্তরীণ অবজেক্ট রেফারেন্সের মাধ্যমে কপি হয়) বলা হয় অথবা আমরা ব্যাবহার করতে পারি [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) এর মত "ডিপ ক্লোনিং" ফাংশন।
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.