Sementara banyak orang di sini mengatakan tidak ada cara terbaik untuk membuat objek, ada alasan mengapa ada begitu banyak cara untuk membuat objek dalam JavaScript, pada 2019, dan ini ada hubungannya dengan kemajuan JavaScript melalui berbagai iterasi yang berbeda. rilis EcmaScript dating kembali ke tahun 1997.
Sebelum ECMAScript 5, hanya ada dua cara untuk membuat objek: fungsi konstruktor atau notasi literal (alternatif yang lebih baik untuk Obyek baru ()). Dengan notasi fungsi konstruktor Anda membuat objek yang dapat dipakai menjadi beberapa instance (dengan kata kunci baru), sedangkan notasi literal memberikan objek tunggal, seperti singleton.
// constructor function
function Person() {};
// literal notation
var Person = {};
Terlepas dari metode yang Anda gunakan, objek JavaScript hanyalah properti pasangan nilai kunci:
// Method 1: dot notation
obj.firstName = 'Bob';
// Method 2: bracket notation. With bracket notation, you can use invalid characters for a javascript identifier.
obj['lastName'] = 'Smith';
// Method 3: Object.defineProperty
Object.defineProperty(obj, 'firstName', {
value: 'Bob',
writable: true,
configurable: true,
enumerable: false
})
// Method 4: Object.defineProperties
Object.defineProperties(obj, {
firstName: {
value: 'Bob',
writable: true
},
lastName: {
value: 'Smith',
writable: false
}
});
Dalam versi awal JavaScript, satu-satunya cara nyata untuk meniru warisan berbasis kelas adalah dengan menggunakan fungsi konstruktor. fungsi konstruktor adalah fungsi khusus yang dipanggil dengan kata kunci 'baru'. Dengan konvensi, pengenal fungsi dikapitalisasi, albiet tidak diperlukan. Di dalam konstruktor, kami merujuk pada kata kunci 'ini' untuk menambahkan properti ke objek yang fungsi konstruktor buat secara implisit. Fungsi konstruktor secara implisit mengembalikan objek baru dengan properti yang dihuni kembali ke fungsi panggilan secara implisit, kecuali jika Anda secara eksplisit menggunakan kata kunci pengembalian dan mengembalikan sesuatu yang lain.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.sayName = function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var bob = new Person("Bob", "Smith");
bob instanceOf Person // true
Ada masalah dengan metode sayName. Biasanya, dalam bahasa pemrograman berbasis Object-Oriented Class, Anda menggunakan kelas sebagai pabrik untuk membuat objek. Setiap objek akan memiliki variabel instance sendiri, tetapi akan memiliki pointer ke metode yang didefinisikan dalam cetak biru kelas. Sayangnya, saat menggunakan fungsi konstruktor JavaScript, setiap kali dipanggil, ia akan mendefinisikan properti sayName baru pada objek yang baru dibuat. Jadi setiap objek akan memiliki properti sayName yang unik. Ini akan menghabiskan lebih banyak sumber daya memori.
Selain meningkatkan sumber daya memori, mendefinisikan metode di dalam fungsi konstruktor menghilangkan kemungkinan pewarisan. Sekali lagi, metode ini akan didefinisikan sebagai properti pada objek yang baru dibuat dan tidak ada objek lain, sehingga pewarisan tidak dapat berfungsi seperti itu. Oleh karena itu, JavaScript menyediakan rantai prototipe sebagai bentuk warisan, menjadikan JavaScript sebagai bahasa prototipe.
Jika Anda memiliki orang tua dan orang tua membagikan banyak properti anak, maka anak tersebut harus mewarisi properti tersebut. Sebelum ES5, hal itu dilakukan sebagai berikut:
function Parent(eyeColor, hairColor) {
this.eyeColor = eyeColor;
this.hairColor = hairColor;
}
Parent.prototype.getEyeColor = function() {
console.log('has ' + this.eyeColor);
}
Parent.prototype.getHairColor = function() {
console.log('has ' + this.hairColor);
}
function Child(firstName, lastName) {
Parent.call(this, arguments[2], arguments[3]);
this.firstName = firstName;
this.lastName = lastName;
}
Child.prototype = Parent.prototype;
var child = new Child('Bob', 'Smith', 'blue', 'blonde');
child.getEyeColor(); // has blue eyes
child.getHairColor(); // has blonde hair
Cara kami menggunakan rantai prototipe di atas memiliki kekhasan. Karena prototipe adalah tautan langsung, dengan mengubah properti dari satu objek dalam rantai prototipe, Anda juga akan mengubah properti yang sama dari objek lain. Jelas, mengubah metode warisan anak seharusnya tidak mengubah metode orang tua. Object.create menyelesaikan masalah ini dengan menggunakan polyfill. Dengan demikian, dengan Object.create, Anda dapat dengan aman memodifikasi properti anak dalam rantai prototipe tanpa memengaruhi properti yang sama induknya dalam rantai prototipe.
ECMAScript 5 memperkenalkan Object.create untuk menyelesaikan bug yang disebutkan di atas dalam fungsi konstruktor untuk pembuatan objek. Metode Object.create () MENCIPTAKAN objek baru, menggunakan objek yang ada sebagai prototipe objek yang baru dibuat. Karena objek baru dibuat, Anda tidak lagi memiliki masalah di mana memodifikasi properti anak dalam rantai prototipe akan mengubah referensi orang tua ke properti dalam rantai.
var bobSmith = {
firstName: "Bob",
lastName: "Smith",
sayName: function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var janeSmith = Object.create(bobSmith, {
firstName : { value: "Jane" }
})
console.log(bobSmith.sayName()); // My name is Bob Smith
console.log(janeSmith.sayName()); // My name is Jane Smith
janeSmith.__proto__ == bobSmith; // true
janeSmith instanceof bobSmith; // Uncaught TypeError: Right-hand side of 'instanceof' is not callable. Error occurs because bobSmith is not a constructor function.
Sebelum ES6, berikut adalah pola kreasi umum untuk menggunakan fungsi constructor dan Object.create:
const View = function(element){
this.element = element;
}
View.prototype = {
getElement: function(){
this.element
}
}
const SubView = function(element){
View.call(this, element);
}
SubView.prototype = Object.create(View.prototype);
Sekarang Object.create ditambah dengan fungsi konstruktor telah banyak digunakan untuk pembuatan objek dan pewarisan dalam JavaScript. Namun, ES6 memperkenalkan konsep kelas, yang utamanya adalah sintaksis gula atas warisan berbasis prototipe JavaScript yang ada. Sintaks kelas tidak memperkenalkan model pewarisan berorientasi objek baru ke JavaScript. Dengan demikian, JavaScript tetap merupakan bahasa prototipe.
Kelas ES6 membuat pewarisan jauh lebih mudah. Kami tidak lagi harus menyalin fungsi prototipe kelas induk secara manual dan mengatur ulang konstruktor kelas anak.
// create parent class
class Person {
constructor (name) {
this.name = name;
}
}
// create child class and extend our parent class
class Boy extends Person {
constructor (name, color) {
// invoke our parent constructor function passing in any required parameters
super(name);
this.favoriteColor = color;
}
}
const boy = new Boy('bob', 'blue')
boy.favoriteColor; // blue
Secara keseluruhan, 5 strategi berbeda dari Pembuatan Objek dalam JavaScript ini bertepatan dengan evolusi standar EcmaScript.