জাভাস্ক্রিপ্টে `Object` ক্লাস

জাভাস্ক্রিপ্টে `Object` ক্লাস

এই প্রবন্ধে জাভাস্ক্রিপ্টের Object ক্লাস ব্যাখ্যা করা হয়েছে।

এই প্রবন্ধে ব্যবহারিক উদাহরণসহ জাভাস্ক্রিপ্টের Object ক্লাস ব্যাখ্যা করা হয়েছে।

YouTube Video

জাভাস্ক্রিপ্টে Object ক্লাস

Object একটি বিল্ট-ইন অবজেক্ট, যা সব জাভাস্ক্রিপ্ট অবজেক্টের জন্য বেস হিসেবে কাজ করে। ভাষার অনেক মূল বৈশিষ্ট্য, যেমন প্রোপার্টি পরিচালনা, উত্তরাধিকার (প্রোটোটাইপ চেইন), গণনা, ক্লোনিং এবং ফ্রিজিং, Object-এর আচরণের মাধ্যমে প্রদান করা হয়।

Object.create

অবজেক্ট তৈরির একাধিক উপায় রয়েছে, এবং আপনার উদ্দেশ্যের ভিত্তিতে সেগুলো যথাযথভাবে ব্যবহার করতে হবে।

অবজেক্ট লিটারেল (সবচেয়ে প্রচলিত)

নিম্নের কোডে অবজেক্ট তৈরি করার সবচেয়ে সহজ ও পাঠযোগ্য উপায় দেখানো হয়েছে।

 1// Create an object using object literal
 2const user = {
 3  name: "Alice",
 4  age: 30,
 5  greet() {
 6    return `Hello, I'm ${this.name}`;
 7  }
 8};
 9
10console.log(user.greet()); // "Hello, I'm Alice"
  • এই উদাহরণে, প্রপার্টি এবং মেথডগুলি লিটারাল ব্যবহার করে সংজ্ঞায়িত করা হয়েছে। এটি সহজ এবং সাধারণভাবে উন্নত কর্মক্ষমতা প্রদান করে।

new Object() কনস্ট্রাক্টর

Object কনস্ট্রাক্টর খুব কম ব্যবহৃত হয়, তবে এর আচরণ বোঝা কাজে লাগে।

1// Create an object using the Object constructor
2const objFromCtor = new Object();
3objFromCtor.x = 10;
4objFromCtor.y = 20;
5
6console.log(objFromCtor); // { x: 10, y: 20 }
  • new Object() একটি ফাঁকা অবজেক্ট ফেরত দেয়, তবে {} লিটারেল আরও সংক্ষিপ্ত ও বেশি ব্যবহৃত।

Object.create-এর মাধ্যমে প্রোটোটাইপ নির্ধারণ করা

Object.create নির্দিষ্ট প্রোটোটাইপ সহ অবজেক্ট তৈরি করতে ব্যবহৃত হয়।

1// Create an object with a specified prototype
2const proto = { hello() { return "hi"; } };
3const obj = Object.create(proto);
4obj.name = "Bob";
5
6console.log(obj.hello()); // "hi"
7console.log(Object.getPrototypeOf(obj) === proto); // true
  • Object.create ইনহেরিটেন্স-ভিত্তিক অবজেক্ট ডিজাইনের জন্য আদর্শ, কারণ এটি প্রোটোটাইপ চেইন নিয়ন্ত্রণে সাহায্য করে।

প্রপার্টি অ্যাট্রিবিউট এবং ডিসক্রিপ্টর

প্রপার্টির অ্যাট্রিবিউট যেমন 'value', 'writable', 'enumerable', এবং 'configurable', যেগুলো Object.defineProperty দ্বারা বিস্তারিতভাবে নিয়ন্ত্রণ করা যায়।

defineProperty ব্যবহারের একটি মৌলিক উদাহরণ

defineProperty ব্যবহার করে non-enumerable এবং read-only প্রপার্টি সংজ্ঞায়িত করার একটি উদাহরণ নিচে দেয়া হলো।

 1// Define a non-enumerable read-only property
 2const person = { name: "Carol" };
 3
 4Object.defineProperty(person, "id", {
 5  value: 12345,
 6  writable: false,
 7  enumerable: false,
 8  configurable: false
 9});
10
11console.log(person.id); // 12345
12console.log(Object.keys(person)); // ["name"] — "id" is non-enumerable
13person.id = 999; // silently fails or throws in strict mode
14console.log(person.id); // still 12345
  • defineProperty ব্যবহার করলে আপনি প্রপার্টির আচরণ যেমন এনুমারেশন, পুনঃলিখন, এবং মুছে ফেলা নির্ভুলভাবে নিয়ন্ত্রণ করতে পারেন।

অ্যাক্সেসর প্রপার্টি (getter / setter)

অ্যাক্সেসর ব্যবহারে প্রপার্টিতে পড়া ও লেখার সময় লজিক যুক্ত করা যায়।

 1// Use getter and setter to manage internal state
 2const data = {
 3  _value: 1,
 4  get value() {
 5    return this._value;
 6  },
 7  set value(v) {
 8    if (typeof v === "number" && v > 0) {
 9      this._value = v;
10    } else {
11      throw new Error("value must be a positive number");
12    }
13  }
14};
15
16console.log(data.value); // 1
17data.value = 5;
18console.log(data.value); // 5
19// data.value = -1; // would throw
  • getter এবং setter ব্যবহারে প্রপার্টি অ্যাক্সেসকে এক্সটার্নাল API-এর মতো ব্যবহার করা যায় ও যাচাই বা সাইড ইফেক্ট যোগ করা যায়।

প্রোটোটাইপ ও ইনহেরিটেন্স (prototype / __proto__ / Object.getPrototypeOf)

জাভাস্ক্রিপ্টে ইনহেরিটেন্স ক্লাসের উপর নয়, প্রোটোটাইপ চেইনের উপর ভিত্তি করে। অবজেক্ট অন্য অবজেক্টকে প্রোটোটাইপ হিসেবে উল্লেখ করতে পারে।

Object.getPrototypeOf এবং Object.setPrototypeOf

নিম্নের উদাহরণটি দেখায় কীভাবে প্রোটোটাইপ পরিদর্শন ও সেট করা যায়।

1// Inspect and change prototype
2const base = { speak() { return "base"; } };
3const derived = Object.create(base);
4console.log(Object.getPrototypeOf(derived) === base); // true
5
6const other = { speak() { return "other"; } };
7Object.setPrototypeOf(derived, other);
8console.log(derived.speak()); // "other"
  • Object.getPrototypeOf একটি অবজেক্টের প্রোটোটাইপ নিয়ে আসে।
  • Object.setPrototypeOf বিদ্যমান অবজেক্টের প্রোটোটাইপ পরিবর্তন করে, তবে এটি পারফরম্যান্সে প্রভাব ফেলে তাই সতর্কতার সঙ্গে ব্যবহার করা উচিত।

গুরুত্বপূর্ণ বিল্ট-ইন মেথডসমূহ

Object.prototype দ্বারা প্রদানকৃত ইনস্ট্যান্স মেথডগুলোর মধ্যে থেকে সর্বাধিক ব্যবহৃত এবং গুরুত্বপূর্ণ মেথডগুলোর পাশাপাশি Object-এর স্ট্যাটিক মেথডগুলোর স্পষ্ট ব্যাখ্যা আমরা দেব।

hasOwnProperty, isPrototypeOf, toString, valueOf

hasOwnProperty, isPrototypeOf, toString, এবং valueOf অবজেক্টের মৌলিক আচরণ সংজ্ঞায়িত করে।

 1// Demonstrate prototype methods
 2const base = { greet() { return "hello"; } };
 3const child = Object.create(base);
 4const a = { x: 1 };
 5
 6console.log(a.hasOwnProperty("x")); // true
 7console.log(a.hasOwnProperty("toString")); // false — toString is inherited
 8
 9console.log(a.toString()); // "[object Object]" by default
10
11console.log(base.isPrototypeOf(child)); // true
12console.log(Object.prototype.isPrototypeOf(child)); // true
  • hasOwnProperty হলো গুরুত্বপূর্ণ একটি মেথড, যেটির মাধ্যমে নির্ধারণ করা যায় কোনো প্রপার্টি সরাসরি অবজেক্টে আছে কিনা।
  • isPrototypeOf যাচাই করে টার্গেট অবজেক্টটি তার প্রোটোটাইপ হিসেবে নিজেকে রাখে কি না।

Object.keys, Object.values, Object.entries

Object.keys, Object.valuesObject.entries অবজেক্টের নিজস্ব enumerable প্রপার্টির লিস্ট ফেরত দেয়। এগুলো iteration ও রূপান্তরের জন্য দরকারি।

 1// Keys, values and entries
 2const item = { id: 1, name: "Widget", price: 9.99 };
 3
 4// ["id", "name", "price"]
 5console.log(Object.keys(item));
 6
 7// [1, "Widget", 9.99]
 8console.log(Object.values(item));
 9
10// [["id",1], ["name","Widget"], ["price",9.99]]
11console.log(Object.entries(item));
  • এগুলো অবজেক্ট iterate ও রূপান্তরের জন্য প্রায়শই ব্যবহৃত হয়।

Object.assign

Object.assign শ্যালো কপি ও মার্জ করার জন্য ব্যবহৃত হয়। খেয়াল করুন প্রোটোটাইপ ও অ্যাক্সেসর প্রপার্টি কপি হয় না।

1// Shallow copy / merge using Object.assign
2const target = { a: 1 };
3const source = { b: 2 };
4const result = Object.assign(target, source);
5
6console.log(result); // { a: 1, b: 2 }
7console.log(target === result); // true (merged into target)
  • নেস্টেড অবজেক্টের ক্ষেত্রে শুধু রেফারেন্স কপি হয়, তাই ডীপ ক্লোনের জন্য আলাদা বাস্তবায়ন দরকার।

Object.freeze, Object.seal, Object.preventExtensions

Object.freeze, Object.seal এবং Object.preventExtensions অবজেক্টের মিউটেবিলিটি নিয়ন্ত্রণ করে।

 1// Freeze vs seal vs preventExtensions
 2const obj = { a: 1 };
 3Object.freeze(obj);
 4obj.a = 2; // fails silently or throws in strict mode
 5delete obj.a; // fails
 6
 7const obj2 = { b: 2 };
 8Object.seal(obj2);
 9obj2.b = 3; // allowed
10// delete obj2.b; // fails
11
12const obj3 = { c: 3 };
13Object.preventExtensions(obj3);
14obj3.d = 4; // fails
  • freeze সবচেয়ে কঠোর, এটি অবজেক্টের প্রপার্টি পরিবর্তনে সম্পূর্ণ বাধা দেয়।
  • seal নতুন প্রপার্টি যোগ বা মুছে ফেলা প্রতিরোধ করে, তবে বিদ্যমান প্রপার্টির মান পরিবর্তন করার অনুমতি দেয়।
  • preventExtensions শুধুমাত্র নতুন প্রপার্টি যোগ করা বন্ধ করে; বিদ্যমান প্রপার্টি পরিবর্তন বা মুছে ফেলা যেতে পারে।

অবজেক্টের এনামারেশন, নিয়ম এবং for...in / for...of

for...in শুধুমাত্র enumerable প্রপার্টির নাম নয়, প্রোটোটাইপ চেইনের প্রপার্টিও এনামারেট করে, তাই hasOwnProperty-এর সঙ্গে ব্যবহার করা হয়। Object.keys()-কে for...of-এর সাথে সংযুক্ত করা আরও নিরাপদ এবং আপনার উদ্দেশ্য স্পষ্ট করে তোলে।

 1// Safe enumeration
 2const obj = Object.create({ inherited: true });
 3obj.own = 1;
 4
 5for (const key in obj) {
 6  if (obj.hasOwnProperty(key)) {
 7    console.log("own prop:", key);
 8  } else {
 9    console.log("inherited prop:", key);
10  }
11}
12
13for (const key of Object.keys(obj)) {
14  console.log("key via Object.keys:", key);
15}
  • প্রপার্টি এনামারেশনের নিয়ম ECMAScript স্পেসিফিকেশনে নির্ধারিত, এবং কিছু ক্ষেত্রে অর্ডার গ্যারান্টিযুক্ত, কিছু ক্ষেত্রে নয়। সাধারণ নিয়ম অনুযায়ী, যেসব কী নাম্বার হিসেবে বোঝা যায়, সেগুলো ঊর্ধ্বক্রমে সাজানো হয়, অন্যদিকে অন্যান্য কী ইনসারশন অর্ডার অনুসরণ করে।

ক্লোনিং এবং ডীপ কপি

অবজেক্ট অনুলিপির দুটি ধরণ আছে: Object.assign বা স্প্রেড সিনট্যাক্স ব্যবহার করে শ্যালো কপি এবং পুনরাবৃত্তিমূলক পদ্ধতি ব্যবহার করে ডিপ কপি। পরিস্থিতির উপর নির্ভর করে এগুলো যথাযথভাবে ব্যবহার করা গুরুত্বপূর্ণ।

শ্যালো কপি (স্প্রেড সিনট্যাক্স / Object.assign)

1// Shallow copy with spread operator
2const original = { a: 1, nested: { x: 10 } };
3const shallow = { ...original };
4shallow.nested.x = 99;
5console.log(original.nested.x); // 99 — nested object is shared
  • শ্যালো কপিতে নেস্টেড অবজেক্টের রেফারেন্স শেয়ার হয়, তাই মূল অবজেক্টে পরিবর্তন হলে কপিতেও প্রভাব পড়ে।

সহজ ডীপ কপি (কিছু সতর্কতা সহ)

JSON ট্রিক ব্যবহার করে দ্রুত ডীপ কপি করা যায়, কিন্তু এতে ফাংশন, Date, সার্কুলার রেফারেন্স ও undefined হারিয়ে যেতে পারে। আসল ডীপ ক্লোনের জন্য বিশেষ লাইব্রেরি ব্যবহার করতে হয়।

1// Deep clone using JSON methods — limited use-cases only
2const source = { a: 1, d: new Date(), nested: { x: 2 } };
3const cloned = JSON.parse(JSON.stringify(source));
4console.log(cloned); // ok for plain data, but Date becomes string, functions lost
  • JSON-ভিত্তিক মেথডসমূহ দ্রুত সাধারণ ডেটা পরিচালনার জন্য সুবিধাজনক, তবে সাধারণ ক্ষেত্রে এদের আচরণ বিঘ্নিত হতে পারে।

মিক্সিন এবং অবজেক্ট কম্পোজিশন

বহুবিধ ইনহেরিটেন্স না করে আচরণ কম্পোজিশনের জন্য মিক্সিন প্যাটার্ন প্রায়শই ব্যবহৃত হয়।

 1// Simple mixin function
 2const canEat = {
 3  eat() { return `${this.name} eats`; }
 4};
 5const canWalk = {
 6  walk() { return `${this.name} walks`; }
 7};
 8
 9function createPerson(name) {
10  const person = { name };
11  return Object.assign(person, canEat, canWalk);
12}
13
14const p = createPerson("Dana");
15console.log(p.eat()); // "Dana eats"
16console.log(p.walk()); // "Dana walks"
  • মিক্সিন নমনীয় হলেও প্রপার্টি নামের সংঘর্ষ এবং পরীক্ষাযোগ্যতায় সতর্ক থাকতে হয়।

সাধারণ সমস্যাসমূহ ও সেরা চর্চা

এখানে কিছু সাধারণ সমস্যা এবং সেরা চর্চা উল্লেখ করা হলো।

  • মিউটেবিলিটি অবজেক্ট ডিফল্টভাবে পরিবর্তনযোগ্য (mutable)। state management যুক্ত অ্যাপ্লিকেশনে, Object.freeze বা কোনো immutable লাইব্রেরি ব্যবহার করে অপরিবর্তনীয় ডেটা স্ট্রাকচার বিবেচনা করুন।

  • প্রোটোটাইপ পলিউশন Object.assign বা লুপ দিয়ে সরাসরি বাহ্যিক ডেটা মার্জ করলে __proto__ বা constructor-এর মতো বিশেষ প্রপার্টির মাধ্যমে অপ্রত্যাশিত পার্শ্বপ্রতিক্রিয়া ও নিরাপত্তা ঝুঁকি তৈরি হতে পারে। সরাসরি মার্জ করার আগে ব্যবহারকারীর ইনপুট ফিল্টার করুন।

  • for...in-এর সমস্যাবলি** for...in প্রোটোটাইপের প্রপার্টিও এনামারেট করে, তাই hasOwnProperty দিয়ে যাচাই করুন। Object.keys ব্যবহার করা আরও স্পষ্ট।

  • শ্যালো কপির অপব্যবহার নেস্টেড অবজেক্টে পরিবর্তন এড়াতে ডীপ কপি দরকার কিনা, বিবেচনা করে নিন।

ব্যবহারিক উদাহরণ: ইমিউটেবল অবজেক্ট আপডেট প্যাটার্ন

স্টেট সরাসরি না বদলে নতুন অবজেক্ট ফেরত দেয় এমন প্যাটার্ন React ও অনুরূপ লাইব্রেরিতে বহুল ব্যবহৃত।

 1// Immutable update example
 2const state = { todos: [{ id: 1, text: "Buy milk", done: false }] };
 3
 4// Toggle todo done immutably
 5function toggleTodo(state, todoId) {
 6  return {
 7    ...state,
 8    todos: state.todos.map(t => t.id === todoId ? { ...t, done: !t.done } : t)
 9  };
10}
11
12const newState = toggleTodo(state, 1);
13console.log(state.todos[0].done); // false
14console.log(newState.todos[0].done); // true
  • এই কোডটি মূল state অবজেক্ট সরাসরি পরিবর্তন না করে নতুন state অবজেক্ট তৈরি করার একটি উদাহরণ। toggleTodo ফাংশনটি todos অ্যারে কপি করে এবং শুধু টার্গেট উপাদানটি পরিবর্তন করে একটি নতুন অবজেক্ট ফেরত দেয়, ফলে মূল state অপরিবর্তিত থাকে।
  • ইমিউটেবল আপডেটে পার্শ্বপ্রতিক্রিয়া কমে এবং স্টেট ম্যানেজমেন্ট সহজ হয়।

ব্যবহারিক উদাহরণ: নিরাপদ মার্জ (প্রোটোটাইপ পলিউশন সম্পর্কে সতর্ক থাকুন)

বাহ্যিক JSON মার্জ করার সময় __proto__ উপেক্ষা করুন, যাতে প্রোটোটাইপ পলিউশন না ঘটে।

 1// Safe merge ignoring __proto__ keys
 2function safeMerge(target, source) {
 3  for (const key of Object.keys(source)) {
 4    if (key === "__proto__" || key === "constructor") continue;
 5    target[key] = source[key];
 6  }
 7  return target;
 8}
 9
10const target = {};
11const source = JSON.parse('{"a":1,"__proto__":{"polluted":true}}');
12safeMerge(target, source);
13console.log(target.polluted); // undefined — safe
14console.log({}.polluted); // undefined — prototype not polluted
  • এ ধরনের সুরক্ষা লাইব্রেরি ও ফ্রেমওয়ার্কেও গুরুত্বপূর্ণ।

পারফরম্যান্স বিবেচনা

পারফরম্যান্সের দিক থেকে নিচের বিষয়গুলো বিবেচনা করুন:।

  • প্রোটোটাইপ ঘন ঘন পরিবর্তন (Object.setPrototypeOf) অথবা প্রপার্টির ডায়নামিক যোগ/বিয়োগ এড়িয়ে চলুন, কারণ এগুলো ইঞ্জিন অপ্টিমাইজেশন ব্যাহত করে।
  • যখন অনেক ছোট অবজেক্ট তৈরি করা হয়, তখন একই কাঠামো (একই গুণাবলির সেট) থাকা অবজেক্ট ব্যবহার করলে অপ্টিমাইজেশন আরও কার্যকর হয়।
  • ডীপ কপিতে খরচ (পারফরম্যান্স) বেশি। এসব ব্যবহার কমিয়ে দিন বা ডিফ-ভিত্তিক আপডেট ব্যবহারের কথা ভাবুন।

সারসংক্ষেপ

Object হল জাভাস্ক্রিপ্টের কেন্দ্রবিন্দু, যা অবজেক্ট তৈরি, প্রপার্টি নিয়ন্ত্রণ, ইনহেরিটেন্স, কপি এবং মিউটেবিলিটি ব্যবস্থাপনা সহ নানা সুবিধা দেয়। Object.defineProperty, Object.assign, এবং Object.freeze-এর মতো API-সমূহ বোঝা গুরুত্বপূর্ণ, এবং প্রোটোটাইপ দূষণ ও অগভীর কপি করার মত সমস্যাগুলো এড়াতে সচেতনভাবে ডিজাইন করা প্রয়োজন।

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

YouTube Video