সব প্রোগ্রামিং ল্যাংগুয়েজের নিজস্ব ডেটা স্ট্রাকচার থাকে (যা ব্যবহার করে আপনি আপনার ডেটা বা তথ্য প্রোগ্রামে রাখতে পারেন) - তবে একেক প্রোগ্রামিং ভাষায় একেক রকম ডেটা স্ট্রাকচার দেখা যায়। এই আর্টিকেলে জাভাস্ক্রিপ্টের নিজস্ব ডেটা স্ট্রাকচার আর সেগুলোর বিভিন্ন প্রোপার্টি (বৈশিষ্ট্য) নিয়ে আলোচনা করা হয়েছে। এই নিজস্ব ডেটা স্ট্রাকচার গুলো ব্যবহার করে অন্যান্য ডেটা স্ট্রাকচার বানানো যাবে। যেখানে সম্ভব অন্য ভাষার সাথে পার্থক্য ও দেখানো হয়েছে।
ECMAScript স্ট্যান্ডার্ড অনুযায়ী ৬ ধরণের ডেটা স্ট্রাকচার আছেঃ
- সংখ্যা (Number)
- স্ট্রিং String
- বুলিয়ান Boolean (সত্যমিথ্যা)
- নাল Null
- অসংজ্ঞায়িত Undefined
- অবজেক্ট Object
নিচের আলোচনায় আমরা দেখব কিভাবে এগুলো ব্যবহার করে ডেটা রাখা যায় আর কীভাবে এগুলোর সাহায্যে আরও উন্নতমানের ডেটা স্ট্রাকচার তৈরি করা যায়।
মৌলিক/বেসিক মানসমূহ
অবজেক্ট ছাড়া বাকি সব টাইপের ডেটার মান তৈরি করার পর আর পরিবর্তন করা যায় না। বিশেষকরে, স্ট্রিং (যেখানে C ভাষায় স্ট্রিং এর মান পরিবর্তন করা যায়)। এই টাইপের ডেটাকে আমরা মৌলিক (primitive) টাইপের বলে থাকি। নিচে {{ anch("Strings") }} নিয়ে আলোচনায় এই বিষয়ে বিস্তারিত রয়েছে।
বুলিয়ান, নাল এবং অসংজ্ঞায়িত
শুধুমাত্র চারটি ধ্রুবক (কন্সট্যান্ট) দিয়েই এই ডেটাটাইপ গুলো প্রকাশ করা সম্ভবঃ বুলিয়ান প্রকাশ করার জন্য true
, false
, নাল প্রকাশের জন্য null
, আর অসংজ্ঞায়িত প্রকাশের জন্য undefined
। যেহেতু এগুলো কন্সট্যান্ট, এগুলো রিচ ডেটা রাখতে পারে না।
সংখ্যা
ECMAScript স্ট্যান্ডার্ড অনুযায়ী সংখ্যা প্রকাশ করার জন্য একটি মাত্র নাম্বার-টাইপ আছেঃ "double-precision 64-bit binary format IEEE 754 value"। অন্যান্য প্রোগ্রামিং ভাষার মত Integer (পূর্ণ সংখ্যা) প্রকাশ করার জন্য আলাদা কোন টাইপ নেই! ভগ্নাংশ রাখার পাশাপাশি জাভাস্ক্রিপ্টের এই একমাত্র নাম্বার টাইপ দিয়ে +Infinity
, -Infinity
, এবং NaN
(not-a-number) এই বিশেষ প্রতীক গুলোও প্রকাশ করা যায়।
যদিও একটি সংখ্যা সাধারণত শুধুমাত্র এর মানই প্রকাশ করে, জাভাস্ক্রিপ্টের কিছু বাইনারী অপারেটর আছে, যেগুলো দিয়ে বিট মাস্কিং পদ্ধতিতে একটি মাত্র সংখ্যা থেকেই অনেকগুলো বুলিয়ান মান প্রকাশ করা সম্ভব। তবে এরকম ব্যবহার নিরুৎসাহিত করা হয়, কারণ জাভাস্ক্রিপ্টে অন্য পদ্ধতিতে বুলিয়ান মান রাখা যায় (যেমন বুলিয়ান মানের array ব্যবহার করে অথবা অবজেক্টে প্রত্যেকটা বুলিয়ান মানের জন্য একটা করে প্রোপার্টি ব্যবহার করে)। বিট মাসস্কিং ব্যবহার করলে কোড দুর্বোধ্য হয়, পরে এই কোড নিয়ে আর কাজ করাও যায় না। ক্ষেত্র বিশেষে বিট মাসস্কিং ব্যবহার না করে কোন উপায় থাকে না, যেমন স্টোরেজ সীমাবদ্ধতা থাকলে অথবা নেটওয়ার্ক দিয়ে প্রত্যেক্টা বিট পাঠানোর সময়। তবে যখনই পারা যায়, বিট মাসস্কিং শেষ সম্বল হিসেব রেখে দিয়ে দেখতে হবে অন্য কোন উপায়ে কোডটা করে ফেলা যায় কিনা!
স্ট্রিং
স্ট্রিং হচ্ছে বাক্য বা একসাথে অনেকগুলো অক্ষর। C ভাষার সাথে জাভাস্ক্রিপ্টের পার্থক্য হচ্ছে জাভাস্ক্রিপ্টের স্ট্রিং তৈরি করার পর পরিবর্তন করা যায় না। তবে একটি স্ট্রিং এর ওপর কোন অপারেশন প্রয়োগ করে নতুন অন্য স্ট্রিং তৈরি করা যায়। যেমনঃ
- মূল স্ট্রিং এর যেকোন অংশ থেকে যেকোন সংখ্যক অক্ষর নিয়ে সাব-স্ট্রিং তৈরি করা যায়। অথবা সরাসরি এই ফাংশন ব্যবহার করে সাবস্ট্রিং তৈরি করা যায়ঃ
String.substr()
। - যোগ করার অপারেটর (+) ব্যবহার করে দুইটা স্ট্রিং একের পর এক বসিয়ে নতুন আরেকটা স্ট্রিং তৈরি করা যায়। একই কাজ হয়
String.concat()
ফাংশন ব্যবহার করে।
আপনার কোডের সব ডেটা স্ট্রিং দিয়ে প্রকাশ করবেন না!
জটিল রকমের ডেটাকে স্ট্রিং দিয়ে প্রকাশ করার প্রবণতা খুবই লক্ষ্য করা যায়। কারণ, কিছু সুবিধা পাওয়া যায় প্রায় সবকিছু স্ট্রিং দিয়ে প্রকাশ করতে গেলেঃ
- স্ট্রিং এর পর স্ট্রিং বসিয়ে অনেক জটিল ডেটা তৈরি করা যায়।
- স্ট্রিং ডেটাকে ডিবাগ করা খুব সহজ।
- অনেক API তেই স্ট্রিং খুব পরিচিত একটা মুখ। এসব API এর মধ্যে উদাহরণ হিসেবে input fields, local storage মান, {{ domxref("XMLHttpRequest") }} responses যখন
responseText ব্যবহার করা হচ্ছে
, ইত্যাদি।) তাই মনে হতে পারে সব ডেটাই তো স্ট্রিং দিয়ে প্রকাশ করা যাচ্ছে!
এটা সত্য যে প্রায় সব ডেটা স্ট্রাকচার কেই স্ট্রিং দিয়ে প্রকাশ করা সম্ভব, কিন্তু এটা ভাল আইডিয়া না। যেমন, আলাদা করার জন্য কিছু একটা ব্যবহার করে কেউ স্ট্রিং দিয়ে লিস্ট তৈরি করার চেষ্টা করতে পারে (যেখানে array বেশি উপযুক্ত হত)। এখন আলাদা করার জন্য যেই অক্ষরটা ব্যবহার করা হয়েছে, সেটিই যদি লিস্টের সদস্য হিসেবে হাজির হয় তাহলে সমস্যা দেখা দিবে। কোন এসকেপ অক্ষর ব্যবহার করা যেতে পারে হয়ত, কিন্তু এত কাহিনী কীর্তি করার তো দরকার নেই কারণ লিস্ট রাখার জন্য নিবেদিত ডেটা স্ট্রাকচার ই আছে, যেটা ব্যবহার না করে স্ট্রিং ব্যবহার করলে অপ্রয়োজনীয় বোঝা বহন করতে হবে।
তাই শুধুমাত্র টেক্সট-জাতীয় ডেটা রাখার জন্যই স্ট্রিং ব্যবহার করা উচিত। জটিল ডেটা রাখার জন্য স্ট্রিংটিকে পার্স করে উপযুক্ত ডেটা স্ট্রেকচার ব্যবহার করতে হবে।
অবজেক্ট
জাভাস্ক্রিপ্টে, অবজেক্টকে আমরা অনেকগুলো ডেটা রাখার জন্য একটা প্যাকেট হিসেবে চিন্তা করতে পারি। অবজেক্ট লিটেরেল সিনট্যাক্স ব্যবহার করে আমরা অবজেক্টের অল্প কিছু প্রোপার্টির মান দিয়ে দিতে পারি। তবে পরে যেকোন সময় যেকোন প্রোপার্টি ঐ অবজেক্টে যোগ বা বিয়োগ করা যাবে। যেকোন টাইপের ডেটা আমরা প্রোপার্টি হিসেবে রাখতে পারি অবজেক্টের, অন্য অবজেক্টের ডেটাও। এভাবে, জটিল ডেটা স্ট্রাকচার তৈরি করা সম্ভব।
"সাধারণ" অবজেক্ট, আর ফাংশন
জাভাস্ক্রিপ্টে অবজেক্ট হচ্ছে key-value ম্যাপিং। মানে অবজেক্টের কোন একটা স্ট্রিং key এর মান হিসেবে যেকোন ডেটা টাইপের value রাখা যাবে। তাই অবজেক্ট কে হ্যাশ-ম্যাপের বিকল্প হিসেবে ব্যবহার করা যায়। তবে, নন-স্ট্যান্ডার্ড __proto__
pseudo প্রোপার্টি সাবধানে ব্যবহার করতে হবে। যেখানে প্রযোজ্য, সেখানে __proto__
এর ভুল মান বসালে অবজেক্টের নিজস্ব প্রোটোটাইপ (ধরণ) বদলে যাবে। যেসব ক্ষেত্রে আমরা জানি না কোন স্ট্রিং এর উৎস কী (যেমন কোন ইনপুট ফিল্ড) সেসব ক্ষেত্রে সাবধান থাকতে হবেঃ অন্যরা এই সমস্যায় ভুগেছে। এসব ক্ষেত্রে কোন StringMap abstraction ব্যবহার করা যেতে পারে।
ফাংশনও অবজেক্ট, জাভাস্ক্রিপ্টে। পার্থক্য হল, ফাংশন কে কল করা যায়।
Arrays
Arrays ও অবজেক্ট, জাভাস্ক্রিপ্টে। তবে এখানে, প্রোপার্টি গুলোর key হচ্ছে পূর্ণ সংখ্যা আর বিশেষ 'length' প্রোপার্টি রয়েছে এদের। আরও কাহিনী হল, এরেগুলো ইনহেরিট হয় Array.prototype
থেকে - যার ফলে বেশ কিছু দরকারি ফাংশন পাওয়া যায় এরে অবজেক্ট গুলো থেকে। যেমন, indexOf
ফাংশন ব্যবহার করে array তে কোন একটা মান (সদস্য) আছে কিনা জানা যায় আবার push
ফাংশন ব্যবহার করে এরে এর শেষে কোন সদস্য যোগ করা যায়। লিস্ট কিংবা সেট হিসেবে ব্যবহার করার জন্য তাই এরে হচ্ছে সবচেয়ে উপযুক্ত ডেটা-স্ট্রাকচার।
তারিখ
তারিখ প্রকাশ করার জন্য সবচেয়ে উপযুক্ত হবে নিজস্ব Date
ইউটিলিটি ব্যবহার করা।
WeakMaps, ম্যাপ, সেট
স্ট্যান্ডার্ড নয়। আশা করা যায় ECMAScript 6. ভার্সনে স্ট্যান্ডার্ড হবে।
এসব ডেটা স্ট্রাকচার কোন অবজেক্টের রেফারেন্স কে key হিসেবে নিতে পারে। সেট দিয়ে একসারি (set) অব্জেট প্রকাশ করা হয়, আবার WeakMaps আর ম্যাপ দিয়ে কোন অবজেক্ট কে ভ্যালু হিসেবে রাখা হয়। ম্যাপ আর উইকম্যাপ এর মাঝে পার্থক্য হচ্ছেঃ ম্যাপে অবজেক্ট key, enumerate করা যায়। আর উইকম্যাপে গার্বেজ-কালেকশন বেশি ভালভাবে কাজ করে।
One could implement Maps and Sets in pure ECMAScript 5. However, since objects cannot be compared (in the sense of "less than" for instance), look-up performance would necessarily be linear. Native implementations of them (including WeakMaps) can have look-up performance that is approximately logarithmic to constant time.
Usually, to bind data to a DOM node, one could set properties directly on the object or use data-*
attributes. This has the downside that the data is available to any script running in the same context. Maps and WeakMaps make easy to privately bind data to an object.
TypedArrays
স্ট্যান্ডার্ড নয়। আশা করা যায় ECMAScript 6. ভার্সনে স্ট্যান্ডার্ড হবে।