2.11 কল বাই ভ্যালু এবং কল বাই রেফারেন্স
আজকে আমরা আলোচনা করতে যাচ্ছি Primitive এবং Reference টাইপ ডাটার মাঝে কি পার্থক্য এবং এই ডাটা টাইপগুলো কিভাবে কাজ করে। Primitive এবং Reference টাইপকে pass by value এবং pass by reference-ও বলা হয়ে থাকে। একজন জাভাস্ক্রিপ্ট প্রোগ্রামার হিসাবে এই ডাটা টাইপগুলো সম্পর্কে পরিষ্কার জ্ঞান রাখা আবশ্যক।
জাভাস্ক্রিপ্টে দুই টাইপের ডাটা টাইপ আছে।
- Primitive ডাটা টাইপ
- Non-primitive বা reference ডাটা টাইপ
জাভাস্ক্রিপ্টে Strings, Numbers, Boolean, Null, undefined, bigint এবং symbol এই ডাটা টাইপগুলো প্রিমিটিভ ডাটা টাইপ হিসাবে পরিচিত এবং Arrays, Objects, Function নন-প্রিমিটিভ বা রেফারেন্স ডাটা টাইপ হিসাবে পরিচিত। এদের মাঝে মৌলিক পার্থক্য হচ্ছে যে প্রিমিটিভ ডাটা immutable বা অপরিবর্তনীয় এবং নন-প্রিমিটিভ ডাটা mutable বা পরিবর্তনীয়।
প্রিমিটিভ ডাটা টাইপ
প্রমিটিভ ডাটা immutable বা অপরিবর্তনীয় ডাটা টাইপ হিসাবে পরিচিত। কারণ এই ডাটা একবার তৈরি হয়ে গেলে এটি পরিবর্তন করার কোন পথ নেই। তাহলে চলেন আপনাদের প্রমাণ করে দেখাই।
উপরের কোডটা রান করলে জাভাস্ক্রিপ্টের কারিশমা দেখতে পারবেন। সব কিছু মাথার উপর দিয়ে গেল? আচ্ছা, চলেন ব্যাপারটা ব্যাখ্যা করি। আপনি হাজার বার চাইলেও স্ট্রিং এর ভ্যালু পরিবর্তন করতে পারবেন না। কারণ স্ট্রিং একটি immutable বা অপরিবর্তনীয় ডাটা। একটি কথা মনে রাখবেন যদি স্ট্রিংকে কোন ভেরিয়েবলে অ্যাসাইন করে ফেলেন এবং অ্যাসাইন করার পর স্ট্রিংকে মডিফাই করতে চান, তাহলে আপনি একটি নতুন স্ট্রিং পাবেন। যেমন- .toUpperCase(), .slice(), .trim() ইত্যাদি।
প্রিমিটিভ ডাটা টাইপগুলো একে অপরের সাথে তাদের ভ্যালু দ্বারা তুলনা করে।
প্রিমিটিভ টাইপগুলো সব সময় তাদের ভ্যালু পাস করে। যখন আমরা কোন প্রিমিটিভ ডাটা টাইপকে অন্য কোন ভেরিয়েবলে অ্যাসাইন করি, তখন তার ভ্যালু কপি হয়ে নতুন ভেরিয়েবলে অ্যাসাইন হয়।
নন-প্রিমিটিভ ডাটা টাইপ
নন-প্রিমিটিভ ডাটা mutable বা পরিবর্তনীয়। কারণ একটি নন-প্রিমিটিভ ডাটা তৈরি হয়ে যাওয়ার পরেও তার ভ্যালু পরিবর্তন হতে পারে। আমরা যখন কোন নন-প্রিমিটিভ ডাটা তৈরি করি, তখন সেই ডাটার জন্যে মেমোরিতে একটা অ্যাড্রেস তৈরি হয় এবং সেই অ্যাড্রেসটাকে মনে রেখে কোন এক জায়গায় ভ্যালুগুলোকে স্ট্রোর করে রাখে। তারপর আমাদের যখন দরকার পরে তখন সে ঐ অ্যাড্রেসকে কল করে এবং আমাদের ডাটা প্রদান করে। এটা বুঝতে হলে আপনাকে স্ট্যাক এবং হীপ মেমোরি সম্পর্কে জানতে হবে। তবে আমি যতটুকু বললাম এখন এতটুকু মনে রাখলেই হবে।
নন-প্রিমিটিভ বা রেফারেন্স ডাটাগুলো সব সময় তাদের রেফারেন্স পাস করে। যখন আমরা কোন রেফারেন্স ডাটাকে অন্য কোন ভেরিয়েবলে অ্যাসাইন করি, তখন তার রেফারেন্স কপি হয়। মানে arr1 কে যখন আমরা arr2 তে অ্যাসাইন করি তখন তার রেফারেন্স বা অ্যাড্রেসটাকে কপি করে বা মনে রাখে তার ভ্যালুকে না। তাই দুইটা ভেরিয়েবলের অ্যাড্রেস একই থাকে। তাই যখন আমরা কোন একটি ভেরিয়েবলের ভ্যালু পরিবর্তন করি, তখন দুইটা ভেরিয়েবলেরই ভ্যালু পরিবর্তন হয়ে যায়।
আশা করি, উপরের কোডে কি হচ্ছে সেটা এখন খুব ভাল ভাবেই বুঝতে পারছেন। একটি কথা নন-প্রিমিটিভ ডাটা তাদের রেফারেন্স দ্বারা তুলনা করে।
এখানে দুইটা অবজেক্টের একই ভ্যালু কিন্তু যখন আমরা দুইটা অবজেক্টকে একে-অপরের সাথে তুলনা করছি, তখন তারা false রিটার্ন করছে। কারণ তাদের ভ্যালু একই হলেও তাদের অ্যাড্রেস এক না।
-
Call By Value or primitives types এর উদাহরণfunction multiplyByTen(value) {value = value * 10;}var number = 7;console.log(“Before call: number = “ + number); // 7multiplyByTen(number);console.log(“After call: number = “ + number); // 7
- Call By Reference of non-primitives types এর উদাহরণ
function passByReference(person) {person.name = “Alex”;}var alam = { name: “Alam” };console.log(alam.name);// AlampassByReference(alam);console.log(alam.name);// Alex
- call by value
function printGreeting(greetName) {greetName = “Hello, “ + greetName;console.log(“New value: “ + greetName); // Output: Hello, Anik}var greetName = ‘Anik’;printGreeting(greetName);console.log(“Old value: “ + greetName); // Output: Anik
- call by reference
function modifyObj(person) {person.name = ‘Fahim’;person.age = 26;}var person = {name: ‘Anik’,age: 25};console.log(“Initial name value: “ + person.name); // Initial name value: AnikmodifyObj(person);console.log(“Updated name value: “ + person.name); // Udated name value: Fahim
- মনে করুন, আমি Google Doc এ একটি ফাইল খুলেছি এবং সেটাতে আপনাকেও এডিট করার পারমিশন দিয়েছি। এখন ফাইলটিতে আপনি বা আমি যেই কোন কিছু লিখি বা পরিবর্তন করি না কেন সেটা আমাদের দুজনের দিক থেকেই পরিবর্তন হবে। বিষয়টি এমন হবে না যে আপনি দেখলে এক রকম হবে আর আমি দেখলে অন্য রকম হবে। এই বিষয়টি ঠিক Call by reference এর মতো। আবার অন্যদিকে, আমার কাছে থাকা একটি ফাইলের কপি আমি আপনাকে দিলাম অর্থাৎ কপি মূলত দুটি, একটি আপনার আর অন্যটি আমার। সুতরাং আমি যদি আমার ফাইলে কোন পরিবর্তন করি তবে সেটি শুধুমাত্র আমার ফাইলেই পরিবর্তন হবে, আপনারটা যেমন ছিল বা আপনি যেভাবে পরিবর্তন করেছেন সেভাবেই থাকবে। আমাদের কারো পরিবর্তন একে অন্যের উপর কোন প্রভাব ফেলবে না। এই বিষয়টি Call by value এর মতো। আশাকরি এখন বিষয় দুটি বুঝতে কোন সমস্যা হবে না। চলুন একটা উদাহরণ দেখিঃ
// Call By Value Partlet primitiveData = 200;(function callByValue(primitiveData) {primitiveData = 404;})(primitiveData);console.log(primitiveData); // Output: 200// Call By Reference Partlet nonPrimitiveData = [‘Abid’, ‘Shahan’, ‘Imrul’, ‘Biplob’];(function callByReference(nonPrimitiveData) {nonPrimitiveData[0] = ‘Tareq’;nonPrimitiveData.push(‘Tajnur’);})(nonPrimitiveData);console.log(nonPrimitiveData); // Output: [ ‘Tareq’, ‘Shahan’, ‘Imrul’, ‘Biplob’, ‘Tajnur’ ]
- জাভাস্ক্রিপ্টে pass by value এবং pass by reference মধ্যে পার্থক্য কী?
- নিচের কোডের আউটপুট কি হবে?
var myObject = {price: 20.99,get_price: function () {return this.price;},};var customObject = Object.create(myObject);customObject.price = 19.99;delete customObject.price;console.log(customObject.get_price());
- নিচের কোডের আউটপুট কি হবে?
(function (a) {arguments[0] = 10;return a;})(5);
- নিচের কোডের আউটপুট কি হবে?
function Car(color) {this.color = color;}var lada = new Car(‘Black’);Car.prototype.currentGear = 1;console.log(++lada.currentGear);console.log(Car.prototype.currentGear);
- নিচের কোডের আউটপুট কি হবে?
var User = function () {};User.prototype.attributes = {isAdmin: false,};var admin = new User(‘Sam’),guest = new User(‘Bob’);admin.attributes.isAdmin = true;console.log(admin.attributes.isAdmin);console.log(guest.attributes.isAdmin);