JavaScript Δημιουργία αντικειμένου - Πώς να ορίσετε αντικείμενα στο JS
Τα αντικείμενα είναι η κύρια μονάδα ενθυλάκωσης στον Προγραμματισμό Αντικειμενοστρεφής. Σε αυτό το άρθρο, θα περιγράψω διάφορους τρόπους δημιουργίας αντικειμένων σε JavaScript Αυτοί είναι:
- Αντικείμενο κυριολεκτικά
- Object.create ()
- Μαθήματα
- Εργοστασιακές λειτουργίες
Αντικείμενο κυριολεκτικά
Πρώτον, πρέπει να κάνουμε διάκριση μεταξύ δομών δεδομένων και αντικειμενοστρεφών αντικειμένων. Οι δομές δεδομένων έχουν δημόσια δεδομένα και καμία συμπεριφορά. Αυτό σημαίνει ότι δεν έχουν μεθόδους.
Μπορούμε εύκολα να δημιουργήσουμε τέτοια αντικείμενα χρησιμοποιώντας την κυριολεκτική σύνταξη αντικειμένων. Μοιάζει με αυτό:
const product = { name: 'apple', category: 'fruits', price: 1.99 } console.log(product);
Τα αντικείμενα στο JavaScript είναι δυναμικές συλλογές ζευγών κλειδιών-τιμών. Το κλειδί είναι πάντα μια συμβολοσειρά και πρέπει να είναι μοναδικό στη συλλογή. Η τιμή μπορεί να είναι ένα πρωτόγονο, ένα αντικείμενο ή ακόμα και μια συνάρτηση.
Μπορούμε να αποκτήσουμε πρόσβαση σε μια ιδιότητα χρησιμοποιώντας την κουκκίδα ή την τετραγωνική σημείωση.
console.log(product.name); //"apple" console.log(product["name"]); //"apple"
Εδώ είναι ένα παράδειγμα όπου η τιμή είναι ένα άλλο αντικείμενο.
const product = { name: 'apple', category: 'fruits', price: 1.99, nutrients : { carbs: 0.95, fats: 0.3, protein: 0.2 } }
Η τιμή της carbs
ιδιότητας είναι ένα νέο αντικείμενο. Εδώ είναι πώς μπορούμε να έχουμε πρόσβαση στην carbs
ιδιοκτησία.
console.log(product.nutrients.carbs); //0.95
Ονόματα ιδιοκτησίας Shorthand
Εξετάστε την περίπτωση όπου αποθηκεύουμε τις τιμές των ιδιοτήτων μας σε μεταβλητές.
const name = 'apple'; const category = 'fruits'; const price = 1.99; const product = { name: name, category: category, price: price }
Το JavaScript υποστηρίζει αυτά που ονομάζονται στενά ονόματα ιδιοτήτων. Μας επιτρέπει να δημιουργήσουμε ένα αντικείμενο χρησιμοποιώντας μόνο το όνομα της μεταβλητής. Θα δημιουργήσει μια ιδιότητα με το ίδιο όνομα. Το επόμενο κυριολεκτικό αντικείμενο είναι ισοδύναμο με το προηγούμενο.
const name = 'apple'; const category = 'fruits'; const price = 1.99; const product = { name, category, price }
Object.create
Στη συνέχεια, ας δούμε πώς να υλοποιήσουμε αντικείμενα με συμπεριφορά, αντικειμενοστραφή αντικείμενα.
Το JavaScript έχει αυτό που ονομάζεται πρωτότυπο σύστημα που επιτρέπει την κοινή χρήση συμπεριφοράς μεταξύ αντικειμένων. Η κύρια ιδέα είναι να δημιουργήσετε ένα αντικείμενο που ονομάζεται πρωτότυπο με μια κοινή συμπεριφορά και στη συνέχεια να το χρησιμοποιήσετε κατά τη δημιουργία νέων αντικειμένων.
Το πρωτότυπο σύστημα μας επιτρέπει να δημιουργήσουμε αντικείμενα που κληρονομούν συμπεριφορά από άλλα αντικείμενα.
Ας δημιουργήσουμε ένα πρωτότυπο αντικείμενο που μας επιτρέπει να προσθέσουμε προϊόντα και να λάβουμε τη συνολική τιμή από ένα καλάθι αγορών.
const cartPrototype = { addProduct: function(product){ if(!this.products){ this.products = [product] } else { this.products.push(product); } }, getTotalPrice: function(){ return this.products.reduce((total, p) => total + p.price, 0); } }
Παρατηρήστε ότι αυτή τη φορά η τιμή της ιδιότητας addProduct
είναι μια συνάρτηση. Μπορούμε επίσης να γράψουμε το προηγούμενο αντικείμενο χρησιμοποιώντας μια συντομότερη φόρμα που ονομάζεται σύνταξη μεθόδου στενογραφίας.
const cartPrototype = { addProduct(product){/*code*/}, getTotalPrice(){/*code*/} }
Το αντικείμενο cartPrototype
είναι το πρωτότυπο που διατηρεί την κοινή συμπεριφορά που αντιπροσωπεύεται από δύο μεθόδους addProduct
και getTotalPrice
. Μπορεί να χρησιμοποιηθεί για τη δημιουργία άλλων αντικειμένων που κληρονομούν αυτήν τη συμπεριφορά.
const cart = Object.create(cartPrototype); cart.addProduct({name: 'orange', price: 1.25}); cart.addProduct({name: 'lemon', price: 1.75}); console.log(cart.getTotalPrice()); //3
Το cart
αντικείμενο έχει cartPrototype
ως πρωτότυπο. Κληρονομεί τη συμπεριφορά από αυτήν. cart
έχει μια κρυφή ιδιότητα που δείχνει το πρωτότυπο αντικείμενο.
Όταν χρησιμοποιούμε μια μέθοδο σε ένα αντικείμενο, αυτή η μέθοδος πραγματοποιείται πρώτα αναζήτηση στο ίδιο το αντικείμενο και όχι στο πρωτότυπό του.
Αυτό
Λάβετε υπόψη ότι χρησιμοποιούμε μια ειδική λέξη-κλειδί που ονομάζεται this
πρόσβαση και τροποποίηση των δεδομένων στο αντικείμενο.
Να θυμάστε ότι οι συναρτήσεις είναι ανεξάρτητες μονάδες συμπεριφοράς στο JavaScript. Δεν αποτελούν απαραίτητα μέρος ενός αντικειμένου. Όταν είναι, πρέπει να έχουμε μια αναφορά που επιτρέπει στη λειτουργία να έχει πρόσβαση σε άλλα μέλη στο ίδιο αντικείμενο. this
είναι το πλαίσιο λειτουργίας. Δίνει πρόσβαση σε άλλες ιδιότητες.
Δεδομένα
Ίσως αναρωτιέστε γιατί δεν έχουμε ορίσει και αρχικοποιήσει την products
ιδιότητα στο ίδιο το πρωτότυπο αντικείμενο.
Δεν πρέπει να το κάνουμε αυτό. Τα πρωτότυπα πρέπει να χρησιμοποιούνται για κοινή χρήση συμπεριφοράς και όχι δεδομένων. Η κοινή χρήση δεδομένων θα έχει τα ίδια προϊόντα σε πολλά αντικείμενα καλαθιού. Εξετάστε τον παρακάτω κώδικα:
const cartPrototype = { products:[], addProduct: function(product){ this.products.push(product); }, getTotalPrice: function(){} } const cart1 = Object.create(cartPrototype); cart1.addProduct({name: 'orange', price: 1.25}); cart1.addProduct({name: 'lemon', price: 1.75}); console.log(cart1.getTotalPrice()); //3 const cart2 = Object.create(cartPrototype); console.log(cart2.getTotalPrice()); //3
Τόσο τα αντικείμενα όσο cart1
και τα cart2
αντικείμενα που κληρονομούν την κοινή συμπεριφορά από cartPrototype
τα ίδια μοιράζονται επίσης τα ίδια δεδομένα. Δεν το θέλουμε αυτό. Τα πρωτότυπα πρέπει να χρησιμοποιούνται για κοινή χρήση συμπεριφοράς και όχι δεδομένων.
Τάξη
Το πρωτότυπο σύστημα δεν είναι ένας κοινός τρόπος κατασκευής αντικειμένων. Οι προγραμματιστές είναι πιο εξοικειωμένοι με την κατασκευή αντικειμένων εκτός τάξεων.
Η σύνταξη τάξης επιτρέπει έναν πιο οικείο τρόπο δημιουργίας αντικειμένων που μοιράζονται μια κοινή συμπεριφορά. Δημιουργεί ακόμα το ίδιο πρωτότυπο πίσω από τη σκηνή, αλλά η σύνταξη είναι σαφέστερη και αποφεύγουμε επίσης το προηγούμενο ζήτημα που σχετίζεται με τα δεδομένα. Η τάξη προσφέρει ένα συγκεκριμένο μέρος για τον καθορισμό των δεδομένων που είναι ξεχωριστά για κάθε αντικείμενο.
Εδώ είναι το ίδιο αντικείμενο που δημιουργήθηκε χρησιμοποιώντας τη σύνταξη ζάχαρης κατηγορίας:
class Cart{ constructor(){ this.products = []; } addProduct(product){ this.products.push(product); } getTotalPrice(){ return this.products.reduce((total, p) => total + p.price, 0); } } const cart = new Cart(); cart.addProduct({name: 'orange', price: 1.25}); cart.addProduct({name: 'lemon', price: 1.75}); console.log(cart.getTotalPrice()); //3 const cart2 = new Cart(); console.log(cart2.getTotalPrice()); //0
Notice that the class has a constructor method that initialized that data distinct for each new object. The data in the constructor is not shared between instances. In order to create a new instance, we use the new
keyword.
I think the class syntax is more clear and familiar to most developers. Nevertheless, it does a similar thing, it creates a prototype with all the methods and uses it to define new objects. The prototype can be accessed with Cart.prototype
.
It turns out that the prototype system is flexible enough to allow the class syntax. So the class system can be simulated using the prototype system.
Private Properties
The only thing is that the products
property on the new object is public by default.
console.log(cart.products); //[{name: "orange", price: 1.25} // {name: "lemon", price: 1.75}]
We can make it private using the hash #
prefix.
Private properties are declared with #name
syntax. #
is a part of the property name itself and should be used for declaring and accessing the property. Here is an example of declaring products
as a private property:
class Cart{ #products constructor(){ this.#products = []; } addProduct(product){ this.#products.push(product); } getTotalPrice(){ return this.#products.reduce((total, p) => total + p.price, 0); } } console.log(cart.#products); //Uncaught SyntaxError: Private field '#products' must be declared in an enclosing class
Factory Functions
Another option is to create objects as collections of closures.
Closure is the ability of a function to access variables and parameters from the other function even after the outer function has executed. Take a look at the cart
object built with what is called a factory function.
function Cart() { const products = []; function addProduct(product){ products.push(product); } function getTotalPrice(){ return products.reduce((total, p) => total + p.price, 0); } return { addProduct, getTotalPrice } } const cart = Cart(); cart.addProduct({name: 'orange', price: 1.25}); cart.addProduct({name: 'lemon', price: 1.75}); console.log(cart.getTotalPrice()); //3
addProduct
and getTotalPrice
are two inner functions accessing the variable products
from their parent. They have access to the products
variable event after the parent Cart
has executed. addProduct
and getTotalPrice
are two closures sharing the same private variable.
Cart
is a factory function.
The new object cart
created with the factory function has the products
variable private. It cannot be accessed from the outside.
console.log(cart.products); //undefined
Factory functions don’t need the new
keyword but you can use it if you want. It will return the same object no matter if you use it or not.
Recap
Usually, we work with two types of objects, data structures that have public data and no behavior and object-oriented objects that have private data and public behavior.
Data structures can be easily built using the object literal syntax.
JavaScript offers two innovative ways of creating object-oriented objects. The first is using a prototype object to share the common behavior. Objects inherit from other objects. Classes offer a nice sugar syntax to create such objects.
Η άλλη επιλογή είναι να ορίσετε αντικείμενα είναι συλλογές κλεισίματος.
Για περισσότερες πληροφορίες σχετικά με το κλείσιμο και τις τεχνικές προγραμματισμού λειτουργίας, ανατρέξτε στη σειρά βιβλίων μου Λειτουργικός προγραμματισμός με JavaScript και React.
Η Λειτουργική προγραμματισμού σε JavaScript βιβλίο βγαίνει.