JavaScripti loomine - kuidas objekte JS-is määratleda

Objektid on objektiorienteeritud programmeerimise peamine kapseldamise üksus. Selles artiklis kirjeldan JavaScripti objektide loomiseks mitut viisi. Nemad on:

  • Objekti sõnasõnaline
  • Object.create ()
  • Klassid
  • Tehase funktsioonid

Objekti sõnasõnaline

Esiteks peame eristama andmestruktuure objektobjektidest. Andmestruktuurides on avalikud andmed ja käitumine puudub. See tähendab, et neil pole meetodeid.

Selliseid objekte saame hõlpsasti luua, kasutades objekti sõnasõnalist süntaksit. See näeb välja selline:

const product = { name: 'apple', category: 'fruits', price: 1.99 } console.log(product);

JavaScripti objektid on võtme-väärtuse paaride dünaamilised kogumid. Võti on alati string ja see peab kogu ainulaadne olema. Väärtus võib olla primitiiv, objekt või isegi funktsioon.

Atribuudile pääseme juurde punkti või ruudu abil.

console.log(product.name); //"apple" console.log(product["name"]); //"apple"

Siin on näide, kus väärtus on teine ​​objekt.

const product = { name: 'apple', category: 'fruits', price: 1.99, nutrients : { carbs: 0.95, fats: 0.3, protein: 0.2 } }

Vara väärtus carbson uus objekt. Siit saate teada, kuidas pääseme carbskinnistule ligi.

console.log(product.nutrients.carbs); //0.95

Lühike vara nimed

Vaatleme juhtumit, kus meie omaduste väärtused on salvestatud muutujatesse.

const name = 'apple'; const category = 'fruits'; const price = 1.99; const product = { name: name, category: category, price: price }

JavaScript toetab nn lühikeste omaduste nimesid. See võimaldab meil luua objekti, kasutades ainult muutuja nime. See loob samanimelise atribuudi. Järgmine objekti literaal on samaväärne eelmisega.

const name = 'apple'; const category = 'fruits'; const price = 1.99; const product = { name, category, price }

Object.create

Järgmisena vaatame, kuidas objekte käitumisega, objektorienteeritud objekte rakendada.

JavaScriptil on nn prototüübisüsteem, mis võimaldab objektide vahel käitumist jagada. Peamine mõte on luua tavalise käitumisega objekt nimega prototüüp ja kasutada seda siis uute objektide loomisel.

Prototüübisüsteem võimaldab meil luua objekte, mis pärivad käitumise teistelt objektidelt.

Koostame prototüübi objekti, mis võimaldab meil lisada tooteid ja saada ostuhinnast koguhind.

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); } }

Pange tähele, et seekord on vara väärtus addProductfunktsioon. Eelmise objekti võime kirjutada ka lühema vormi abil, mida nimetatakse kiirmenetluse süntaksiks.

const cartPrototype = { addProduct(product){/*code*/}, getTotalPrice(){/*code*/} }

See cartPrototypeon prototüüpobjekt, mis hoiab tavalist käitumist esindatuna kahe meetodiga addProductja getTotalPrice. Seda saab kasutada teiste objektide loomiseks, mis selle käitumise pärivad.

const cart = Object.create(cartPrototype); cart.addProduct({name: 'orange', price: 1.25}); cart.addProduct({name: 'lemon', price: 1.75}); console.log(cart.getTotalPrice()); //3

cartObjektil on cartPrototypeoma prototüüp. See pärib sellest käitumise. carton varjatud omadus, mis osutab prototüübi objektile.

Kui kasutame meetodit objektil, otsitakse seda meetodit kõigepealt objektil endal, mitte selle prototüübil.

seda

Pange tähele, et thisobjekti andmetele juurde pääsemiseks ja nende muutmiseks kasutame spetsiaalset märksõna .

Pidage meeles, et funktsioonid on JavaScripti iseseisvad käitumisüksused. Need ei ole tingimata osa objektist. Kui nad on, peab meil olema viide, mis võimaldab funktsioonil pääseda juurde teistele sama objekti liikmetele. thison funktsiooni kontekst. See annab juurdepääsu teistele omadustele.

Andmed

Võite mõelda, miks me pole productsprototüübi enda omadust määratlenud ja initsialiseerinud .

Me ei tohiks seda teha. Käitumise, mitte andmete jagamiseks tuleks kasutada prototüüpe. Andmete jagamine toob kaasa sama toote olemasolu mitmel ostukorvi objektil. Mõelge allolevale koodile:

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

Nii cart1ja cart2objektid pärib levinud käitumine alates cartPrototypejagada ka samu andmeid. Me ei taha seda. Käitumise, mitte andmete jagamiseks tuleks kasutada prototüüpe.

Klass

Prototüübisüsteem ei ole tavaline objektide ehitamise viis. Arendajad tunnevad objektide ehitamist klassiväliselt paremini.

Klassi süntaks võimaldab tuttavamat viisi ühist käitumist jagavate objektide loomiseks. See loob endiselt stseeni taga sama prototüübi, kuid süntaks on selgem ja väldime ka eelmist andmetega seotud probleemi. Klass pakub konkreetse koha, et määratleda iga objekti jaoks eraldi olevad andmed.

Siin on sama objekt, mis on loodud klassi suhkru süntaksiga:

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.

Teine võimalus on määratleda objektid sulgude kogumid.

Lisateavet sulgemiste ja funktsioonide programmeerimise tehnikate kohta vaadake minu raamatusarja Funktsionaalne programmeerimine JavaScripti ja Reactiga.

Functional Programming JavaScripti raamat on tulemas.