আপনারা হয়তো অনেকসময় দেখেছেন যে [] + {} === {} + []
সত্য true
দেখাচ্ছে। যদিও আমরা আগের দুইটা পর্বে দেখেছি [] + {}
সমান '[object Object]’
হচ্ছে, আর {} + []
সমান 0
হচ্ছে। বাট তারপরেও এদেরকে কম্পেয়ার করতে গেলে আবার সমান সমানই দেখায়ঃ
[] + {} === {} + []
// true
কিন্তু এটা উল্টিয়ে ক্রোমের ডেভেলপার কন্সোলে যদি {} + [] === [] + {}
এটা ট্রাই করেন তাহলে দেখবেন false
দেখাচ্ছে, আবার নোড জেএস এর REPL এ true
দেখাচ্ছেঃ
// NodeJS REPL
{} + [] === [] + {}
// true
// Google Chrome Developer Console
{} + [] === [] + {}
// false
মাথায় গন্ডগোল লেগে যাচ্ছে ঠিক না? আসলে চিন্তার কোন কারণ নাই, ব্যাপারটা আসলে গত পর্বে দেখানোর মতোই এদের REPL এর ডিফারেন্ট আচরণের কারণেই হচ্ছে। তবে এখানে প্রথমে আমরা নোড জেএস কিভাবে করছে সেটা আলোচনা করবো, আর পরে ব্রাউজারেরগুলো।
নোড জেএস এর REPL এ যাই দেন না কেন সেটাকে অ্যাকচুয়ালি এক্সপ্রেশন হিসেবেই গণ্য করা হয়, আর এক্সপ্রেশন কন্টেক্সটেই সেটার এক্সিকিউট করা হয়। তাই আপনি এদেরকে যে কম্বিনেশনেই ট্রাই করুন না কেন সবগুলোই সত্য true
দেখাবেঃ
// in node js only
{} + [] === [] + {}
// true
[] + {} === {} + []
// true
{} + [] === {} + []
// true
[] + {} === [] + {}
// true
এখানে নোড জেএস এর REPL এক্সপ্রেশন হিসেবে গণ্য করায় প্রথমে খালি {}
থাকা স্বত্বেও সেটাকে আসলে খালি অবজেক্ট {}
হিসেবেই গণ্য করা হয়েছে। ফলে এই পর্বে দেখানোর মতো করে এখানে সবগুলোই এক্সপ্রেশনে সেইম ভ্যালুই আউটপুট করছেঃ
({} + [])
// '[object Object]'
([] + {})
// '[object Object]'
এখানে আমি ব্র্যাকেটস() ইউজ করে ফোর্স এক্সপ্রেশনে কনভার্ট করে নিয়েছি, তাই এটা ব্রাউজারেও ঠিকঠাক কাজ করবে।
এখানে অ্যাডিশন +
অপারেটর এর সাহায্যে স্ট্রিং যুক্ত(String Concatenation) হয়েছেঃ
String([])
// ''
String({})
// '[object Object]'
'' + '[object Object]'
// '[object Object]'
([] + {})
// '[object Object]'
ঠিক এই কারণেই নোড জেএস এ সবরকমের কম্বিনেশনই সেইম ফলাফল, অর্থাৎ সত্য true
দেখাবে একটার সাথে আরেকটার কম্পেয়ার করার সময়। বাট ক্রোম ডেভেলপার কন্সোলসহ বেশ কিছু ব্রাউজারে আবার অন্যরকম আচরণ দেখতে পাবেন যদিনা ফোর্স এক্সপ্রেশনে কনভার্ট করেন।
ব্রাউজারে দেখবেন [] + {}
এর সাথে {} + []
কম্পেয়ার করলে সেটা সত্য true
দেখাচ্ছে। খালি অ্যারে []
সামনে দিয়ে কম্পেয়ার করলেই সব সত্য true দেখাচ্ছেঃ
[] + {} === {} + []
// true
[] + {} === [] + {}
// true
কিন্তু যখনি আবার খালি {}
সামনের দিকে দিবেন সেটা মিথ্যা false
দেখাবেঃ
{} + [] === [] + {}
// false
{} + [] === {} + []
// false
ঘটনাটা ঠিক আগের পর্বে দেখানো ঘটনাটার মতো করেই ঘটছে। প্রথমে খালি {}
থাকার কারণে সেটাকে খালি ব্লক হিসেবে গণ্য করা হচ্ছে। তারপর +
খালি অ্যারে []
হওয়াতে এখানে +
টা আসলে ইউনারি প্লাস +
অপারেটর হিসেবে গণ্য হবে, আর এর পরের অপারেন্ড, আমাদের ক্ষেত্রে খালি অ্যারেটাকে []
নাম্বারে কনভার্ট করার চেষ্টা করবে। ফলাফলে খালি ব্লক {}
থেকে তো কিছু আসবে না, জাস্ট খালি অ্যারে []
টা কনভার্ট হয়ে ফলাফল শূন্য 0
হবেঃ
+ []
// 0
{} + []
// 0
কিন্তু আবার {} + [] === [] + {}
এর পরের [] + {}
তে হিসাব নিকাশ উল্টে যাবে। তখন আবার যেটাই আগে বা পরে থাকুক না কেন সব এক্সপ্রেশন কন্টেক্সটে হবে আর ফলাফল সেরকমভাবেই দেখাবে। হিসাব খুবই সোজা, সেটা হচ্ছে এখানে যেহেতু {}
স্টার্টিং এ নাই তাই এটাকে খালি অবজেক্ট হিসেবেই গণ্য করা হবে। আর অ্যাডিশন +
অপারেটর স্ট্রিং হিসেবে যুক্ত করবে আর সেটাই ফলাফল হবে। আমি বুঝার সুবিধার্থে ফোর্স এক্সপ্রেশন নিয়ে দেখাচ্ছিঃ
([] + {})
// '[object Object]'
({} + [])
// '[object Object]'
ফলাফলে আমরা আসলে {} + [] === [] + {}
এখানে শূন্য 0
এর সাথে '[object Object]'
কে কম্পেয়ার করছি যেটা অবশ্যই সমান সমান না কখনইঃ
0 === '[object Object]'
এরকম যতোই স্টার্টিং এ খালি {}
থাকবে সেটাকে খালি ব্লক হিসেবে গণ্য করা হবে আর সেভাবেই সবকিছু হিসেব করা হবে। বাট আবার যদি ফোর্স এক্সপ্রেশন করেন তাহলে দেখবেন সব ঠিকঠাকঃ
({} + [] === [] + {})
// true
({} + [] === {} + [])
// true
এতো এতো আলোচনা করার পর মূল বিষয়টা দাঁড়াচ্ছে এই যে যখন আপনি এইধরনের সমস্যা দেখতে পাবেন তখন চিন্তা করবেন যে এটা এক্সপ্রেশন কন্টেক্সটে হচ্ছে নাকি স্টেটমেন্ট কন্টেক্সটে। এক্সপ্রেশন কন্টেক্সটে হলে তো তেমন সমস্যা নেই, বাট স্টেটমেন্ট কন্টেক্সটে চলে গেলে এমন খালি {}
অবজেক্ট এর মতো দেখতে জিনিস খালি ব্লক {}
হিসবেও গণ্য হতে পারে। আর ফলাফলও তখন সে হিসেবেই হবে।