রহস্যময়ী জাভাস্ক্রিপ্টঃ (! + [] + [] + ![]).length সমান 9 হচ্ছে কিভাবে?

আপনারা অনেকসময় হয়তো এরকমও দেখে থাকবেন যে (! + [] + [] + ![]).length সমান 9 অথবা ! + [] + [] + ![] সমান 'truefalse’ দেখাচ্ছেঃ

(! + [] + [] + ![]).length
// 9

! + [] + [] + ![]
// 'truefalse’

এটার ফলাফল এমন কেনো হচ্ছে সেটা জানতে হলে আমাদেরকে প্রথমেই কয়েকটা বিষয় সম্পর্কে ধারনা নিতে হবে, যেমন লজিক্যাল নট ! অপারেটরটার মানে কি, তারপর ইউনারি প্লাস + অপারেটর কি এবং সবশেষে জাভাস্ক্রিপ্ট এ অপারেটর প্রেসিডেন্স(Precedence) ও অ্যাসোসিয়েটিভিটি(Associativity) কিভাবে কাজ করে ইত্যাদি ইত্যাদি।

লজিক্যাল নট (!) অপারেটর

এই লজিক্যাল নট ! অপারেটরটি সত্যকে(truthy), মিথ্যা(falsy) ভ্যালুতে এবং মিথ্যাকে সত্য ভ্যালুতে রূপান্তর করে। এটা সাধারণত একটি অপারেন্ডের আগে এবং বুলিয়ান ভ্যালুর সাথে ব্যবহার করা হয়, তবে নন-বুলিয়ান ভ্যালুর সাথে ব্যবহার করলে সেই ভ্যালু ট্রুথি না ফলসি সেটার উপর ডিপেন্ড করে সেটার বিপরীত বুলিয়ান ভ্যালুতে রূপান্তর করেঃ

!false
// true 

!0
// true 

!""
// true

!"Hello World"
// false

![]
// false

ইউনারি প্লাস (+) অপারেটর

এই ইউনারি প্লাস + অপারেটর সম্পর্কে আগের পর্বেও একটু আলোচনা করা হয়েছিলো। জাভাস্ক্রিপ্টসহ অন্যান্য প্রোগ্রামিং ল্যাংগুয়েজ এই + জিনিসটার অনেক কাজ থাকতে পারে। যেমন দুই অপারেন্ডের মাঝে বসলে অ্যাডিশন অপারেটর হিসেবে কাজ করে, আবার একটা অপারেন্ডের আগে পিছে বসলে ইউনারি অপারেটর হিসেবে কাজ করে, যেমনঃ ইউনারি প্লাস(+x), ইউনারি মাইনাস(-x), ইউনারি ইনক্রিমেন্ট(++x, x++), ইউনারি ডিক্রিমেন্ট(--x, x--) অপারেটর হিসেব কাজ করতে পারে। ইউনারি প্লাস + অপারেটর অপারেন্ডের আগে বসে অপারেন্ডকে নাম্বারে কনভার্ট করার চেষ্টা করবে যদি নাম্বার না হয়ে থাকেঃ

+ []
// 0

Number([])
// 0

অপারেটর প্রেসিডেন্স(Precedence) ও অ্যাসোসিয়েটিভিটি(Associativity)

অপারেটর প্রেসিডেন্স হলো কোন অপারেটর কোনসময়, কোনটার আগে বা পরে আসবে সেটা নির্ণয় করার পদ্ধতি। আমরা যারা টুকটাক ম্যাথ করেছি, আমরা সবাই BODMAS রুল সম্পর্কে অবগত আছি। একটা সমীকরণে একইসাথে যোগ, বিয়োগ, গুণ, ভাগ, ব্র্যাকেটস ইত্যাদি ইত্যাদি থাকলে কোনটার হিসেব আগে করতে হবে আর কোনটা পরে সেটা আমরা এই BODMAS দিয়ে সহজেই নির্ণয় করতে পারি। এরকম জাভাস্ক্রিপ্টে বা প্রোগ্রামিং ল্যাংগুয়েজের ক্ষেত্রেও অপারেটর প্রেসিডেন্স অথবা এই অপারেটরগুলো একটা আগে আরেকটা পরে হিসেব হবে। এটা সম্পর্কে বিস্তারিত জানতে এখানে দেখতে পারেন।

তবে আমাদের উক্ত সমস্যায় প্রধান প্রধান যে অপারেটরগুলো আছে সেগুলো হচ্ছে গ্রুপিং (...), ইউনারি প্লাস +, লজিক্যাল নট !, ডট . এবং অ্যাডিশন + অপারেটর। এখানে গ্রুপিং (…) এর সবচেয়ে বেশী প্রেসিডেন্স থাকবে, অর্থ্যাৎ সবার আগে এটার হিসেব হবে। তারপর এটার ভিতরে সবচেয়ে বেশী প্রাধান্য পাবে ইউনারি প্লাস + এবং লজিক্যাল নট ! অপারেটরটি। তারপর আসবে অ্যাডিশন অপারেটর + এর হিসাব এবং সবশেষে এই গ্রুপিং এর বাইরে ডট মেম্বার অ্যাক্সেস অপারেটর . এর প্রধান্য পাবে যেটা দিয়ে আমরা length অ্যাক্সেস করবো।

তারপর আরেকটা গুরুত্বপূর্ন বিষয় আসে যেটা হচ্ছে অ্যাসোসিয়েটিভিটি(Associativity)। এটা ইউজ করা হয় সেইম প্রেসিডেন্স থাকা অপারেটর এর ক্ষেত্রে যদি গ্রুপিং করা না থাকে তাহলে কোনটার হিসেব আগে হবে আর কোনটার হিসেব পরে হবে সেটা বের করার জন্য। ধরেন উপরের সমস্যায় লজিক্যাল নট ! অপারেটরটি একাধিক জায়গায় আছে, আবার অ্যাডিশন প্লাস + অপারেটরটিও একাধিক জায়গায় আছে। এদের প্রেসিডেন্স কিন্তু সেইমই, তাইলে কোনটা আগে আর কোনটা পরে হিসেব হবে? ঠিক এটাই নির্ণয় করা হয় অপারেটর অ্যাসোসিয়েটিভিটির মাধ্যমে। এখানে লজিক্যাল নট ! এর হিসেব হবে ডান দিক থেকে বাম দিকে(right to left), অ্যাডিশন প্লাস + অপারেটর এর আবার বাম দিক থেকে ডান দিকে(left to right)।

মূল সমস্যার ব্যাখ্যা

এবার আমাদের মোটামুটি সবগুলো বিষয় সম্পর্কে ধারনা হয়েছে, এবার আমরা আমাদের মূল সমস্যা (! + [] + [] + ![]).length দিকে দেখতে পারি। এখানে গ্রুপিং (…) অপারেটর এর প্রাধান্য যেহেতু সবচেয়ে বেশি তাই প্রথমে এর ভিতরে ! + [] + [] + ![] থেকে হিসাবনিকাশ শুরু হবে। ভিতরে শুরুতেই প্রথমে লজিক্যাল নট ! এবং ইউনারি অপারেটর + প্রাধান্য পাবে। এখানে যেহেতু এদের প্রেসিডেন্স সেইম, তাই এবার অ্যাসোসিয়েটিভিটি হিসেবে ডান দিক থেক বাম দিকে হিসেব হবে। অর্থাৎ প্রথমে +[] এর হিসেব হবে, তারপর এটার ফলাফলের সাথে লজিক্যাল নট ! এরঃ

+[] 
// 0

তারপর এই 0 এর আগে লজিক্যাল নট ! অপারেটরটি থাকায় সেটার হিসেব হবেঃ

!0
//true

তারপর আমাদের এখানে দেখবেন শেষের দিকে আরেকটা লজিক্যাল নট ! অপারেটর রয়েছে এবং এবার সেটার হিসেব হবেঃ

![]
// false

এগুলোর সব হিসাবনিকাশ শেষ হওয়ার পর আমাদের মূল্য সমস্যাটা ! + [] + [] + ![] এখন এরকম দেখা যাবে অনেকটাঃ

true + [] + false

এখানে এখন শুধু অ্যাডিশন প্লাস + অপারেটরটাই রয়ে গেছে, অতএব এবার এগুলোর হিসেব হবে অ্যাডিশন অপারেটর + এর অ্যাসোসিয়েটিভিটি হিসেবে বাম দিক থেকে ডান(left to right) দিকে। তো এখানে true + [] এর ক্ষেত্রে পূর্বের একটা পর্বে আলোচনা করার মতো করে এখানে আমরা যেহেতু একটা বুলিয়ান আর একটা অ্যারের মাঝখানে অ্যাডিশন প্লাস + অপারেটরটি বসেছে আর এই দুইটাই আসলে নাম্বার না, তাই এখানে এই + অপারেটরটি টাইপ কোয়ারশনের সাহায্যে দুইটাকেই স্ট্রিং এ কনভার্ট করবে এবং সর্বশেষে দুইটাকে স্ট্রিং হিসেবে যুক্ত()String Concatenation করবেঃ

true + []
// 'true'

// Explanation
String(true)
// 'true'

String([])
// ''

// Finally
'true' + ''
// 'true'

তারপর রয়ে গেলো এটার সাথে আবার false কে অ্যাডিশন অপারেটর + দিয়ে যুক্ত করা, যেটা একই নিয়মে আবার false ভ্যালুটি স্ট্রিঙে কনভার্ট করবে এবং এটার সাথে অ্যাড হবেঃ

'true' + false
// 'truefalse'

তো সবশেষে এই সবগুলো নিয়মকানুন ফলো করে, হিসেবনিকেশ করে তারপর এই ! + [] + [] + ![] এর ভ্যালু হয়েছে 'truefalse'

তারপর আমাদের এবার গ্রুপিং অপারেটর () এর শেষে .length আসছে, যেটা মূলত এই স্ট্রিং এর length বের করেছে যেটার ভ্যালু হচ্ছে 9। অর্থাৎ এই স্ট্রিং এর length হচ্ছে আসলে 9:

('truefalse').length

আশা করি এবার পুরো ব্যাপারটা খুব সুন্দর করে বুঝতে পেরেছেন এখানে কিভাবে কি হলো। এই প্রবলেমটা খুবই সুন্দর একটা উদাহরণ জাভাস্ক্রিপ্ট এর অপারেটর প্রেসিডেন্স ও অ্যাসোসিয়েটিভিটি বুঝার জন্য। আশা করি এগুলো সম্পর্কে ধারনা থাকলেই অনেক সহজে এরকম সমস্যাগুলোর সমাধান খুব সহজেই বের করতে পারবেন।

শেয়ার করুন

লেখাটি ভাল লাগলে সোশ্যাল মিডিয়ায় শেয়ার করুন। আপনার কলিগ, বন্ধু কিংবা প্রিয় কারও কাজে লাগতে পারে। জানেন তো, শেয়ারিং ইজ কেয়ারিং!

সাবস্ক্রিপশন সেন্টার

প্রতিদিন ওয়েবসাইটে আসা আপনার জন্য কষ্টকর হতে পারে। তাই যখনই আমি নতুন ব্লগ পোস্ট, সিরিজ, বই বা ভিডিও পাবলিশ করব,
তখনই তা আপনার ইমেইলে পেতে সাবস্ক্রাইব করুন। নো স্প্যামিং প্রমিজ!