Funktioner är kodblock som utför vissa uppgifter och som kan återanvändas i programmet.
Det finns två typer av funktioner i ActionScript 3.0:
metoder
och
funktionsslut
. Huruvida en funktion kallas metod eller funktionsslut beror på det sammanhang som funktionen definierats i. En funktion kallas metod om du definierar den som en del av en klassdefinition eller bifogar den till en instans av ett objekt. En funktion kallas funktionsslut om den har definierats på något annat sätt.
Funktioner har alltid varit oerhört viktiga i ActionScript. I ActionScript 1.0 fanns inte nyckelordet
class
, och ”klasser” definierades av konstruktorfunktioner. Även om nyckelordet
class
sedan dess har lagts till i språket är det fortfarande viktigt att du känner till hur funktioner fungerar om du vill få ut det mesta av språket. Detta kan vara en utmaning för programmerare som förväntar sig att ActionScript-funktioner ska bete sig på samma sätt som funktioner i C++ eller Java. Även om grundläggande funktionsdefinition och funktionsanrop inte är någon utmaning för erfarna programmerare, kräver ändå vissa av de avancerade funktionerna i ActionScript en viss förklaring.
Grundläggande funktionsbegrepp
Anropsfunktioner
Du kan anropa en funktion med dess identifierare följt av parentesoperatorn (
()
). Använd parentesoperatorn för att omsluta de funktionsparametrar som ska skickas till funktionen. Funktionen
trace()
är till exempel en funktion på översta nivån i ActionScript 3.0:
trace("Use trace to help debug your script");
Om du anropar en funktion som saknar parametrar måste du använda en tom parentes. Du kan till exempel använda metoden
Math.random()
, som inte tar någon parameter, för att generera ett slumpmässigt tal:
var randomNum:Number = Math.random();
Definiera egna funktioner
Du kan definiera en funktion på två sätt i ActionScript 3.0: du kan använda en funktionssats eller ett funktionsuttryck. Vilken teknik du använder beror på om du vill ha en statisk eller dynamisk programmeringsstil. Om du föredrar statisk programmering, s.k. strikt läge, definierar du funktioner med funktionssatser. Om du har ett särskilt behov av att använda funktionsuttryck definierar du funktioner med dessa. Funktionsuttryck används oftare i dynamisk programmering, s.k. standardläge.
Funktionssatser
Funktionssatser används mest vid definition av funktioner i strikt läge. En funktionssats börjar med nyckelordet
function
följt av:
-
Funktionens namn
-
De parametrar i en kommaavgränsad lista som omsluts av parentes
-
Funktionstexten, d.v.s. den ActionScript-kod som ska köras när funktionen anropas, omsluten av klammerparenteser
Följande kod skapar en funktion som definierar en parameter och sedan anropar funktionen med strängen ”
hello
” som parametervärde:
function traceParameter(aParam:String)
{
trace(aParam);
}
traceParameter("hello"); // hello
Funktionsuttryck
Det andra sättet att deklarera en funktion är att använda en tilldelningsprogramsats med ett funktionsuttryck, vilken ibland kallas funktionslitteral eller anonym funktion. Detta är en mer detaljerad metod som används mycket i tidigare versioner av ActionScript.
En tilldelningssats med ett funktionsuttryck börjar med nyckelordet
var
följt av:
-
Funktionens namn
-
Kolonoperatorn (
:
)
-
Klassen
Function
som anger datatypen
-
Tilldelningsoperatorn (
=
)
-
Nyckelordet
function
-
De parametrar i en kommaavgränsad lista som omsluts av parentes
-
Funktionstexten, d.v.s. den ActionScript-kod som ska köras när funktionen anropas, omsluten av klammerparenteser
I följande kod deklareras funktionen
traceParameter
med ett funktionsuttryck:
var traceParameter:Function = function (aParam:String)
{
trace(aParam);
};
traceParameter("hello"); // hello
Observera att du inte anger något funktionsnamn, vilket du gör i en funktionssats. En annan viktig skillnad mellan funktionsuttryck och funktionssatser är att ett funktionsuttryck är ett uttryck och inte en programsats. Detta betyder att ett funktionsuttryck inte kan stå för sig självt, vilket en funktionssats kan. Ett funktionsuttryck kan användas som en del av en sats, vanligen en tilldelningssats. I följande exempel visas ett array-element som tilldelats ett funktionsuttryck:
var traceArray:Array = new Array();
traceArray[0] = function (aParam:String)
{
trace(aParam);
};
traceArray[0]("hello");
Välj mellan programsatser och uttryck
Som allmän regel gäller att du använder en funktionssats om du inte särskilt måste använda ett uttryck. Funktionssatser är mindre detaljerade och de är mera konsekventa vad gäller strikt läge och standardläge än funktionsuttryck.
Funktionssatser är lättare att läsa än tilldelningssatser som innehåller funktionsuttryck. Funktionssatser gör koden mera koncis. De är mindre krångliga än funktionsuttryck, som kräver att du använder både nyckelordet
var
och
function
.
Funktionssatser är mera konsekventa vad beträffar de två kompilatorlägena, eftersom du kan använda punktsyntax i både strikt läge och standardläge för att anropa en metod som deklarerats med en funktionssats. Detta är inte alltid säkert när det gäller metoder som deklarerats med ett funktionsuttryck. I följande kod definieras klassen Example med två metoder:
methodExpression()
som deklareras med ett funktionsuttryck samt
methodStatement()
som deklareras med en funktionssats. I strikt läge kan du inte använda punktsyntax för att anropa metoden
methodExpression()
.
class Example
{
var methodExpression = function() {}
function methodStatement() {}
}
var myEx:Example = new Example();
myEx.methodExpression(); // error in strict mode; okay in standard mode
myEx.methodStatement(); // okay in strict and standard modes
Funktionsuttryck passar bättre för programmering som fokuseras på körningsbeteende, s.k. dynamiskt beteende. Om du föredrar strikt läge men ändå måste anropa en metod som deklarerats med ett funktionsuttryck, kan du använda vilken teknik du vill. Du kan anropa metoden med hjälp av hakparentes (
[]
) i stället för punktoperatorn (
.
). Följande metodanrop lyckas både i strikt läge och i standardläge:
myExample["methodLiteral"]();
Du kan också deklarera hela klassen som en dynamisk klass. Även om detta gör att du kan anropa metoden med punktoperatorn, är nackdelen att du offrar vissa funktioner i strikt läge för alla instanser av den här klassen. Kompilatorn genererar inte något fel om du försöker komma åt en odefinierad egenskap för en instans av en dynamisk klass.
I vissa lägen är funktionsuttryck mycket användbara. Ofta används funktionsuttryck för funktioner som används bara en gång och sedan tas bort. Ett ovanligare användning är att bifoga en funktion till en prototypegenskap. Mer information finns i Objektet prototype.
Det finns två små skillnader mellan funktionssatser och funktionsuttryck som du måste tänka på när du väljer vilken teknik du ska använda. Den första skillnaden är att funktionsuttryck inte existerar oberoende som objekt med hänsyn till minneshantering och skräpsamling. När du tilldelar ett annat objekt, t.ex. ett array-element eller en objektegenskap, ett funktionsuttryck skapar du bara en referens till funktionsuttrycket i koden. Om den array eller det objekt som funktionsuttrycket är kopplat till hamnar utanför omfånget eller på annat sätt blir otillgängligt, kan du inte komma åt funktionsuttrycket. Om arrayen eller objektet tas bort blir det minne som funktionsuttrycket använder godkänt för skräpsamling, vilket betyder att minnet kan återvinnas och återanvändas för andra ändamål.
I följande exempel visas, att för ett funktionsuttryck är funktionen inte längre tillgänglig när egenskapen som uttrycket är kopplat till tas bort. Klassen Test är dynamisk, vilket betyder att du kan lägga till egenskapen
functionExp
som innehåller ett funktionsuttryck. Funktionen
functionExp()
kan anropas med punktoperatorn, men när egenskapen
functionExp
tas bort är funktionen inte längre tillgänglig.
dynamic class Test {}
var myTest:Test = new Test();
// function expression
myTest.functionExp = function () { trace("Function expression") };
myTest.functionExp(); // Function expression
delete myTest.functionExp;
myTest.functionExp(); // error
Om å andra sidan funktionen först definieras med en funktionssats existerar den som ett eget objekt och fortsätter att existera även när du tar bort egenskapen som funktionen är kopplad till. Operatorn
delete
fungerar bara på egenskaper för objekt, och inte ens ett anrop för att ta bort själva funktionen
stateFunc()
fungerar.
dynamic class Test {}
var myTest:Test = new Test();
// function statement
function stateFunc() { trace("Function statement") }
myTest.statement = stateFunc;
myTest.statement(); // Function statement
delete myTest.statement;
delete stateFunc; // no effect
stateFunc();// Function statement
myTest.statement(); // error
Den andra skillnaden mellan funktionssatser och funktionsuttryck är att funktionssatser existerar i hela omfånget som de definierats i, däribland programsatser som visas före funktionssatsen. Funktionsuttryck definieras däremot bara för efterföljande programsatser. I följande kod anropas funktionen
scopeTest()
innan den definieras:
statementTest(); // statementTest
function statementTest():void
{
trace("statementTest");
}
Funktionsuttryck är inte tillgängliga innan de definieras, och följande kod genererar ett körningsfel:
expressionTest(); // run-time error
var expressionTest:Function = function ()
{
trace("expressionTest");
}
Returnera värden från funktioner
Om du vill returnera ett värde från funktionen använder du programsatsen
return
följt av det uttryck eller litterala värde du vill returnera. Följande kod returnerar ett uttryck som representerar parametern:
function doubleNum(baseNum:int):int
{
return (baseNum * 2);
}
Observera att programsatsen
return
avbryter funktionen, vilket innebär att programsatser under en
return
-programsats inte körs, enligt följande:
function doubleNum(baseNum:int):int {
return (baseNum * 2);
trace("after return"); // This trace statement will not be executed.
}
I strikt läge måste du returnera ett värde för en lämplig typ om du väljer att ange en returtyp. I följande kod genereras ett fel i strikt läge eftersom ett giltigt värde inte returneras:
function doubleNum(baseNum:int):int
{
trace("after return");
}
Kapslade funktioner
Du kan kapsla funktioner, vilket betyder att funktioner kan deklareras inuti andra funktioner. En kapslad funktion är bara tillgänglig inuti dess överordnade funktion, såvida inte en referens till funktionen skickas till extern kod. I följande kod deklareras två kapslade funktioner inuti funktionen
getNameAndVersion()
:
function getNameAndVersion():String
{
function getVersion():String
{
return "10";
}
function getProductName():String
{
return "Flash Player";
}
return (getProductName() + " " + getVersion());
}
trace(getNameAndVersion()); // Flash Player 10
När kapslade funktioner skickas till extern kod skickas de som funktionsslut, vilket betyder att funktionen sparar alla definitioner som finns i omfånget när funktionen definieras. Mer information finns i Funktionsomfång.
Funktionsparametrar
I ActionScript 3.0 finns vissa funktioner för funktionsparametrar som kan verka vara nyheter för programmerare som är nybörjare i språket. Även om begreppet att skicka parametrar med värde eller referens är känt för de flesta programmerare, är kanske
argument
objektet och... (rest)-parametern ny för många.
Överföra argument med värde eller referens
I många programmeringsspråk är det viktigt att förstå skillnaden mellan att skicka argument med värde eller med referens. Skillnaden kan påverka sättet som koden utformas på.
Att skickas med värde betyder att värdet för argumentet kopieras till en lokal variabel som ska användas i funktionen. Att skickas med referens betyder att bara en referens till argumentet skickas, i stället för det verkliga värdet. Ingen kopia av argumentet görs. I stället skapas en referens till den variabel som skickas som ett argument och den kopplas till en lokal variabel som ska användas i funktionen. Med den lokala variabeln, som är en referens till en variabel utanför funktionen, kan du ändra värdet på ursprungsvariabeln.
I ActionScript 3.0 skickas alla argument med referens, eftersom alla värden lagras som objekt. Objekt som tillhör primitiva datatyper, däribland Boolean, Number, int, uint och String, har speciella operatorer som gör att de beter sig som om de skickats med värde. Med följande kod skapas till exempel funktionen
passPrimitives()
som definierar två parametrar,
xParam
och
yParam
, som båda är av typen int. Dessa parametrar liknar lokala variabler som deklarerats i texten för funktionen
passPrimitives()
. När funktionen anropas med argumenten
xValue
och
yValue
initieras parametrarna
xParam
och
yParam
med referenser till int-objekt som representeras av
xValue
och
yValue
. Eftersom argumenten är primitiva beter de sig som om de skickats med värde. Även om
xParam
och
yParam
initialt bara innehåller referenser till objekten
xValue
och
yValue
, genererar alla ändringar i variablerna i funktionstexten nya kopior av värdena i minnet.
function passPrimitives(xParam:int, yParam:int):void
{
xParam++;
yParam++;
trace(xParam, yParam);
}
var xValue:int = 10;
var yValue:int = 15;
trace(xValue, yValue);// 10 15
passPrimitives(xValue, yValue); // 11 16
trace(xValue, yValue);// 10 15
I funktionen
passPrimitives()
ökas värdena för
xParam
och
yParam
, men detta påverkar inte värdena för
xValue
och
yValue
, vilket visas i den senaste
trace
-programsatsen. Detta skulle vara fallet även om parametrarna hade exakt samma namn som variablerna,
xValue
och
yValue
, eftersom
xValue
och
yValue
inuti funktionen pekar på nya platser i minnet som ligger åtskilda från variablerna med samma namn utanför funktionen.
Alla andra objekt, d.v.s. objekt som inte hör till de primitiva datatyperna, skickas alltid med referens, vilket gör att du kan ändra värdet på ursprungsvariabeln. I följande kod skapas objektet
objVar
med de två egenskaperna
x
och
y
. Objektet skickas som ett argument till funktionen
passByRef()
. Eftersom objektet inte är av primitiv typ skickas det med referens och stannar som referens. Detta betyder att ändringar av parametrarna i funktionen påverkar objektets egenskaper utanför funktionen.
function passByRef(objParam:Object):void
{
objParam.x++;
objParam.y++;
trace(objParam.x, objParam.y);
}
var objVar:Object = {x:10, y:15};
trace(objVar.x, objVar.y); // 10 15
passByRef(objVar); // 11 16
trace(objVar.x, objVar.y); // 11 16
Parametern
objParam
refererar samma objekt som den globala variabeln
objVar
. Som du kan se av programsatsen
trace
i exemplet återspeglas ändringar i egenskaperna
x
och
y
för objektet
objParam
i objektet
objVar
.
Standardvärden för parametrar
I ActionScript 3.0 kan du deklarera
standardparametervärden
för en funktion. Om ett anrop till en funktion med standardvärden för parametrar utesluter en parameter med standardvärden, används värdet som anges i funktionsdefinitionen för denna parameter. Alla parametrar med standardvärden måste placeras i slutet av parameterlistan. De värden som angetts som standardvärden måste vara kompileringskonstanter. Om det finns ett standardvärde för en parameter blir denna parameter en
valfri parameter
. En parameter utan standardvärde betraktas som en
obligatorisk parameter
.
I följande kod skapas en funktion med tre parametrar, varav två har standardvärden. När funktionen anropas med bara en parameter, används standardvärdena för denna parameter.
function defaultValues(x:int, y:int = 3, z:int = 5):void
{
trace(x, y, z);
}
defaultValues(1); // 1 3 5
Objektet Arguments
När parametrar skickas till en funktion, kan du använda objektet
arguments
för att komma åt information om de parametrar som skickats till funktionen. Vissa aspekter om
argument
är viktiga:
-
Objektet
arguments
är en array som innehåller alla parametrar som skickats till funktionen.
-
Egenskapen
arguments.length
rapporterar antalet parametrar som skickats till funktionen.
-
Egenskapen
arguments.callee
ger en referens till själva funktionen, och den är användbar för rekursiva anrop till funktionsuttryck.
Obs!
Objektet
arguments
är inte tillgängligt om någon parameter heter
arguments
eller om du använder parametern ... (rest).
Om funktionstexten refererar till
arguments
-objektet kan funktionsanrop i ActionScript 3.0 innehålla fler parametrar än de som definierats i funktionsdefinitionen, men ett kompileringsfel genereras i strikt läge om antalet parametrar inte matchar antalet obligatoriska parametrar (och eventuellt valfria parametrar). Du kan använda arrayaspekten för objektet
arguments
för att komma åt alla parametrar som skickats till funktionen, vare sig de är definierade i funktionsdefinitionen eller inte. I följande exempel, som bara kompileras i standardläge, används arrayen
arguments
tillsammans med egenskapen
arguments.length
för att kalkera alla parametrar som skickats till funktionen
traceArgArray()
:
function traceArgArray(x:int):void
{
for (var i:uint = 0; i < arguments.length; i++)
{
trace(arguments[i]);
}
}
traceArgArray(1, 2, 3);
// output:
// 1
// 2
// 3
Egenskapen
arguments.callee
används ofta i anonyma funktioner för att skapa rekursion. Du kan använda den för att göra koden flexiblare. Om namnet på en rekursiv funktion ändras under utvecklingen måste du kanske ändra det rekursiva anropet i funktionstexten om du använder
arguments.callee
i stället för funktionsnamnet. Egenskapen
arguments.callee
används i följande funktionsuttryck för att skapa rekursion:
var factorial:Function = function (x:uint)
{
if(x == 0)
{
return 1;
}
else
{
return (x * arguments.callee(x - 1));
}
}
trace(factorial(5)); // 120
Om du använder parametern ... (rest) i funktionsdeklarationen är objektet
arguments
inte tillgängligt. Du måste i stället komma åt parametrarna med hjälp av de parameternamn du deklarerat för dem.
Du bör inte använda strängen
"arguments"
som parameternamn, eftersom den skuggar objektet
arguments
. Om till exempel funktionen
traceArgArray()
skrivs om så att parametern
arguments
läggs till, pekar referenserna på
arguments
i funktionstexten på parametern och inte på objektet
arguments
. Följande kod ger inga utdata:
function traceArgArray(x:int, arguments:int):void
{
for (var i:uint = 0; i < arguments.length; i++)
{
trace(arguments[i]);
}
}
traceArgArray(1, 2, 3);
// no output
Objektet
arguments
i tidigare versioner av ActionScript innehåller också egenskapen
caller
som är en referens till den funktion som anropas i aktuell funktion. Egenskapen
caller
finns inte i ActionScript 3.0, men om du behöver en referens till anropsfunktionen, kan du ändra den så att den skickar en extra parameter som är en referens till sig själv.
Parametern... (rest)
I ActionScript 3.0 introduceras en ny parameterdeklaration som kallas parametern... (rest). Med den här parametern kan du ange en arrayparameter som godkänner valfritt antal kommaavgränsade parametrar. Parametern kan heta vad som helst bara det inte är ett reserverat ord. Parameterdeklarationen måste vara den sist angivna parametern. Om du använder den här parametern kan du inte använda objektet
arguments.
Även om parametern ... (rest) har samma funktioner som arrayen
arguments
och egenskapen
arguments.length
har den inte samma funktioner som
arguments.callee
. Du måste kontrollera att du inte behöver använda
argument.callee
innan du använder parametern ... (rest).
I följande exempel skrivs funktionen
traceArgArray()
om med hjälp av ... (rest)-parametern i stället för objektet
arguments
:
function traceArgArray(... args):void
{
for (var i:uint = 0; i < args.length; i++)
{
trace(args[i]);
}
}
traceArgArray(1, 2, 3);
// output:
// 1
// 2
// 3
Parametern... (rest) kan också användas med andra parametrar så länge som den är den sista parametern. I följande exempel ändras funktionen
traceArgArray()
så att dess första parameter,
x
, är av typen int och den andra parametern använder parametern ... (rest). Det första värdet finns inte med i utdata eftersom den första parametern inte längre ingår i arrayen som skapats av parametern ... (rest).
function traceArgArray(x: int, ... args)
{
for (var i:uint = 0; i < args.length; i++)
{
trace(args[i]);
}
}
traceArgArray(1, 2, 3);
// output:
// 2
// 3
Funktioner som objekt
Funktioner i ActionScript 3.0 är objekt. När du skapar en funktion skapar du ett objekt, som inte bara kan skickas som parameter till en annan funktion, utan även få egenskaper och metoder kopplade till sig.
Funktioner som skickas som argument till andra funktioner skickas med referens och inte med värde. När du skickar en funktion som ett argument använder du bara identifieraren och inte parentesoperatorn som du använder för att anropa metoden. Med följande kod skickas funktionen
clickListener()
som ett argument till metoden
addEventListener()
:
addEventListener(MouseEvent.CLICK, clickListener);
Även om du som inte använt ActionScript tidigare tycker att det är märkligt, kan funktioner ha egenskaper och metoder som vilka andra objekt som helst. Alla funktioner har i själva verket en skrivskyddad egenskap som heter
length
som lagrar antalet parametrar som definierats för funktionen. Egenskapen
arguments.length
rapporterar i stället antalet argument som skickas till funktionen. Kom ihåg, att i ActionScript kan antalet argument som skickas till en funktion överstiga antalet parametrar som definierats för samma funktion. I följande exempel, som bara kompileras i standardläge eftersom strikt läge kräver en exakt överensstämmelse mellan antalet skickade argument och antalet definierade parametrar, visas skillnaden mellan de två egenskaperna:
// Compiles only in standard mode
function traceLength(x:uint, y:uint):void
{
trace("arguments received: " + arguments.length);
trace("arguments expected: " + traceLength.length);
}
traceLength(3, 5, 7, 11);
/* output:
arguments received: 4
arguments expected: 2 */
I standardläget kan du definiera egna funktionsegenskaper genom att definiera dem utanför funktionstexten. Funktionsegenskaperna kan fungera som kvasistatiska egenskaper som du använder för att spara en variabel som relateras till funktionen. Du kanske vill spåra hur många gånger en viss funktion anropas. Du kan använda den här funktionen om du skriver ett spel och vill spåra hur många gånger en användare använder ett visst kommando, men du kan också använda en statisk klassegenskap för detta. I följande exempel, som bara kompileras i standardläge eftersom du inte kan lägga till dynamiska egenskaper i funktioner i strikt läge, skapas en funktionsegenskap utanför funktionsdeklarationen och egenskapen ökar stegvis varje gång som funktionen anropas:
// Compiles only in standard mode
var someFunction:Function = function ():void
{
someFunction.counter++;
}
someFunction.counter = 0;
someFunction();
someFunction();
trace(someFunction.counter); // 2
Funktionsomfång
Med en funktions omfång anges var i programmet funktionen kan anropas men också vilka funktionsdefinitioner som funktioner har åtkomst till. Samma omfångsregler som gäller för variabelidentifierare gäller också för funktionsidentifierare. En funktion som deklareras i det globala omfånget kan användas i hela koden. ActionScript 3.0 innehåller globala funktioner, till exempel
isNaN()
och
parseInt()
, som är tillgängliga överallt i koden. En kapslad funktion, d.v.s. en funktion som har deklarerats inuti en annan funktion, kan användas var som helst i den funktion som den har deklarerats i.
Omfångskedjan
Varje gång en funktion körs skapas ett antal objekt och egenskaper. Först skapas ett speciellt objekt som kallas
aktiveringsobjekt
som lagrar parametern och alla lokala variabler eller funktioner som deklarerats i funktionstexten. Du kan inte komma åt aktiveringsobjektet direkt eftersom det är en intern mekanism. Därefter skapas en
omfångskedja
, som innehåller en ordnad lista på objekt som vid körning genomsöks efter identifierardeklarationer. Varje funktion som körs har en omfångskedja som lagras i en intern egenskap. Om det är en kapslad funktion startar omfångskedjan med det egna aktiveringsobjektet, följt av aktiveringsobjektet i den överordnade funktionen. Kedjan fortsätter på det här sättet tills den når det globala objektet. Det globala objektet skapas när ett ActionScript-program startar och objektet innehåller alla globala variabler och funktioner.
Funktionsslut
Ett
funktionsslut
är ett objekt som innehåller en ögonblicksbild av en funktion och dess
lexikala miljö
. En funktions lexikala miljö innehåller alla variabler, egenskaper, metoder och objekt i funktionens omfångskedja, tillsammans med deras värden. Funktionsslut skapas varje gång en funktion körs skilt från ett objekt eller en klass. Det faktum att funktionsslutet sparar omfånget som det definierats i, skapar intressanta resultat när en funktion skickas som ett argument eller ett returvärde till ett annat omfång.
I följande kod skapas två olika funktioner:
foo()
, som returnerar den kapslade funktionen
rectArea()
som beräknar arean av en rektangel, samt
bar()
som anropar
foo()
och lagrar det returnerade funktionsslutet i variabeln
myProduct
. Även om funktionen
bar()
definierar sin egen lokala variabel
x
(med värdet 2) när funktionsslutet
myProduct()
anropas, sparas variabeln
x
(med värdet 40) som definierats i funktionen
foo().
Funktionen
bar()
returnerar därför värdet
160
i stället för
8
.
function foo():Function
{
var x:int = 40;
function rectArea(y:int):int // function closure defined
{
return x * y
}
return rectArea;
}
function bar():void
{
var x:int = 2;
var y:int = 4;
var myProduct:Function = foo();
trace(myProduct(4)); // function closure called
}
bar(); // 160
Metoder beter sig på ungefär samma sätt eftersom de också sparar information om den lexikala miljö som de skapats i. Dessa egenskaper märks mest när en metod extraheras från sin instans, vilket skapar en bunden metod. Den största skillnaden mellan ett funktionsslut och en bunden metod är att värdet för nyckelordet
this
i en bunden metod alltid refererar till instansen som den ursprungligen var kopplad till, medan värdet för nyckelordet
this
kan ändras i ett funktionsslut.
|
|
|