Kelas `Object` di JavaScript

Kelas `Object` di JavaScript

Artikel ini menjelaskan kelas Object di JavaScript.

Artikel ini menjelaskan kelas Object di JavaScript, termasuk contoh praktis.

YouTube Video

Kelas Object di JavaScript

Object adalah objek bawaan yang menjadi dasar untuk semua objek JavaScript. Banyak fitur inti bahasa, seperti manajemen properti, pewarisan (rantai prototipe), enumerasi, cloning, dan pembekuan, disediakan melalui perilaku Object.

Object.create

Ada berbagai cara untuk membuat objek, dan Anda harus menggunakannya dengan tepat sesuai tujuan Anda.

Object literal (yang paling umum)

Kode berikut menunjukkan cara paling sederhana dan mudah dibaca untuk membuat sebuah objek.

 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"
  • Dalam contoh ini, properti dan metode didefinisikan menggunakan literal. Ini sederhana dan umumnya menawarkan kinerja yang unggul.

Konstruktor new Object()

Konstruktor Object jarang digunakan, tetapi berguna untuk memahami perilakunya.

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() mengembalikan objek kosong, namun literal {} lebih singkat dan lebih umum digunakan.

Menentukan prototipe dengan Object.create

Object.create digunakan untuk membuat objek dengan prototipe tertentu.

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 sangat ideal untuk desain objek berbasis pewarisan, memungkinkan Anda mengontrol rantai prototipe dengan presisi.

Atribut properti dan deskriptor

Properti memiliki atribut seperti 'value', 'writable', 'enumerable', dan 'configurable', yang dapat dikontrol secara rinci dengan Object.defineProperty.

Contoh dasar penggunaan defineProperty

Berikutnya adalah contoh mendefinisikan properti yang tidak dapat dienumerasi dan hanya-baca menggunakan 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
  • Dengan menggunakan defineProperty, Anda dapat mengontrol perilaku properti secara tepat seperti enumerasi, penulisan ulang, dan penghapusan.

Properti akses (getter / setter)

Dengan aksesors, Anda dapat menyisipkan logika pada saat properti dibaca dan ditulisi.

 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
  • Dengan getter dan setter, Anda dapat memperlakukan akses properti seperti API eksternal dan menambahkan validasi atau efek samping.

Prototipe dan pewarisan (prototype / __proto__ / Object.getPrototypeOf)

Pewarisan di JavaScript didasarkan pada rantai prototipe, bukan pada kelas. Objek dapat merujuk ke objek lain sebagai prototipe mereka.

Object.getPrototypeOf dan Object.setPrototypeOf

Contoh berikut menunjukkan cara memeriksa dan mengatur prototipe.

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 mengambil prototipe dari sebuah objek.
  • Object.setPrototypeOf mengubah prototipe dari objek yang ada, namun harus digunakan dengan hati-hati karena dapat memengaruhi performa.

Metode bawaan yang penting

Kami akan menjelaskan dengan jelas metode yang paling sering digunakan dan penting yang dipilih dari metode instan yang disediakan oleh Object.prototype, serta metode statis yang dimiliki oleh Object.

hasOwnProperty, isPrototypeOf, toString, valueOf

hasOwnProperty, isPrototypeOf, toString, dan valueOf mendefinisikan perilaku dasar dari objek.

 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 adalah metode penting untuk memeriksa apakah suatu properti ada langsung pada objek tersebut.
  • isPrototypeOf memeriksa apakah objek target memiliki dirinya sendiri sebagai prototipe.

Object.keys, Object.values, Object.entries

Object.keys, Object.values, dan Object.entries mengembalikan daftar properti enumerable milik objek itu sendiri. Metode-metode ini berguna untuk iterasi dan transformasi.

 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));
  • Metode-metode ini sering digunakan untuk iterasi dan transformasi objek.

Object.assign

Object.assign digunakan untuk menyalin secara dangkal dan menggabungkan objek. Perlu dicatat bahwa prototipe dan properti akses tidak ikut tersalin.

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)
  • Untuk objek bersarang, hanya referensinya yang disalin, sehingga Anda membutuhkan implementasi berbeda untuk kloning mendalam.

Object.freeze, Object.seal, Object.preventExtensions

Object.freeze, Object.seal, dan Object.preventExtensions mengontrol mutabilitas objek.

 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 adalah yang paling ketat; metode ini mencegah segala perubahan pada properti objek.
  • seal mencegah penambahan atau penghapusan properti, tetapi memungkinkan perubahan nilai dari properti yang sudah ada.
  • preventExtensions hanya mencegah penambahan properti baru; properti yang sudah ada masih dapat diubah atau dihapus.

Enumerabilitas objek, urutan, dan for...in / for...of

for...in mengenumerasi nama properti enumerable, namun juga menyertakan properti pada rantai prototipe, sehingga sering digunakan bersama dengan hasOwnProperty. Menggabungkan Object.keys() dengan for...of lebih aman dan membuat tujuan Anda lebih jelas.

 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}
  • Aturan enumerasi properti diatur dalam spesifikasi ECMAScript, dan dalam beberapa kasus urutan enumerasi dijamin, sementara pada kasus lain tidak demikian. Sebagai aturan umum, kunci yang diinterpretasikan sebagai angka diurutkan secara menaik, sementara kunci lain mengikuti urutan penyisipan.

Kloning dan penyalinan mendalam

Ada dua jenis penyalinan objek: penyalinan dangkal menggunakan Object.assign atau sintaks spread, dan penyalinan mendalam menggunakan metode rekursif. Penting untuk menggunakannya secara tepat sesuai dengan situasi.

Salinan dangkal (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
  • Dengan salinan dangkal, objek bersarang berbagi referensi, sehingga perubahan pada objek asli dapat mempengaruhi salinannya.

Salinan mendalam sederhana (dengan peringatan)

Menggunakan trik JSON adalah cara cepat untuk membuat salinan mendalam, tetapi memiliki kekurangan seperti kehilangan fungsi, Date, referensi sirkular, dan nilai undefined. Untuk kloning mendalam yang benar, Anda perlu menggunakan pustaka khusus.

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
  • Metode berbasis JSON nyaman untuk menangani data sederhana dengan cepat, tetapi dalam kasus umum, perilakunya bisa tidak berjalan dengan baik.

Mixin dan komposisi objek

Alih-alih pewarisan ganda, pola komposisi perilaku menggunakan mixin sering digunakan.

 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"
  • Mixin bersifat fleksibel, tetapi Anda harus berhati-hati terhadap tabrakan nama properti dan keterujian.

Kesalahan umum dan praktik terbaik

Berikut beberapa kesalahan umum dan praktik terbaik.

  • Mutabilitas Objek secara default dapat diubah (mutable). Dalam aplikasi dengan manajemen state, pertimbangkan struktur data immutable menggunakan Object.freeze atau pustaka immutable.

  • Pencemaran prototipe Menggabungkan data eksternal langsung ke objek menggunakan Object.assign atau loop dapat menyebabkan efek samping tak terduga pada properti khusus seperti __proto__ atau constructor, menimbulkan risiko keamanan. Saring input pengguna sebelum langsung menggabungkannya.

  • Kesalahan penggunaan for...in for...in juga mengenumerasi properti pada prototipe, jadi periksa dengan hasOwnProperty. Menggunakan Object.keys lebih jelas.

  • Penyalahgunaan salinan dangkal Pertimbangkan apakah Anda perlu salinan mendalam untuk mencegah perubahan pada objek bersarang memengaruhi objek asli.

Contoh Praktis: Pola Pembaruan Objek Immutable

Pola yang mengembalikan objek baru tanpa mengubah state secara langsung umum digunakan di React dan pustaka serupa.

 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
  • Kode ini adalah contoh membuat objek state baru tanpa langsung mengubah objek state yang asli. Fungsi toggleTodo menyalin array todos dan mengembalikan objek baru dengan hanya elemen target yang dimodifikasi, sehingga state yang asli tetap tidak berubah.
  • Pembaruan immutable mengurangi efek samping dan memudahkan manajemen status.

Contoh Praktis: Penggabungan Aman (Waspada Pencemaran Prototipe)

Saat menggabungkan JSON eksternal, abaikan __proto__ untuk mencegah pencemaran prototipe.

 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
  • Perlindungan semacam ini juga penting dalam pustaka dan framework.

Pertimbangan performa

Terkait dengan performa, pertimbangkan hal-hal berikut:.

  • Hindari perubahan prototipe yang sering (Object.setPrototypeOf) atau penambahan/penghapusan properti secara dinamis, karena dapat menghambat optimisasi mesin.
  • Saat membuat banyak objek kecil, optimasi menjadi lebih efektif jika Anda menggunakan objek dengan struktur yang seragam (set properti yang sama).
  • Penyalinan mendalam membutuhkan biaya tinggi. Minimalkan penggunaannya atau pertimbangkan pembaruan berbasis selisih (diff).

Ringkasan

Object adalah inti dari JavaScript, menyediakan berbagai fitur seperti pembuatan objek, kontrol properti, pewarisan, penyalinan, dan pengelolaan mutabilitas. Penting untuk memahami API seperti Object.defineProperty, Object.assign, dan Object.freeze, serta merancang dengan hati-hati untuk menghindari bahaya seperti pencemaran prototipe dan penyalinan dangkal.

Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.

YouTube Video