Végrehajtási környezet elvesztése (scope loss)
Egy korábbi fejezetben már volt arról szó, hogy a this kulcsszó egy függvényen belül a hívó által meghatározott, független attól, hogy milyen futási környezetben definiáltuk az adott függvényt.
function F1(){
this.name = "F1 object";
this.toString = function(){
return "I am "+ this.name;
};
}
function Kutya(name){
this.name = name;
}
var objF = new F1();
alert(objF); // I am F1 object
var objKutya1 = new Kutya("bundas");
objKutya1.toString = objF.toString;
alert(objKutya1); // I am bundas
A fenti példa azt mutatja be, hogy ugyanaz a függvény különböző futási környezetben is végrehajtható. A toString() függvény első végrehajtásakor a this kulcsszó az objF objektumot testesíti meg, míg második alkalommal már az objKutya1 objektumot.
Végrehajtási kontextus elvesztéséről akkor beszélünk, ha egy függvényünk nem abban a kontextusban fut le, mint amiben azt definiáltuk. Ha a függvényünk egy objektum tulajdonságaira vagy metódusaira hivatkozik a this kulcsszóval, a függvény végrehajtásakor hiba lép fel, mivel a this egy másik objektumra hivatkozik. Fontos kihangsúlyozni, hogy a végrehajtási környezet elvesztéséből csak akkor származhat problémánk, ha a függvényünkben használtuk a this kulcsszót. Lássunk néhány példát.
<script type="text/javascript">
var App = {
locales : {
message : "button clicked"
},
init : function(){
var oBtn = document.getElementById('btnTest');
oBtn.onclick = function(){
alert(this.locales.message);
};
};
};
window.onload = function(){
App.init();
};
</script>
</head>
<body>
<button id="btnTest" accesskey="t">Test</button>
</body>
</html>
Az App objektum init() metódusa egy eseménykezelőt kapcsol a HTML oldalon lévő nyomógombhoz. Az anonim eseménykezelő akkor lesz végrehajtva, amikor a gombot a felhasználó lenyomja. Az eseménykezelő lefutásakor a kívánt üzenet nem íródik ki, helyette egy futási hiba keletkezik ('this.locales.message' is null or not an object). Az eseménykezelő függvény ugyanis más kontextusban hajtódik végre, azaz a this kulcsszó objektum referenciát tartalmaz magára a HTML nyomógombra. Erről könnyen meggyőződhetünk, elég kiíratni a nyomógomb elem azonosítóját (id tulajdonságát).
oBtn.onclick = function(){
alert(this.id); // btnTest
};
Maradjunk még ennél a példánál, és próbáljuk meghívni az init metódust az oldal betöltése után a következő módon:
window.onload = App.init;
A nyomógombra kattintás után futási hiba keletkezik ugyanazzal a hibaüzenettel (’this.locales.message’ is null or not an object). Sikerült egy újabb példát bemutatni futási környezet elvesztésére. A különbség csak annyi, hogy most az init függvény a globális végrehajtási környezetben van végrehajtva.
var App = {
locales : {
message : "button clicked"
},
init : function(){
var oBtn = document.getElementById('btnTest');
alert(this); // [object Window]
oBtn.onclick = function(){
alert(this); // [object HTMLButtonElement]
};
}
};
window.onload = App.init;
A window objektum onload tulajdonságához csak egy referenciát rendeltünk az init() függvényre. Így az init() függvény semmit sem fog tudni az App objektumról, a this kulcsszó a globális objektumra (ez általában a window objektum) fog hivatkozni.
| Eval | Eval kód esetén a hívó futási környezet this értékét veszi fel. |
| Függvény | Függvény kód esetén a hívó biztosítja a this értékét, viszont ha ez nem egy objektum, akkor a this a globális objektum lesz. |
| Globális kód | Globális kód esetén a this a globális objektum lesz. |