Ang klase ng `Object` sa JavaScript

Ang klase ng `Object` sa JavaScript

Ipinapaliwanag ng artikulong ito ang klase ng Object sa JavaScript.

Ipinapaliwanag ng artikulong ito ang klase ng Object sa JavaScript, kasama ang mga praktikal na halimbawa.

YouTube Video

Ang klase ng Object sa JavaScript

Ang Object ay isang built-in na object na nagsisilbing base ng lahat ng mga object sa JavaScript. Marami sa mga pangunahing tampok ng wika, tulad ng pamamahala ng ari-arian, mana (prototype chain), pag-enumerate, pag-clone, at pag-freeze, ay ibinibigay sa pamamagitan ng pag-uugali ng Object.

Object.create

Maraming paraan upang lumikha ng mga object, at dapat piliin ang angkop na paraan depende sa iyong layunin.

Object literal (pinakakaraniwan)

Ipinapakita ng sumusunod na code ang pinaka-simpleng at pinaka-nababasang paraan para lumikha ng object.

 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"
  • Sa halimbawa na ito, ang mga property at metodo ay tinutukoy gamit ang mga literal. Ito ay simple at karaniwang nag-aalok ng mas mataas na pagganap.

new Object() constructor

Bihirang gamitin ang Object constructor, ngunit mahalagang maunawaan ang kanyang pag-uugali.

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() ay nagbabalik ng empty object, ngunit mas maikli at mas karaniwan ang literal na {}.

Pagtatakda ng prototype gamit ang Object.create

Ginagamit ang Object.create upang lumikha ng object na may tinukoy na prototype.

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
  • Ang Object.create ay mainam para sa disenyo ng object na nakabatay sa inheritance, dahil hinahayaan kang kontrolin nang eksakto ang prototype chain.

Mga katangian at deskriptor ng property

Ang mga property ay may mga katangian tulad ng 'value', 'writable', 'enumerable', at 'configurable' na maaaring kontrolin nang detalyado gamit ang Object.defineProperty.

Pangunahing halimbawa ng paggamit ng defineProperty

Susunod ay isang halimbawa ng pagtukoy ng hindi na-enumerate at read-only na mga property gamit ang 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
  • Ang paggamit ng defineProperty ay nagbibigay-daan sa iyo na eksaktong kontrolin ang kilos ng mga property gaya ng pag-enumerate, pag-rewrite, at pagtanggal.

Mga Accessor Property (getter / setter)

Sa pamamagitan ng accessors, maaari kang maglagay ng lohika sa pagbasa at pagsulat ng property.

 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
  • Gamit ang getter at setter, maaari mong ituring ang property access na parang external API at magdagdag ng validation o iba pang epekto.

Prototype at inheritance (prototype / __proto__ / Object.getPrototypeOf)

Ang inheritance sa JavaScript ay nakabatay sa prototype chain, hindi sa mga klase. Maaaring sumangguni ang mga object sa ibang object bilang kanilang mga prototype.

Object.getPrototypeOf at Object.setPrototypeOf

Ipinapakita ng susunod na halimbawa kung paano i-inspeksyunin at itakda ang mga prototype.

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"
  • Ang Object.getPrototypeOf ay kumukuha ng prototype ng isang object.
  • Binabago ng Object.setPrototypeOf ang prototype ng umiiral na object, ngunit gamitin ito nang maingat dahil maaaring maapektuhan ang performance.

Mahalagang mga built-in na pamamaraan

Ipapaliwanag namin nang malinaw ang mga pinaka-madalas gamitin at mahahalagang pamamaraan na pinili mula sa mga instance methods na ibinibigay ng Object.prototype, pati na rin ang mga static methods na pagmamay-ari ng Object.

hasOwnProperty, isPrototypeOf, toString, valueOf

Ang hasOwnProperty, isPrototypeOf, toString, at valueOf ay tumutukoy sa mga pangunahing kilos ng mga object.

 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
  • Ang hasOwnProperty ay mahalagang method upang suriin kung ang property ay direktang pagmamay-ari ng object.
  • Ang isPrototypeOf ay tinitingnan kung ang target na object ay may sarili bilang prototype.

Object.keys, Object.values, Object.entries

Object.keys, Object.values, at Object.entries ay nagbabalik ng mga listahan ng sariling enumerable properties ng object. Nakakatulong ang mga ito sa iteration at transformation.

 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));
  • Madalas itong ginagamit sa pag-ikot at pagbabago ng mga object.

Object.assign

Ginagamit ang Object.assign para sa mababaw na pagkopya at pagsasama. Tandaan na ang mga prototype at accessor property ay hindi nakokopya.

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)
  • Para sa mga nested na object, tanging reference lang ang kinokopya kaya kailangan ng ibang paraan para sa deep cloning.

Object.freeze, Object.seal, Object.preventExtensions

Ang Object.freeze, Object.seal, at Object.preventExtensions ay kumokontrol sa mutability ng mga object.

 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
  • Ang freeze ang pinakastikto; pinipigilan nitong mabago ang anumang property ng object.
  • Ang seal ay pumipigil sa pagdagdag o pagtanggal ng mga property, ngunit pinapayagan ang pagbabago ng mga umiiral na halaga ng property.
  • Ang preventExtensions ay humahadlang lamang sa pagdagdag ng bagong mga property; ang umiiral na mga property ay maaari pa ring baguhin o tanggalin.

Enumerability ng object, pagkakasunod-sunod, at for...in / for...of

Ang for...in ay nag-eenumerate ng mga enumerable property name, ngunit pati na rin ang mga property mula sa prototype chain, kaya madalas itong ginagamit kasama ng hasOwnProperty. Mas ligtas ang pagsasama ng Object.keys() sa for...of at mas malinaw ang iyong layunin.

 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}
  • Ang mga patakaran para sa enumeration ng property ay tinukoy sa ECMAScript specification, at may mga pagkakataon na garantisado ang order ng enumeration at kung minsan ay hindi naman. Bilang pangkalahatang tuntunin, ang mga key na binibigyang-kahulugan bilang mga numero ay isinaayos ayon sa pataas na pagkakasunod-sunod, habang ang ibang mga key ay sumusunod sa pagkakasunod ng pagpasok.

Pagkopya at deep copying

May dalawang uri ng pagkopya ng object: shallow copying gamit ang Object.assign o ang spread syntax, at deep copying gamit ang recursive na mga pamamaraan. Mahalaga na gamitin ang mga ito nang naaayon depende sa sitwasyon.

Mababaw na pagkopya (spread syntax / 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
  • Sa mababaw na pagkopya, magkasalo ng reference ang mga nested object, kaya ang pagbabago sa orihinal ay makakaapekto rin sa kopya.

Simpleng deep copy (may babala)

Ang paggamit ng JSON trick ay mabilis na paraan para sa deep copy, ngunit may kahinaan tulad ng pagkawala ng mga function, Date, circular reference, at undefined values. Para sa tunay na deep cloning, dapat gumamit ng espesyal na library.

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
  • Ang mga pamamaraan na nakabatay sa JSON ay maginhawa para sa mabilisang paghawak ng simpleng datos, ngunit sa karaniwang mga kaso, maaaring masira ang kanilang pag-uugali.

Mixins at object composition

Sa halip na multiple inheritance, kadalasang ginagamit ang pattern ng pagtatambal ng mga gawi gamit ang mixins.

 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"
  • Ang mixins ay flexible, ngunit kailangang pag-ingatan ang pagbangga ng pangalan ng property at ang testability.

Karaniwang bitag at pinakamahusay na kasanayan

Narito ang ilang karaniwang bitag at pinakamahusay na kasanayan.

  • Mutability Ang mga object ay mutable bilang default. Sa mga application na may state management, ikonsidera ang paggamit ng immutable na mga data structure gamit ang Object.freeze o isang immutable na library.

  • Prototype Pollution Ang pag-merge ng external data sa isang object gamit ang Object.assign o loops ay maaaring magdulot ng hindi inaasahang epekto sa mga espesyal na property gaya ng __proto__ o constructor, na nagdudulot ng panganib sa seguridad. I-filter ang input ng user bago direktang i-merge.

  • Mga Bitag ng for...in Ang for...in ay nag-eenumerate din ng mga property mula sa prototype, kaya siguraduhing suriin gamit ang hasOwnProperty. Mas malinaw ang paggamit ng Object.keys.

  • Maling Paggamit ng Shallow Copy Isaalang-alang kung kailangan ng deep copying upang maiwasan ang pagbabago sa nested na object na makaapekto sa orihinal.

Praktikal na Halimbawa: Pattern ng Pag-update ng Immutable na Object

Ang mga pattern na nagbabalik ng bagong object nang hindi direktang binabago ang state ay karaniwang ginagamit sa React at katulad na mga library.

 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
  • Ang code na ito ay halimbawa ng paglikha ng bagong state object nang hindi direktang binabago ang orihinal na state object. Kinokopya ng function na toggleTodo ang todos array at nagbabalik ng bagong object kung saan tanging ang target na elemento lamang ang binago, kaya ang orihinal na state ay nananatiling hindi nagbago.
  • Ang immutable na pag-update ay nagpapababa ng side effects at nagpapadali sa pamamahala ng state.

Praktikal na Halimbawa: Ligtas na Pagsasama (Mag-ingat sa Prototype Pollution)

Kapag nag-merge ng external JSON, i-ignore ang __proto__ upang maiwasan ang prototype pollution.

 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
  • Mahalaga rin ang ganitong uri ng proteksyon sa mga library at framework.

Mga Pagsasaalang-alang sa Performance

Tungkol sa performance, isaalang-alang ang mga sumusunod:.

  • Iwasan ang madalas na pagbabago ng prototype (Object.setPrototypeOf) o dynamic na pagdagdag/pag-alis ng property, dahil nakakaapekto ito sa optimization ng engine.
  • Kapag gumagawa ng maraming maliliit na object, mas epektibo ang optimization kung gagamit ka ng mga object na may iisang istraktura (parehong set ng mga katangian).
  • Mahal ang deep copying. Bawasan ang paggamit nito o isaalang-alang ang diff-based na pag-update.

Buod

Mahalaga ang Object sa JavaScript, nagbibigay ito ng iba't ibang feature tulad ng paglikha ng object, kontrol ng property, inheritance, pagkopya, at pamamahala ng mutability. Mahalagang maunawaan ang mga API tulad ng Object.defineProperty, Object.assign, at Object.freeze, at magdisenyo nang maingat upang maiwasan ang mga bitag tulad ng prototype pollution at shallow copying.

Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.

YouTube Video