JavaScript new operátor

2014.03.28. | írta: tmichel

Múltkor elkezdtem egy mini-sorozatot azokról a témákról, amik nem fértek bele a web alapozó tanfolyamunkba. Az első bejegyzésben a Function.prototype.call és társai kerültek elő. Most erre építkezve elmélyedünk a new operátor szépségeiben.

A new feladata

A new operátor egy előre definiált típust példányosít. Ez persze így nem igaz, mert JavaScriptben nem lehet új típust létrehozni. Valójában a new operátor által létrehozott új objektum Object típusú lesz, de egy constructor function hozza létre, így lényegében egy olyan objektumot kapunk, amit előre felparamétereztünk.

var Person = function (name) {
    this.name = name;
};

Person.prototype.greet = function () {
    return "Hi, my name is " + this.name + "!";
};

var p = new Person("tmichel");

console.log(p.name); // => tmichel
console.log(p.greet()); // => Hi, my name is tmichel!

Láthatjuk, hogy a létrehozott objektum úgy viselkedik, mintha Person típusú lenne, miközben tudjuk, hogy a valós típusa Object. Ez annak köszönhető, hogy az újonnan létrehozott objektum megörökölte a Person prototípusát.

A new operátor nagyjából a következő lépésekben hozza létre az új objektumot:

  1. Létrehoz egy új objektumot.
  2. Beállítja a konstruktor függvény (publikus) prototípusát az új objektum (privát) prototípusaként.
  3. Meghívja a konstruktor függvényt, this-ként az újonnan létrehozott objektumot használja.
  4. Visszatér az új objektummal, vagy a konstruktor függvény visszatérési értékével.

A 2. pont az igazán kritikus. JavaScriptben prototípusokkal lehet imitálni a legtöbb OO koncepciót, bár kérdéses, hogy kell-e. Egy objektum prototípusát csak létrehozási időben lehet beállítani (a szabvány szerint). Tehát csak a new operátor és az Object.create függvény segítségével. Újabb böngészőkben elérhető a __proto__ tulajdonság az összes objektumon. Ez tartalmazza a prototípust és ezen keresztül meg is lehet változtatni egy azt. Mondanom sem kell, hogy ez igen veszélyes lehet és nem nem várt következményekkel járhat. Ezen túl a __proto__ nem szabványos, így nincs garancia rá, hogy melyik böngésző támogatja és melyik nem.

Írjunk saját new operátort!

Nem kell más tennünk, mint a fenti 4 pontot végrehajtani.

function mynew(ctor) {
    // létrehozunk egy új objektumot és beállítjuk a prototípusát (1. és 2. pont)
    var $this = Object.create(ctor.prototype),
        args = Array.prototype.slice.call(arguments, 1);

    // meghívjuk a konstruktor függvényt és visszatérünk a függvény visszatérési
    // értékével, vagy ha undefined, akkor magával az új objektummal.
    return ctor.apply($this, args) || $this;
}

A fentebb definiált Person-t a következő kódrészlettel lehet példányosítani az új new operátorunkkal:

var me = mynew(Person, "tmichel");

console.log(p.name); // => tmichel
console.log(me.greet()); // => Hi, my name is tmichel!

Látható, hogy ugyanazt az eredményt kaptuk, mintha a beépített nyelvi elemet használtuk volna.

Ebből a rövid kis bejegyzésből is kiderül, hogy a JavaScript többet tartogat, mint amit elsőre gondolnánk. Érdemes elmerülni a nyelv részleteiben és picit elmélyedni a JavaScript VM-ek lelki világában. A sorozat következő részében a prototípusokat vizsgáljuk meg közelebbről. Kövessetek minket!

Facebook Twitter Google+
comments powered by Disqus