Kelas `Object` dalam JavaScript
Artikel ini menerangkan kelas Object dalam JavaScript.
Artikel ini menerangkan kelas Object dalam JavaScript, termasuk contoh praktikal.
YouTube Video
Kelas Object dalam JavaScript
Object ialah objek terbina dalam yang menjadi asas kepada semua objek JavaScript. Banyak ciri teras bahasa ini, seperti pengurusan sifat, pewarisan (rantai prototaip), penyenaraian, pengklonan, dan pembekuan, disediakan melalui tingkah laku Object.
Object.create
Terdapat pelbagai cara untuk mencipta objek, dan anda perlu menggunakannya mengikut tujuan anda.
Literal objek (paling biasa)
Kod berikut menunjukkan cara paling mudah dan mudah dibaca untuk mencipta 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, sifat dan kaedah ditakrifkan menggunakan literal. Ia adalah mudah dan secara amnya menawarkan prestasi yang lebih baik.
Konstruktor new Object()
Konstruktor Object jarang digunakan, tetapi memahami perilakunya adalah berguna.
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, tetapi literal{}adalah lebih pendek dan lebih biasa digunakan.
Menentukan prototaip dengan Object.create
Object.create digunakan untuk mencipta objek dengan prototaip 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.createsangat sesuai untuk reka bentuk objek berasaskan pewarisan, membolehkan anda mengawal rantai prototaip dengan lebih tepat.
Atribut dan deskriptor sifat
Setiap sifat mempunyai atribut seperti 'value', 'writable', 'enumerable', dan 'configurable', yang boleh dikawal secara terperinci dengan Object.defineProperty.
Contoh asas penggunaan defineProperty
Seterusnya ialah contoh mentakrifkan sifat yang tidak boleh dihitung 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
- Penggunaan
definePropertymembolehkan anda mengawal dengan tepat tingkah laku sifat seperti penyenaraian, pengubahan, dan penghapusan.
Sifat akses (getter / setter)
Dengan akses, anda boleh menyuntik logik semasa bacaan dan penulisan sifat.
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
getterdansetter, anda boleh mengendalikan akses sifat seperti API luaran dan menambah pemeriksaan (validasi) atau kesan sampingan.
Prototaip dan pewarisan (prototype / __proto__ / Object.getPrototypeOf)
Pewarisan dalam JavaScript adalah berdasarkan rantai prototaip, bukan pada kelas. Objek boleh merujuk kepada objek lain sebagai prototaip mereka.
Object.getPrototypeOf dan Object.setPrototypeOf
Contoh berikut menunjukkan cara untuk memeriksa dan menetapkan prototaip.
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.getPrototypeOfmendapatkan prototaip bagi sesuatu objek.Object.setPrototypeOfmengubah prototaip objek sedia ada, tetapi anda harus menggunakannya dengan berhati-hati kerana boleh menjejaskan prestasi.
Kaedah terbina dalam yang penting
Kami akan menerangkan dengan jelas kaedah yang paling biasa digunakan dan penting yang dipilih daripada kaedah-keadah contoh yang disediakan oleh Object.prototype, serta kaedah statik yang dimiliki oleh Object.
hasOwnProperty, isPrototypeOf, toString, valueOf
hasOwnProperty, isPrototypeOf, toString, dan valueOf mentakrifkan tingkah laku asas sesuatu 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
hasOwnPropertyialah kaedah penting untuk menyemak sama ada sifat berada secara langsung pada objek itu.isPrototypeOfmemeriksa sama ada objek sasaran mempunyai dirinya sebagai prototaip.
Object.keys, Object.values, Object.entries
Object.keys, Object.values, dan Object.entries mengembalikan senarai sifat milik objek yang boleh disenaraikan. Ini berguna untuk pengulangan 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));- Kaedah ini kerap digunakan untuk mengulangi dan menukar objek.
Object.assign
Object.assign digunakan untuk menyalin secara cetek dan untuk penggabungan. Ambil perhatian bahawa prototaip dan sifat akses tidak akan disalin.
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 rujukan yang disalin, jadi anda memerlukan implementasi lain untuk penyalinan mendalam.
Object.freeze, Object.seal, Object.preventExtensions
Object.freeze, Object.seal, dan Object.preventExtensions mengawal kebolehubahan 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
freezeadalah yang paling ketat; ia menghalang sebarang perubahan pada sifat objek.sealmenghalang penambahan atau penghapusan sifat, tetapi membenarkan perubahan nilai sifat yang sedia ada.preventExtensionshanya menghalang penambahan sifat baru; sifat yang sedia ada masih boleh diubah atau dipadam.
Kenumerasian objek, urutan, dan for...in / for...of
for...in menyenaraikan nama sifat yang boleh disenaraikan, tetapi ia juga termasuk sifat pada rantai prototaip, maka ia sering digunakan bersama hasOwnProperty. Menggabungkan Object.keys() dengan for...of adalah lebih selamat dan menjadikan niat 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}- Peraturan untuk penomboran sifat ditakrifkan dalam spesifikasi ECMAScript, dan terdapat kes di mana urutan disahkan dan kes di mana ia tidak dijamin. Secara umumnya, kunci yang ditafsirkan sebagai nombor akan diatur secara menaik, manakala kunci-kunci lain mengikut urutan masukan.
Pengklonan dan salinan mendalam
Terdapat dua jenis penyalinan objek: salinan cetek menggunakan Object.assign atau sintaks sebaran, dan salinan mendalam menggunakan kaedah rekursif. Adalah penting untuk menggunakannya dengan sesuai bergantung kepada situasi.
Salinan cetek (sintaks sebar / 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 cetek, objek bersarang berkongsi rujukan, jadi perubahan pada objek asal mungkin menjejaskan salinan.
Salinan mendalam yang mudah (dengan peringatan)
Menggunakan helah JSON ialah cara yang pantas untuk membuat salinan mendalam, tetapi ia mempunyai kekurangan seperti kehilangan fungsi, Date, rujukan bulat, dan nilai undefined. Untuk benar-benar melakukan pengklonan mendalam, 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
- Kaedah berasaskan JSON adalah mudah untuk mengendalikan data ringkas dengan cepat, tetapi dalam kes biasa, kelakuannya boleh menjadi tidak seperti yang diharapkan.
Mixin dan komposisi objek
Sebagai ganti pewarisan berbilang, corak penggabungan perilaku dengan 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 adalah fleksibel, tetapi anda harus berhati-hati dengan pertembungan nama sifat dan kebolehujian.
Perangkap lazim dan amalan terbaik
Berikut ialah beberapa perangkap lazim dan amalan terbaik.
-
Kebolehubahan Objek boleh diubah secara lalai. Dalam aplikasi dengan pengurusan keadaan, pertimbangkan struktur data tidak boleh diubah menggunakan
Object.freezeatau pustaka tidak boleh diubah. -
Pencemaran prototaip Menggabungkan data luaran ke dalam objek secara langsung dengan
Object.assignatau ulangan boleh menyebabkan kesan sampingan yang tidak dijangka dengan sifat khas seperti__proto__atauconstructor, sekali gus mewujudkan risiko keselamatan. Tapis input pengguna sebelum penggabungan secara langsung. -
Perangkap penggunaan
for...infor...injuga menyenaraikan sifat dari prototaip, jadi semak denganhasOwnProperty. MenggunakanObject.keyslebih jelas. -
Penyalahgunaan salinan cetek Pertimbangkan sama ada anda memerlukan salinan mendalam untuk mengelakkan perubahan pada objek bersarang daripada menjejaskan objek asal.
Contoh Praktikal: Corak Kemas Kini Objek Tidak Boleh Ubah
Corak yang mengembalikan objek baharu tanpa mengubah keadaan secara langsung lazim digunakan dalam React dan pustaka seumpamanya.
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
- Kod ini adalah contoh mencipta objek keadaan baru tanpa mengubah terus objek
stateasal. FungsitoggleTodomenyalin lariktodosdan mengembalikan objek baru dengan hanya elemen sasaran diubah, jadistateasal tidak berubah. - Kemas kini tidak boleh ubah mengurangkan kesan sampingan dan menjadikan pengurusan keadaan lebih mudah.
Contoh Praktikal: Penggabungan Selamat (Berhati-hati dengan Pencemaran Prototaip)
Apabila menggabungkan JSON luaran, abaikan __proto__ untuk mengelak pencemaran prototaip.
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 sebegini juga penting dalam pustaka dan kerangka kerja.
Pertimbangan prestasi
Dari segi prestasi, pertimbangkan perkara berikut:.
- Elakkan perubahan prototaip yang kerap (
Object.setPrototypeOf) atau penambahan/pembuangan sifat secara dinamik, kerana ia boleh menjejaskan pengoptimuman enjin JavaScript. - Apabila menjana banyak objek kecil, pengoptimuman menjadi lebih berkesan jika anda menggunakan objek dengan struktur yang seragam (set sifat yang sama).
- Salinan mendalam mahal dari segi prestasi. Kurangkan penggunaannya atau pertimbangkan menggunakan kemas kini berasaskan perbezaan (diff-based updates).
Ringkasan
Object adalah pusat kepada JavaScript, menyediakan pelbagai ciri seperti penciptaan objek, kawalan sifat, pewarisan, penyalinan dan pengurusan kebolehubahan. Adalah penting untuk memahami API seperti Object.defineProperty, Object.assign, dan Object.freeze, serta mereka bentuk dengan teliti untuk mengelakkan masalah seperti pencemaran prototaip dan penyalinan cetek.
Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.