JavaScript new operátor
2014. március 28.
by 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:
- Létrehoz egy új objektumot.
- Beállítja a konstruktor függvény (publikus) prototípusát az új objektum (privát) prototípusaként.
- Meghívja a konstruktor függvényt,
this
-ként az újonnan létrehozott objektumot használja. - 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!