ЈаваСцрипт Цреате Објецт - Како дефинисати објекте у ЈС-у

Објекти су главна јединица енкапсулације у објектно оријентисаном програмирању. У овом чланку ћу описати неколико начина за изградњу објеката у ЈаваСцрипт-у. Су:

  • Објект дословно
  • Објецт.цреате ()
  • Предавања
  • Фабричке функције

Објецт Литерал

Прво, морамо направити разлику између структура података и објектно оријентисаних објеката. Структуре података имају јавне податке и не понашају се. То значи да немају методе.

Такве објекте можемо лако створити користећи дословну синтаксу објекта. Изгледа овако:

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

Објекти у ЈаваСцрипт-у су динамичке колекције парова кључ / вредност. Кључ је увек низ и мора бити јединствен у колекцији. Вредност може примитив, објекат или чак функцију.

Својству можемо приступити помоћу тачке или квадратног записа.

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

Стенографска имена својстава

Размотримо случај када имамо вредности својих својстава ускладиштене у променљиве.

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

ЈаваСцрипт подржава оно што се назива скраћеним именима својстава. Омогућава нам да креирамо објекат користећи само име променљиве. Створиће својство са истим именом. Следећи објектни литерал је еквивалентан претходном.

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

Објецт.цреате

Даље, погледајмо како имплементирати објекте са понашањем, објектно оријентисане објекте.

ЈаваСцрипт има оно што се назива прототипним системом који омогућава дељење понашања између објеката. Главна идеја је створити објекат који се назива прототип са уобичајеним понашањем, а затим га користити при стварању нових објеката.

Прототипни систем нам омогућава да креирамо објекте који наслеђују понашање од других објеката.

Направимо прототипни објекат који нам омогућава додавање производа и добијање укупне цене из колица за куповину.

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за приступ и модификовање података на објекту.

Запамтите да су функције независне јединице понашања у ЈаваСцрипт-у. Они нису нужно део објекта. Кад јесу, треба да имамо референцу која омогућава функцији приступ осталим члановима на истом објекту. 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.

Друга опција је дефинисање објеката као збирки затварања.

За више информација о затварању и техникама програмирања функција погледајте моју серију књига Функционално програмирање са ЈаваСцрипт-ом и Реацт-ом.

Излази књига о функционалном програмирању у ЈаваСцрипт- у.