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 βιβλίο βγαίνει.