5 min read

Az objektum és egyéb jóságok

Az objektum és egyéb jóságok

Az előző leckében homályos utalást tettem az object-re (objektumra). Itt az ideje, hogy tisztázzuk ezt a fogalmat és megfogalmazzuk érthetően, hogy mi az az object.

Object: olyan struktúrált adattípus, amely tartalmazhat (feltételes mód, azaz nem kell feltétlenül mindet tartalmaznia) változókat és metódusokat.

Adattípus... Ez azt jelenti, hogy akkor hozzá tudom rendelni egy változóhoz? Igen azt jelenti, méghozzá a brace vagy curly brakcet (mindkettő ugyanazt jelenti: {} ) segítségével:

var myFirstObject = {
    welcomeText: "Hello, World!",
    greet: function() {
        console.log(this.welcomeText);
    }
}

myFirstObject.greet();
"Hello, World!" objektummal megvalósítva

Elemezzük picit ezt a programot:

  • az első sorban semmi újat nem látjatunk, egy változót hozunk éppen létre (méghozzá objektum típusú változót, melyet a typeof-al ellenőrizni is tudunk: typeof myFirstObject) és már a curly bracket is ismerős.
  • a második sorban a "Hello, World!" szintén ismerős, de a szintaktika gyanús. Valóban az, és ezért is írtam dőlt betűvel az object meghatározásnál a változót, mert az object-en belül ezeket property-nek hívjuk, de ezek tulajdonképpen attól még változók, tehát van neve (welcomeText), értéke ("Hello, World!") és típusa is (string), melyet szintén a typeof-al ki is tudunk iratni (typeof myFirstObject.welcomeText).
  • harmadik sorban ismét valami szokatlant, és olyasmit látunk amivel eddig nem találkozunk: ez a function(), azonban az eleje meg pont úgy néz ki mint a felette lévő sor. Tehát akkor a "greet" egy property (változó), melyhez hozzárendeltük ezt a function() "izét"? Igen. Ha kiiratjuk a "greet" adattípusát (typeof myFirtstObject.greet) akkor azt fogjuk kapni, hogy function (függvény). Innen nem nehéz levonni azt a következtetést, hogy a function egy struktúrális adattípus, és ezzel meg is kaptuk a JS utolsó adattípusát és végre lezártnak tekinthetjük az előző leckét.

Itt most befejezném a boncolgatást, mert olyan dolgok jönnének a képbe, amiket az OOP-s résznél kívánok kifejteni. Lassan helyére kerül minden eddigi ismeretlen fogalom, ám két dologgal még adós vagyok:

  • method: az objecten belüli property-t melynek a típusa function, methodnak hívjuk. Magyarul: ha a változó az objektumon belül van, akkor property-nek hívjuk (ezt fentebb le is írtam, de nem árt az ismétlés). Ha ennek a property-nek a típusa függvény (function) akkor pedig metódusnak hívjuk (de attól még property is). Ez kb. a "minden bogár rovar, de nem minden rovar bogár." esete.
  • parameter(s): a functionnek átadott adat(ok)

Hogy jobban megértsük, hogy mi az a parameter, írjuk át picit a fenti programot úgy, hogy a methodunk (functionünk) képes legyen parameter-t fogadni (kissé bajban vagyok a "hunglish" használatával, nagyon furcsa angol szavakhoz magyar ragokat csatolni, hol használom a - jelet hol nem, elnézést kérek érte).

var myFirstObject = {
    greet: function(message) {
        console.log(message);
    }
}

myFirstObject.greet("Hello, World!");

Ha lefuttatjuk, akkor a már unalomig ismert "Hello, World!" fog visszaköszönni. Nem léphetnénk végre túl rajta és nézhetnénk meg valami mást is? Dehogynem, nézzünk egy nem túl életszerű, de demonstrálás céljára tökéletes function megvalósítást. Írjunk egy olyan olyan függvényt, mely a paramétereit kivonja egymásból és kiírja a képernyőre:

function subtract(firstNumber, secondNumber) {
    var result = firstNumber - secondNumber;
    console.log(result);
}

subtract(42, 11);

Mint látható a function létrehozható object nélkül is (és akkor valóban functionnek hívjuk nem methodnak) és ilyenkor csak szimplán a nevével meg tudjuk hívni. Az is látszik, hogy a functionnek nem csak egy, hanem több paramétere is lehet, melyet aztán azon belül mint változót tudunk használni. A function-on belül is definiálhatunk magunknak újabb változó(ka)t (result). Azt is örömmel konstatálhatjuk, hogy nem csak string típust tudunk a console.log()-al kiiratni, hiszen a result az number típusú (hogy miként tud a console.log() számot kiírni még később elő fog kerülni). Mivel a function egy adattípus ezért hozzárendelhetjük egy változóhoz is, így a programunk az alábbiak szerint módosulna:

var subtract = function(firstNumber, secondNumber) {
    var result = firstNumber - secondNumber;
    console.log(result);
}

subtract(42, 11);

A két programot ugyanúgy hívjuk meg, ugyanazt csinálja, a typeof mindkettőre "function"-t mond, akkor a két program ugyanaz csak máshogy néz ki a deklaráció? Nem egészen, a kettő között van egy apró, ám igen lényeges különbség, amit majd később fogok részletezni. Most sokkal "fontosabb" dolgunk van: próbáljuk ki a programunkat más paraméterekkel. Mondjuk próbáljuk meg a vízből kivonni a "zOxygen"-t:

subtract("H2O", "O");

Hát az eredmény bizony nem az lett amit vártunk (remélem nem vártad ténylegesen, hogy megmarad a hidrogén), hanem a NaN. A NaN a Not a Number rövidítése. Nos akkor már tudjuk, hogy a stringeket nem igazán lehet kivonni egymásból (furcsa módon azonban összeadni össze lehet őket, ilyenkor a jobb oldali string hozzá lesz fűzve (hozzá lesz adva) a bal oldali stringhez: "Jóska" + "Pista": "JóskaPista"). Amikor megírtuk a subtract functiont valószínű fel sem merült bennünk, hogy valaha stringekkel használjuk és ez egészen addig rendben is van amíg csak mi dolgozunk egy programon. Azonban ha az általunk megírt remek subtract functiont mondjuk Béla használni akarja, akkor szegénynek ne kelljen már átnézni az egész kódot azért, hogy ezt biztonságosan megtehesse.
Dehát Béla rájöhetne abból, hogy firstNumber meg secondNumber nem? Valójában igen, és létezik is egy olyan mondás, hogy a jól megírt kód dokumentálja saját magát (persze, sokat segít ha beszédes változóneveket meg function neveket használunk, de ezt azért ne vegyük szentírásnak és ne keverjük a dokumentációval). Nomeg attól, hogy esetleg Béla rájön a compiler nem fog, tehát tök jó lenne ezt valahogy annak is megmondani.

A JS egy gyengén típusos nyelv (weakly vagy loosely typed), hiszen vannak ugyan típusaink, de pl. amikor a functionnek paramétert adunk át az valójában nem tudja, hogy mit fog kapni, azt csak mi tudjuk akkor amikor éppen írjuk a functiont. A function definiálásakor nem kell megmondanunk, hogy mit várunk el. Az erősen típusos nyelvek (strongly typed) sokkal szigorúbb szabályok betartását követelik meg tőlünk, cserébe már fordítás közben figyelmeztetni tudnak az ilyen és ehhez hasonló hibák kapcsán. A typescript ezt a "gyengeséget" orvosolja, segítségével megadhatjuk a function fejlécében, hogy number-t várunk el (ezt egyelőre nem tudod kipróbálni lokálban (ellenben a javasolt online sandboxban igen), mert nincs typescripted, de ami késik arra várni kell):

function subtract(firstNumber: number, secondNumber: number) {
    var result = firstNumber - secondNumber;
    console.log(result)
}

Ez azt jelenti, hogy a typescript segítségével meg tudok szabadulni a hibáktól? Van amitől igen és van amitől nem. Írjunk egy olyan programot amely nem kivonja, hanem elosztja a két számot egymással:

function divide(firstNumber, secondNumber) {
    var result = firstNumber / secondNumber;
    console.log(result);
}

Itt hiába adnánk meg, hogy mindkét paraméternek numbert szeretnénk kapni, nagyon egyszerűen hibára tudjuk késztetni a programunkat akár számokkal is. Egyszerűen adjunk meg második paraméternek nullát. Nullával még a számítógép sem tud osztani, vagy mégis? Próbáljuk ki: divide(42, 0)

Azta, a JS tud 0-val osztani és az eredmény Infinity azaz végtelen lett. Valójában nem a JS tud osztani 0-val, hanem van egy szabvány az aritmetikai műveletekre vonatkozóan, mely az igen hangzatos, ugyanakkor meglehetősen semmitmondó IEEE 754 nevet viseli. Ennek van egy olyan része, hogy ha nullával próbálunk osztani, akkor az eredmény legyen végtelen. Bravó JS, kiválóan implementáltad a szabványt, jár a mezei pirospont.

Talán emlékszel még, hogy azt írtam, hogy a JS egy igen érdekesen összerakott nyelv. És bár itt tökéletesen implementálta a szabványt, bőven fogok mutatni olyan eseteket, ahol az adott szituáció kapcsán széles mosoly fog kiülni az arcodra.

Ha azt gondolnánk, hogy csak a JS-nek vannak érdekességei/tévedései (veet krém...), akkor záró gondolatként Sir Charles Antony Richard Hoare-t idézném a null-al kapcsolatban:

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Mit tanultál ebben a leckében?

  • megtanultad, hogy az object és a function struktúrális adattípus
  • megtanultad, hogy miként tudsz objectet létrehozni
  • végre tisztáztuk a metódus és a paraméter fogalmát
  • ízelítőt kaptál abból, hogyan fog a typescript segíteni nekünk a programozás során