जावास्क्रिप्ट में `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 का उपयोग करके गैर-गणनशील और केवल-पढ़ने योग्य गुणों को परिभाषित करने का अगला उदाहरण है।

 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.values, और Object.entries किसी ऑब्जेक्ट की अपनी एन्यूमेरेबल प्रॉपर्टीज़ की सूची लौटाते हैं। ये इटरेशन और ट्रांस्फॉर्मेशन के लिए उपयोगी हैं।

 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));
  • इनका अक्सर ऑब्जेक्ट्स को इटररेट और ट्रांस्फॉर्म करने के लिए उपयोग किया जाता है।

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 एन्यूमेरेबल प्रॉपर्टी नामों को सूचीबद्ध करता है, लेकिन यह प्रोटोटाइप चेन पर मौजूद प्रॉपर्टीज़ को भी शामिल करता है, इसलिए इसका अक्सर 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 या स्प्रेड सिंटैक्स का उपयोग करके सतही नकल (shallow copying), और पुनरावृत्त विधियों (recursive methods) का उपयोग करके गहरी नकल (deep copying)। स्थिति के अनुसार इनका सही तरीके से उपयोग करना महत्वपूर्ण है।

शैलो कॉपी (स्प्रेड सिंटैक्स / 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) होते हैं। स्टेट प्रबंधन वाले अनुप्रयोगों में, Object.freeze या किसी अपरिवर्तनीय लाइब्रेरी का उपयोग करके अपरिवर्तनीय डेटा संरचनाओं पर विचार करें।

  • प्रोटोटाइप पॉल्यूशन 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 ऑब्जेक्ट को सीधे बदले बिना किया गया है। toggleTodo फ़ंक्शन todos ऐरे की कॉपी बनाता है और केवल लक्षित तत्व को संशोधित करके एक नया ऑब्जेक्ट लौटाता है, जिससे मूल state अपरिवर्तित रहता है।
  • अपरिवर्तनीय (immutable) अपडेट साइड इफेक्ट्स को कम करते हैं और स्टेट मैनेजमेंट को आसान बनाते हैं।

व्यावहारिक उदाहरण: सुरक्षित मर्जिंग (प्रोटोटाइप पॉल्यूशन से सावधान रहें)

बाहरी 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) या गुणों को डायनामिक रूप से जोड़ने/हटाने से बचें, क्योंकि ये इंजन के ऑप्टिमाइज़ेशन में बाधा डालते हैं।
  • जब आप कई छोटे वस्तुओं का निर्माण करते हैं, तो यदि आप समान संरचना (एक ही गुणों का सेट) वाली वस्तुओं का उपयोग करते हैं तो अनुकूलन (optimization) अधिक प्रभावी हो जाता है।
  • डीप कॉपीिंग महंगी होती है। उनके उपयोग को न्यूनतम करें या diff-आधारित अपडेट का उपयोग करने पर विचार करें।

सारांश

Object जावास्क्रिप्ट के केंद्र में है, जो ऑब्जेक्ट निर्माण, प्रॉपर्टी नियंत्रण, इनहेरिटेंस, कॉपी और म्यूटेबिलिटी प्रबंधन जैसी कई सुविधाएँ प्रदान करता है। Object.defineProperty, Object.assign और Object.freeze जैसी APIs को समझना और प्रोटोटाइप पॉल्यूशन और शैलो कॉपिंग जैसी समस्याओं से बचने के लिए सावधानीपूर्वक डिज़ाइन करना महत्वपूर्ण है।

आप हमारे YouTube चैनल पर Visual Studio Code का उपयोग करके ऊपर दिए गए लेख के साथ आगे बढ़ सकते हैं। कृपया YouTube चैनल को भी देखें।

YouTube Video