JavaScript Objektum létrehozása - Hogyan definiálhatók objektumok JS-ben

Az objektumok a kapszulázás fő egysége az objektum-orientált programozásban. Ebben a cikkben az objektumok JavaScript-ben történő létrehozásának számos módját ismertetem. Ők:

  • Objektum szó szerint
  • Object.create ()
  • Osztályok
  • Gyári funkciók

Object Literal

Először is különbséget kell tennünk az adatstruktúrák és az objektumorientált objektumok között. Az adatstruktúrák nyilvános adatokkal rendelkeznek, és nem viselkednek. Ez azt jelenti, hogy nincsenek módszereik.

Könnyen létrehozhatunk ilyen objektumokat az objektum szó szerinti szintaxisa segítségével. Ez így néz ki:

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

Az objektumok a JavaScript-ben kulcs-érték párok dinamikus gyűjteményei. A kulcs mindig egy karakterlánc, és egyedinek kell lennie a gyűjteményben. Az érték lehet primitív, objektum vagy akár függvény is.

A tulajdonsághoz a pont vagy a négyzet jelöléssel férhetünk hozzá.

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

Itt van egy példa, ahol az érték egy másik objektum.

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

A carbstulajdonság értéke új objektum. Így érhetjük el az carbsingatlant.

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

Gyorsírású tulajdonnevek

Tekintsük azt az esetet, amikor tulajdonságaik értékeit változókban tároljuk.

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

A JavaScript támogatja az úgynevezett rövidített tulajdonságneveket. Ez lehetővé teszi számunkra, hogy objektumot hozzunk létre csak a változó nevével. Létrehoz egy azonos nevű tulajdonságot. A következő objektum literál megegyezik az előzővel.

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

Object.create

Ezután nézzük meg, hogyan lehet megvalósítani az objektumokat viselkedéssel, objektum-orientált objektumokkal.

A JavaScript rendelkezik az úgynevezett prototípus rendszerrel, amely lehetővé teszi az objektumok közötti viselkedés megosztását. A fő gondolat egy prototípus nevű objektum létrehozása közös viselkedéssel, majd felhasználás új objektumok létrehozásakor.

A prototípus rendszer lehetővé teszi olyan objektumok létrehozását, amelyek más objektumok viselkedését öröklik.

Hozzunk létre egy prototípus objektumot, amely lehetővé teszi számunkra, hogy termékeket adjunk hozzá, és a teljes árat bevásárlókosárból szerezzük be.

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

Vegye figyelembe, hogy ezúttal a tulajdonság addProductértéke függvény. Az előző objektumot megírhatjuk egy rövidebb formával is, amelyet gyorsírásos módszer szintaxisnak nevezünk.

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

Az cartPrototypea prototípus objektum, amely a közös viselkedést két módszerrel képviseli, addProductés getTotalPrice. Használható más, ezt a viselkedést öröklő objektumok felépítésére.

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

Az cartobjektum cartPrototypeprototípusa. Örökli tőle a viselkedést. cartrejtett tulajdonsággal rendelkezik, amely a prototípus objektumra mutat.

Ha egy objektumon használunk metódust, akkor ezt a módszert először magán az objektumon keresik, nem pedig a prototípusán.

ez

Ne feledje, hogy egy speciális kulcsszót használunk thisaz objektum adatainak eléréséhez és módosításához.

Ne feledje, hogy a függvények a JavaScript független viselkedési egységei. Nem feltétlenül tartoznak egy tárgyhoz. Amikor vannak, rendelkeznünk kell egy referenciával, amely lehetővé teszi a függvény számára, hogy ugyanazon az objektumon más tagokhoz is hozzáférjen. thisa függvénykörnyezet. Hozzáférést biztosít más ingatlanokhoz.

Adat

Kíváncsi lehet, miért nem definiáltuk és inicializáltuk a productstulajdonságot magán a prototípus objektumon.

Nem kellene ezt tennünk. Prototípusokat kell használni a viselkedés megosztásához, nem az adatokhoz. Az adatok megosztása azt eredményezi, hogy ugyanazok a termékek vannak több kosárobjektumon. Vegye figyelembe az alábbi kódot:

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

A közös viselkedést öröklődő objektumok cart1és az cart2objektumok cartPrototypeis ugyanazokat az adatokat osztják meg. Ezt nem akarjuk. Prototípusokat kell használni a viselkedés megosztásához, nem az adatokhoz.

Osztály

A prototípus rendszer nem elterjedt módszer az objektumok építésére. A fejlesztők jobban ismerik az objektumok osztályon kívüli építését.

Az osztály szintaxisa lehetővé teszi a közös viselkedésű objektumok létrehozásának ismertebb módját. Még mindig ugyanazt a prototípust hozza létre a jelenet mögött, de a szintaxis egyértelműbb, és elkerüljük a korábbi adatokkal kapcsolatos problémát is. Az osztály egy meghatározott helyet kínál az egyes objektumoktól elkülönülő adatok meghatározásához.

Itt van ugyanaz az objektum, amelyet az osztály cukorszintaxisával hoztak létre:

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.

The other option is to define objects are collections of closures.

For more on closures and function programming techniques check out my book series Functional Programming with JavaScript and React.

The Functional Programming in JavaScript book is coming out.