Chapter 20: JavaScript Data Access
20-1: Data তুই পালাবি কোথায়
ডাটা একেক সময় একেক স্টাইলে আসবে। কখনো ভেরিয়েবল, কখনো অবজেক্ট, কখনো অ্যারে, কখনো অবজেক্টের মধ্যে অ্যারে, আবার কখনো অ্যারের মধ্যে অবজেক্ট, এমন অনেক অনেক সিস্টেমে ডাটা আসতে পারে। কোনো সিস্টেম থেকে কীভাবে ডাটা বের করে নিয়ে আসতে হবে, সেটা নিয়ে তোর কিছু ধারণা থাকার দরকার আছে।
Array of Objects
একটা অ্যারের মধ্যে যখন অনেকগুলা অবজেক্ট থাকে, তখন কোনো একটা অবজেক্ট থেকে কীভাবে ডাটা বের করবি। বিষয়টা খুবই সিম্পল। জাস্ট অ্যারে থেকে উপাদান কীভাবে নিবি, হয় লুপ করে একটা একটা করে উপাদান পাবি, তারপর সেগুলা দিয়ে কিছু করবি।
আর যদি কোনো একটা স্পেসিফিক আইটেম, সেটা হতে পারে প্রথম যে অবজেক্ট আছে, সেটার মধ্যে এড্রেস পেতে চাস, তাহলে অবজেক্ট যেহেতু অ্যারের মধ্যে আছে, তাই অ্যারের ইনডেক্স দিয়ে প্রথম উপদানটা এক্সেস করবি। তাই data[0] তোকে একটা অবজেক্ট দিবে। এরপর অবজেক্ট পেয়ে যাওয়ার পর ডট নোটেশন দিয়ে সেটার প্রোপার্টি এক্সেস করে ফেলবি। আর কিছু না।
const data = [{id: 1, name: 'abul', address: 'kochu khet'}, { }, { }, { }];
console.log(data[0]);
console.log(data[0].address);
Output:
{ id: 1, name: 'abul', address: 'kochu khet' }
kochu khetঅবজেক্টের মধ্যে অ্যারে
কিছু সময় দেখা যায়, একটা অবজেক্টের মধ্যে অনেকগুলা প্রোপার্টি দিয়ে দিছে, তার মধ্যে একটা প্রোপার্টি হয়তো data নামে আছে। তাই প্রথমে ডট নোটেশন দিয়ে সেই অ্যারেকে এক্সেস করে নিতে হবে। তারপর সেটা একটা অ্যারে হিসেবে পাবি। আর একবার অ্যারে পেয়ে গেলে ওপরের সিস্টেমে সেটার ইনডেক্স তোকে অবজেক্ট দিবে। ধর, তুই সেকেন্ড পজিশন বা 1 ইনডেক্সের অবজেক্টের দাম জানতে চাস, তাহলে ইনডেক্সের পর ডট নোটেশন দিয়ে প্রোপার্টি এক্সেস করে ফেলতে পারবি।
const products = {
count: 5000,
data: [
{ id: 1, name: "lenovo laptop", price: 65000 },
{ id: 2, name: "macbook", price: 165000 },
],
};
console.log(products.data[1].price);
Output: 165000;মাল্টি লেভেল নেস্টেড অবজেক্ট
মাঝে মাঝে অবজেক্টের ভিতরে অবজেক্ট, তার ভিতরে অবজেক্ট, তার ভিতরে অবজেক্ট— এমন একটার পর একটা লেয়ার থাকে। এইগুলা একটু বুঝে বুঝে একটার পর একটা বের করতে হয়। বের করতে একটু উল্টাপাল্টা করলে এরর হয়ে যায়।
const user = {
id: 5001,
name: 'shoriful raj',
address: {
street: {
second: 'poribag er goli'
},
city: 'Dhaka'
}
};
console.log(user.address.street.second);
Output: poribag er goliএইভাবে একটার পর একটা প্রোপার্টি বা অনেক সময় একটার পর একটা মেথড কল করাকে চেইনিং বলে। কারণ, এইটা দেখতে অনেকটা চেইনের মতো।
Practice:
তোর কাছে একটা array আছে [{id: 1, name: 'mukta', address: 'mirpur'}]। তুই address প্রিন্ট করতে চাস, তাহলে প্রোগ্রাম লিখে দেখ, কীভাবে address প্রিন্ট করতে হয়।
একটা প্রোগ্রাম লিখ, যেখানে const library = { name: 'city library', books: [{ id: 1, title: 'JavaScript Basics', price: 300}, { id: 2, title: 'Python Essentials', price: 500}] } আছে। এবার books array থেকে দ্বিতীয় বইয়ের price বের কর।
তোর কাছে const school = { name: 'Green High', students: [{ id: 1, name: 'Samiha'}, { id: 2, name: 'Kamal'}] } নামক একটি অবজেক্ট আছে। এবার students array থেকে প্রথম শিক্ষার্থীর name প্রিন্ট করতে তুই একটা প্রোগ্রাম লিখ।
ধর, একটা অবজেক্ট আছে, const shop = { items: [{ name: 'pen', stock: 100}, { name: 'notebook', stock: 50 }] }। items array থেকে notebook-এর stock বের করতে চাস, তাহলে একটা প্রোগ্রাম লিখে বের কর।
const movie = { title: 'Inception', director: { name: 'Nolan', age: 50 }, rating: 8.8 } নামক অবজেক্টে তুই director-এর name প্রিন্ট করতে চাস। কীভাবে করবি?
একটা প্রোগ্রাম লিখ, যেখানে const game = { name: 'football', players: [{ id: 1, name: 'Lionel Messi'}, { id: 2, name: 'Cristiano Ronaldo'}] } অবজেক্টে প্রথম player-এর name প্রিন্ট করবে।
ধর, const vehicle = { type: 'car', features: { color: 'red', brand: { name: 'Toyota', model: 'Corolla' } } }। brand-এর name প্রিন্ট করতে তুই একটা প্রোগ্রাম লিখ।
20-2: নালিশ দিচ্ছে Nullish Coalescing
তোর যদি মোবাইল ফোন ছিনতাই হয়ে যায়, তাইলে তুই কি সেই ফোনের ভিতরে যেইসব ছবি আছে, সেগুলা পাবি? না, পাবি না। কারণ, মোবাইল ফোন থেকে ছবি পেতে হলে মোবাইল ফোন থাকতে হবে। তাই মোবাইল না থাকার পরেও ছবি পাইতেছি না কেন, সেটা নিয়ে নালিশ করে কোনো লাভ হবে না।
যখন কোনো একটা অবজেক্টে প্রোপার্টি থাকে না, সেটাকে সে খুবই ভদ্রভাবে undefined বলে দেয়। কিন্তু সেই undefined হয়ে যাওয়া জিনিসটাকে তুই যদি আবার অবজেক্ট হিসেবে মনে করে সেটা থেকে আরও কিছু একটা বের করে নিয়ে আসতে চাস, তখন হয়ে যায় বিপত্তি। কারণ, যেটা নাই, সেটার ভিতরে থেকে কিছু পাবে কীভাবে? যেমনটা মোবাইল না থাকলে সেটার ভিতর থেকে ছবি নিয়ে আসতে পারবি না। একইভাবে কোনো একটা প্রোপার্টি না থাকলে সেটার ভিতর থেকে অন্য কিছু নিয়ে আসতে পারবি না।
নিচে সিম্পল একটা user অবজেক্ট আছে, সেটার মধ্যে name নামে একটা প্রোপার্টি আছে। আমরা সিম্পলভাবে এই name প্রোপার্টির মান পেতেই পারি। আবার একইভাবে যদি profile প্রোপার্টির মান এক্সেস করতে যাবি। সেটার মান দিবে undefined। কারণ, user অবজেক্টে profile নামে কোনো প্রোপার্টি নাই। এই যে প্রোফাইল প্রোপার্টি নাই, তারপরেও জোর করে এই নাই জিনিসের মধ্যে email খুঁজতে গেলে এরর দিয়ে বসবে।
const user = { name: 'Jakkas' };
console.log(user.name);
console.log(user.profile);
console.log(user.profile.email);
Output:
Jakkas
undefined
Cannot read properties of undefined (reading 'email')এই এরর ম্যাসেজ থেকে স্পষ্ট বুঝা যাচ্ছে না। সেখানে বলতেছে, Cannot read properties of undefined অর্থাৎ undefined-এর কোনো প্রোপার্টি পড়া যাচ্ছে না। হয়তো এরর ম্যাসেজটা এমন হলে বুঝতে সুবিধা হতো– Cannot read email of profile because profile is undefined।
Optional Chaining
কোনো একটা প্রোপার্টি undefined হয়ে যাওয়ার পর তার ভিতরের প্রোপার্টি পড়তে গেলে যে এরর দেয়, সেটা থেকে রক্ষা পেতে চাইলে একটা অপশনাল চেইনিং ইউজ করতে পারবি। সেটা আর কিছুই না। জাস্ট প্রোপার্টির নাম লেখার আগে যে ডট চিহ্ন দিচ্ছস, সেটার আগে একটা প্রশ্নবোধক চিহ্ন দিয়ে দিবি। তাহলে জাভাস্ক্রিপ্ট বুঝে ফেলবে, এই প্রোপার্টি থাকতেও পারে আবার নাও থাকতে পারে। থাকলে সামনে এগুবে, না থাকলে সেখানেই স্টপ হয়ে যাবে। তখন আর এরর দিবে না।
নিচে নতুন আরেকটা user অবজেক্ট আছে। সেটাতে name প্রোপার্টির পাশাপাশি address প্রোপার্টি আছে। সেই address প্রোপার্টির মান আরেকটা অবজেক্ট। সেই অবজেক্টের মধ্যে city name আরেকটা প্রোপার্টি আছে। তাহলে স্বাভাবিকভাবেই আমরা user.address.city-এর মান পেয়ে যাব কোনো এরর ছাড়াই। আর এর মধ্যে অপশনাল chaining ইউজ করলে কোনো সমস্যা হবে না। কারণ, মান থাকলে অপশনাল চেইন কিছুই করবে না, সরাসরি মান দিয়ে দিবে।
অন্যদিকে user অবজেক্টের মধ্যে profile নাই। আর প্রোফাইল না থাকার কারণে সেটার ভিতরে email থাকার প্রশ্নই আসে না এবং সেটা খুঁজতে গেলে এরর দিয়ে দিবে। তবে আমরা যদি অপশনাল চেইনিং ইউজ করি, তাহলে আর এরর দিবে না। ভদ্রভাবে undefined বলে দিবে। এইটাই অপশনাল চেইনিংয়ের মজা।
const user = { name: "Rahim", address: { city: "Dhaka" } };
console.log(user?.address?.city);
console.log(user?.profile?.email);
Output: Dhaka;
undefined;Nullish Coalescing (??)
নালিশ করার জন্য দুইটা প্রশ্নবোধক চিহ্ন দিয়ে দিতে হবে। তখন Nullish Coalescing হবে। এই ডাবল প্রশ্ন ?? হচ্ছে এমন একটা অপারেটর, যা null বা undefined হলে একটা default value রিটার্ন করে।
Nullish বলতে বুঝায় null বা undefined হতে পারে। এইটা খুবই স্পেসিফিক একটা জিনিস।
আর Coalescing একটা দাঁত ভেঙে ফেলার মতো শব্দ। এইটার মানে হচ্ছে একসাথ করা এবং একসঙ্গে মিলিয়ে কিছু একটা করা। এইখানে প্রোগ্রামিংয়ে nullish coalescing দিয়ে সঠিক মান থাকলে সেটাকে দিচ্ছে, আর null বা undefined হলে ডিফল্ট মান দিচ্ছে, সেটাকে বুঝাচ্ছে।
তুই ভাবতে পারস, এইটা তো আমি if-else দিয়ে করতে পারি। পারবি, যদি স্পেসিফিকলি null আর undefined চেক করে মান সেট করস। তবে কখনো falsy কোনো মান যেমন, 0, "", বা false হলে ডিফল্ট রিটার্ন করলে সেটা ভুল হবে। কারণ 0, "", বা false এইগুলা ডাটায় থাকতে পারে। তাই Nullish Coalescing অনেক বেশি প্রাক্টিক্যালভাবে শুধু null বা undefined-কে চেক করে ডিফল্ট মান দেয়।
একইভাবে তুই শর্টকাটে OR অপারেটর ( || ) দিয়ে যখন userAge চেক করে ডিফল্ট মান চেক করতে পারস, তবে এইখানেও সেইম প্রব্লেম, সব falsy ভ্যালুর জন্য ডিফল্ট মান ধরায় দিবে। অথচ 0, false বা এম্পটি স্ট্রিং ('') সঠিক মান হতে পারে। তখন কিন্তু মান 18 সেট করা ঠিক হবে না।
let userAge = 0;
let age = userAge || 18;
console.log(age);
Output: 18;Nullish Coalescing শুধু null বা undefined-এর জন্যই শুধু default ভ্যালু সেট করে, অন্য কোনো Falsy ভ্যালু থাকলে সেটাকে মান আছে বলে ধরে নেয়। যেমন:
const userAge = 0;
const age = userAge ?? 18;
console.log(age);
Output: 0;একইভাবে দেখতে পারস, null বা undefined হলে কী হবে।
const userName = null;
const name = userName ?? "Anonymous";
console.log(name);
Output: Anonymous;এখানে ?? নিশ্চিত করে যে, userName যদি null বা undefined হয়, তবেই "Anonymous" রিটার্ন করবে।
জোড়ায় জোড়ায় সেইফটি
Optional Chaining আর Nullish Coalescing একসাথে ইউজ করলে এরর খাওয়ার চান্স কমে যায়।
const user = {
name: 'Rahim',
address: { city: 'Dhaka' }
};
const city = user?.address?.city ?? "City not available";
console.log(city);
Output: Dhaka
const postalCode = user?.address?.postalCode ?? "Postal code not available";
console.log(postalCode);
Output: Postal code not availableএখানে user?.address?.postalCode চেক করছে যে, postalCode property আছে কি না। যদি না থাকে, তাহলে "Postal code not available" সেট করছে।
এইভাবেই Optional Chaining আর Nullish Coalescing তোর ডেটা অ্যাক্সেসের লাইফকে সহজ করে দেয়!
Practice:
let x = null;-এর ক্ষেত্রে x ??= 75 ব্যবহার করলে আউটপুট কী হবে?
একটা product অবজেক্টে stock নামের প্রোপার্টি নাই; Nullish Coalescing দিয়ে stock-এর ডিফল্ট মান 0 সেট কর।
productDetails অবজেক্টে discount ভেরিয়েবলের মান falsy কোনো কিছু হলে সেটার মান 10 সেট করার কোড লেখ।
Optional Chaining দিয়ে vehicle অবজেক্টে engine নামের প্রোপার্টি চেক কর এবং ডিফল্ট মান 'Engine info missing' যোগ কর।
Optional Chaining দিয়ে restaurant অবজেক্টে menu নামে প্রোপার্টি রিড কর এবং সেটা না থাকলে 'Menu not available' রিটার্ন কর।
profile অবজেক্টে social অবজেক্টে twitter নামের প্রোপার্টি চেক কর Optional Chaining দিয়ে। twitter না থাকলে 'Twitter handle not available' প্রিন্ট কর।
20-3: শর্টকাটে শর্ট সার্কিট
শর্টকাটে কাজ সারতে পারলে কষ্ট কে করে। এই জন্য ডাটা রিলেটেড বেশ কিছু শর্টকাট জাভাস্ক্রিপ্টে আছে। তার অনেকগুলা আমরা আগেই আলোচনা করে ফেলছি। তা-ও কিছুটা এখন রিভিশন হয়ে যাবে।
বড় হওয়া সহজ না
কোনো একটা সংখ্যাওয়ালা ভেরিয়েবলের মান এক বাড়ানোর জন্য তুই ভেরিয়েবলের নাম, এরপর দুইবার প্লাস চিহ্ন দিতে পারস। তাহলে ইউজ করতে পারস। এইটা তুই আগে থেকেই জানস। তারপরেও নিচের কোড দেখ। দেখবি b-এর মান 5 আউটপুট দিচ্ছে। যদিও তুই a-এর পর দুইটা প্লাস চিহ্ন ঠিকই দিছস।
let a = 5;
let b = a++;
console.log(b);
Output: 5;কারণ, let b = a++; দিলে আগে আগে a-র বর্তমান মান b-তে সেট হয়, তারপর a-এর মান 1 বাড়ে। তাই b মান 5 হয়ে গেছে।
এইটার সমাধান হচ্ছে pre-increment অর্থাৎ আগে ইনক্রিমেন্ট হবে।
let a = 5;
let b = ++a;
console.log(b);
Output: 6;এইবার let b = ++a; লেখার কারণে আগে a-এর মান 1 বাড়ে। তারপর b-তে সেট হয়। তাই এইবার b মান 6 হবে।
সেইম জিনিসটা কিন্তু Decrement অর্থাৎ দুইটা মাইনাস চিহ্নের ক্ষেত্রেও হয়। সেখানেও Post-Decrement, আবার Pre-Decrement আছে। অর্থাৎ ভেরিয়েবল নামের আগে কমানো বা নামের পরে কমানোর বিষয় আছে এবং এই জিনিসটাও সেইমভাবে কাজ করে।
অ্যাসাইনমেন্ট শর্টকাট
যদি কোনো ভেরিয়েবলের সাথে অন্য কোনো সংখ্যা বা অন্য কোনো ভেরিয়েবলের যোগ, বিয়োগ, গুণ, ভাগ এবং ভাগশেষ করে সেটার রেজাল্ট সেই ভেরিয়েবলে সেট করছ, তাহলে +=, -=, *=, /=, %= এই শর্টকাটগুলা ইউজ করতে পারবি। নিচের মতো করে—
১. apples = apples + 5 না লিখে শর্টকাটে apples += 5; লিখতে পারবি
২. oranges = oranges - 8 না লিখে শর্টকাটে oranges -= 8; লিখতে পারবি
৩. bananas = bananas _ 3 না লিখে শর্টকাটে bananas _= 3; লিখতে পারবি
৪. grapes = grapes / 4 না লিখে শর্টকাটে grapes /= 4; লিখতে পারবি
৫. mangoes = mangoes % 3 না লিখে শর্টকাটে mangoes %= 3; লিখতে পারবি
Logical AND Assign (&&=)
&&= হলো একধরনের শর্টকাট অপারেটর। একে বলে Logical AND Assignment Operator। এটা বলে, ভেরিয়েবল যদি সত্যি (truthy) হয়, তাহলে ভ্যালু চেইঞ্জ করে দিবি। আর ভেরিয়েবল যদি X মিথ্যা (falsy) কিছু হয় (যেমন 0, null, undefined, false, NaN, ""), তাহলে কিছুই করবে না।
let mango = 10;
mango &&= 5;
console.log(mango);
Output: 5;কারণ, mango ভেরিয়েবল truthy ছিল, তাই এটা 5 হয়ে গেল।
আর যদি tomato ভেরিয়েবল falsy হয়—
let tomato = 0;
tomato &&= 5;
console.log(tomato);
Output: 0;কারণ, tomato falsy ছিল, তাই এটা unchanged থেকে গেল।
Logical OR Assign(||=)
অন্যদিকে ||= হলো Logical OR Assignment Operator। এটা বলে, ভেরিয়েবল যদি মিথ্যা (falsy) হয়, তাহলে ভেরিয়েবলের ভ্যালু চেইঞ্জ করে দিবি। আর ভেরিয়েবল যদি truthy কিছু হয়, তাহলে কিছুই করবে না।
let money = 0;
money ||= 5;
console.log(money);
Output: 5;কারণ, money ভেরিয়েবল falsy ছিল, তাই এটাকে 5 করে দিল।
আর যদি price ভেরিয়েবল truthy হয়—
let price = 10;
price ||= 5;
console.log(price);
Output: 10;কারণ, price ভেরিয়েবল truthy ছিল, তাই এটা unchanged থেকে গেল।
Practice:
একটি ভেরিয়েবল a-কে 59 সেট করে এর মান একবার post-increment এবং একবার pre-increment করে দেখ, আউটপুট কী হয়।
oranges ভেরিয়েবলের প্রাথমিক মান 100 । oranges-কে 15 দিয়ে ভাগ কর এবং এই শর্টকাট অপারেটর ব্যবহার কর।
একটি ভেরিয়েবল mango = 20। mango &&= 10 ব্যবহার করলে ভেরিয়েবলের নতুন মান কী হবে, কেন?
bananas ভেরিয়েবলের মান 50। এর সাথে 4 গুণ করে সেই মানটি নিজেই ধরে রাখতে হলে কোন শর্টকাট অপারেটর ব্যবহার করবি?
একটি truthy ভেরিয়েবল grapes = 19 দিয়ে ||= অপারেটর ব্যবহার করলে এর মান কী হবে এবং কেন?
apples = apples - 10 এই স্টেটমেন্টটি শর্টকাট অপারেটর ব্যবহার করে লেখ।
let price = undefined; এবং price ||= 90 ব্যবহার করে প্রমাণ কর যে, price-এর মান পরিবর্তিত হয়েছে।
একটি falsy ভেরিয়েবল tomato = 0। এতে mango &&= 5 ব্যবহার করলে আউটপুট কী হবে এবং কেন?
apples = 15 হলে, apples %= 6 ব্যবহার করলে আউটপুট কত হবে এবং সেটা কেন তত হবে?
