Functies
zijn blokken code die specifieke taken uitvoeren en opnieuw kunnen worden gebruikt in uw programma. Er zijn twee typen functies in ActionScript 3.0:
methoden
en
functie closure
. Of een functie een methode of functie closure wordt genoemd, hangt af van de context waarin de functie is gedefinieerd. Een functie wordt een methode genoemd als u deze definieert als onderdeel van een klassendefinitie of koppelt aan een instantie van een object. In alle andere gevallen is er sprake van een functie closure.
Functies hebben altijd een uiterst belangrijke rol gespeeld in ActionScript. In ActionScript 1.0 bestond het trefwoord
class
nog niet, zodat 'klassen' werden gedefinieerd met constructorfuncties. Hoewel het trefwoord
class
later in de taal is opgenomen, is een goed begrip van functies nog steeds belangrijk als u de taal optimaal wilt gebruiken. Dit kan een uitdaging vormen voor programmeurs die verwachten dat functies in ActionScript zich net zo gedragen als functies in talen zoals C++ of Java. Hoewel de basisbewerkingen voor het definiëren en aanroepen van functies voor ervaren programmeurs geen probleem hoeft te zijn, is voor sommige meer geavanceerde mogelijkheden van ActionScript enige uitleg vereist.
Elementaire functieconcepten
Functies aanroepen
U roept een functie aan door de id ervan te gebruiken, gevolgd door de ronde-haakjesoperator (
()
). Tussen de ronde haakjes plaatst u de functieparameters die u naar de functie wilt sturen. De functie
trace()
is bijvoorbeeld een functie op topniveau in ActionScript 3.0:
trace("Use trace to help debug your script");
Als u een functie aanroept zonder parameters, gebruikt u een leeg paar ronde haakjes. Met de methode
Math.random()
, waarvoor geen parameters worden gebruikt, genereert u bijvoorbeeld een willekeurig getal:
var randomNum:Number = Math.random();
Uw eigen functies definiëren
Er zijn twee manieren om een functie te definiëren in ActionScript 3.0: u kunt een functie-instructie of een functie-expressie gebruiken. De techniek die u kiest, hangt af van uw eigen voorkeur voor een meer statische of dynamische programmeerstijl. Definieer uw functies met functie-instructies als u de voorkeur geeft aan statisch programmeren (in de strikte modus). Definieer uw functies met functie-expressies als u daarvoor een specifieke reden hebt. Functie-expressies worden vaker gebruikt bij dynamisch programmeren (in de standaardmodus).
Functie-instructies
Functie-instructies genieten de voorkeur voor het definiëren van functies in de strikte modus. Een functie-instructie begint met het trefwoord
function
, gevolgd door:
-
De functienaam
-
De parameters, in een door komma's gescheiden lijst tussen ronde haakjes
-
De hoofdtekst van de functie, ofwel de ActionScript-code die wordt uitgevoerd bij het aanroepen van de functie, tussen accolades
Met de volgende code wordt bijvoorbeeld een functie gemaakt die een parameter definieert en wordt vervolgens de functie aangeroepen met de tekenreeks '
hello'
als parameterwaarde:
function traceParameter(aParam:String)
{
trace(aParam);
}
traceParameter("hello"); // hello
Functie-expressies
De tweede manier om een functie te declareren is met behulp van een toewijzingsinstructie en een functie-expressie, ook wel een letterlijke functie of anonieme functie genoemd. Deze manier leidt tot uitgebreidere code en werd in eerdere versies van ActionScript veel gebruikt.
Een toewijzingsinstructie met een functie-expressie begint met het trefwoord
var
, gevolgd door:
-
De functienaam
-
De operator
:
(dubbele punt)
-
De klasse
Function
om het gegevenstype aan te duiden
-
De toewijzingsoperator (
=
)
-
Het trefwoord
function
-
De parameters, in een door komma's gescheiden lijst tussen ronde haakjes
-
De hoofdtekst van de functie, ofwel de ActionScript-code die wordt uitgevoerd bij het aanroepen van de functie, tussen accolades
De volgende code declareert bijvoorbeeld de functie
traceParameter
met behulp van een functie-expressie:
var traceParameter:Function = function (aParam:String)
{
trace(aParam);
};
traceParameter("hello"); // hello
Merk op dat u geen functienaam opgeeft, zoals bij een functie-instructie. Nog een belangrijk verschil is dat functie-expressies anders dan functie-instructies geen instructies zijn, maar expressies. Dit betekent dat een functie-expressie niet afzonderlijk kan bestaan en een functie-instructie wel. Een functie-expressie kan alleen als onderdeel van een instructie worden gebruikt, meestal een toewijzingsinstructie. In het volgende voorbeeld wordt een functie-expressie toegewezen aan een arrayelement:
var traceArray:Array = new Array();
traceArray[0] = function (aParam:String)
{
trace(aParam);
};
traceArray[0]("hello");
Kiezen tussen instructies en expressies
Als algemene regel gebruikt u een functie-instructie tenzij specifieke omstandigheden het gebruik van een expressie vereisen. Functie-instructies zijn minder uitgebreid en zorgen voor meer consistentie bij het gebruik in zowel de strikte modus als de standaardmodus dan functie-expressies.
Functie-instructies zijn beter leesbaar dan toewijzingsinstructies met functie-expressies. Functie-instructies maken de code compacter en zijn minder verwarrend dan functie-expressies, waarbij u zowel het trefwoord
var
als
function
moet gebruiken.
Functie-instructies zorgen voor meer consistentie in de twee compilermodi. Zo kunt u de puntnotatie gebruiken in zowel de strikte modus als de standaardmodus om een methode aan te roepen die wordt gedeclareerd met een functie-instructie. Dit is niet altijd mogelijk voor methoden die worden gedeclareerd met een functie-expressie. Met de volgende code wordt bijvoorbeeld een klasse gedefinieerd met de naam Example met twee methoden:
methodExpression()
, gedeclareerd met een functie-expressie, en
methodStatement()
, gedeclareerd met een functie-instructie. In de strikte modus kunt u geen puntnotatie gebruiken om de methode
methodExpression()
aan te roepen.
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
Functie-expressies zijn over het algemeen beter geschikt voor programmeerdoeleinden die georiënteerd zijn op dynamisch gedrag bij uitvoering. Als u in de strikte modus wilt werken maar ook een methode moet aanroepen die wordt gedeclareerd met een functie-expressie, kunt u een van de volgende twee technieken toepassen. Met de eerste techniek roept u de methode aan met behulp van vierkante haakjes (
[]
) in plaats van de puntoperator (
.
). De volgende methodeaanroep is mogelijk in zowel de strikte modus als de standaardmodus:
myExample["methodLiteral"]();
Met de tweede techniek declareert u de gehele klasse als dynamische klasse. Hoewel u de methode zo wel kunt aanroepen met de puntoperator, gaat dit ten koste van enige functionaliteit van de strikte modus voor alle instanties van die klasse. De compiler genereert bijvoorbeeld geen fout wanneer u toegang probeert te krijgen tot een ongedefinieerde eigenschap voor een instantie van een dynamische klasse.
Er zijn enkele omstandigheden waarin functie-expressies nuttig zijn. Functie-expressies worden vaak gebruikt voor functies die maar eenmalig worden toegepast. Minder vaak worden ze gebruikt om een functie te koppelen aan een prototype-eigenschap. Zie Prototypeobject voor meer informatie.
Er zijn twee subtiele verschillen tussen functie-instructies en functie-expressies waarmee u rekening moet houden wanneer u kiest welke techniek u gebruikt. Het eerste verschil is dat functie-expressies niet als onafhankelijke objecten bestaan met betrekking tot geheugenbeheer en opschonen. Met andere woorden, wanneer u een functie-expressie toewijst aan een ander object, zoals een arrayelement of een objecteigenschap, maakt u de enige verwijzing naar die functie in de code. Als de array of het object waaraan de functie-expressie is gekoppeld buiten het bereik valt of om een andere reden niet meer beschikbaar is, hebt u geen toegang meer tot de functie-expressie. Als de array of het object wordt verwijderd, komt het geheugen van de functie-expressie in aanmerking voor opschonen ofwel beschikbaar voor andere doeleinden.
Het volgende voorbeeld laat zien dat voor een functie-expressie na het verwijderen van de eigenschap waaraan de expressie is toegewezen, de functie niet meer beschikbaar is. De klasse Test is van het type dynamic, wat betekent dat u een eigenschap met de naam
functionExp
kunt toevoegen met een functie-expressie. De functie
functionExp()
kan worden aangeroepen met de puntoperator, maar nadat de eigenschap
functionExp
is verwijderd, is de functie niet meer beschikbaar.
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
Als de functie eerst wordt gedefinieerd met een functie-instructie, bestaat deze als een eigen object, ook als de eigenschap wordt verwijderd waaraan de functie is gekoppeld. De operator
delete
werkt alleen voor eigenschappen van objecten. Een aanroep om de functie
stateFunc()
zelf te verwijderen, werkt dus niet.
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
Het tweede verschil tussen functie-instructies en functie-expressies is dat functie-instructies bestaan in het gehele bereik waarin ze worden gedefinieerd, ook in instructies die vóór de functie-instructie staan. Functie-expressies daarentegen worden alleen gedefinieerd voor daaropvolgende instructies. In de volgende code wordt de functie
scopeTest()
bijvoorbeeld aangeroepen voordat deze is gedefinieerd:
statementTest(); // statementTest
function statementTest():void
{
trace("statementTest");
}
Functie-expressies zijn niet beschikbaar voordat ze worden gedefinieerd. De volgende code resulteert dan ook in een uitvoeringsfout:
expressionTest(); // run-time error
var expressionTest:Function = function ()
{
trace("expressionTest");
}
Waarden retourneren uit functies
Als u een waarde wilt retourneren uit een functie, gebruikt u de instructie
return
gevolgd door de expressie of letterlijke waarde die u wilt laten retourneren. De volgende code retourneert bijvoorbeeld een expressie die de parameter vertegenwoordigt:
function doubleNum(baseNum:int):int
{
return (baseNum * 2);
}
U ziet dat de instructie
return
de functie beëindigt, zodat instructies onder een instructie
return
niet worden uitgevoerd:
function doubleNum(baseNum:int):int {
return (baseNum * 2);
trace("after return"); // This trace statement will not be executed.
}
In de strikte modus moet u een waarde van het geschikte type retourneren als u ervoor kiest een retourneringstype op te geven. De volgende code genereert bijvoorbeeld een fout in de strikte modus, omdat geen geldige waarde wordt geretourneerd:
function doubleNum(baseNum:int):int
{
trace("after return");
}
Geneste functies
U kunt functies nesten, wat betekent dat u functies kunt declareren binnen andere functies. Een geneste functie is alleen beschikbaar binnen de bovenliggende functie, tenzij een verwijzing naar de functie wordt doorgegeven naar externe code. De volgende code declareert bijvoorbeeld twee geneste functies binnen de functie
getNameAndVersion()
:
function getNameAndVersion():String
{
function getVersion():String
{
return "10";
}
function getProductName():String
{
return "Flash Player";
}
return (getProductName() + " " + getVersion());
}
trace(getNameAndVersion()); // Flash Player 10
Wanneer geneste functies worden doorgegeven aan externe code, gebeurt dit als een functie closure. Dit betekent dat de functie de definities behoudt die binnen het bereik vallen wanneer de functie wordt gedefinieerd. Zie Functiebereik voor meer informatie.
Functieparameters
ActionScript 3.0 biedt enige functionaliteit voor functieparameters die mogelijk nieuw lijkt voor programmeurs zonder ervaring in deze taal. Hoewel het idee van parameters doorgeven als waarde of als verwijzing bij de meeste programmeurs bekend zal zijn, geldt dat mogelijk niet voor het object
arguments
en de parameter ... (rest).
Argumenten doorgeven als waarde of als verwijzing
In veel programmeertalen is het van belang het onderscheid te weten tussen het doorgeven van argumenten als waarde of als verwijzing. Dit onderscheid kan van invloed zijn op de wijze waarop code wordt samengesteld.
Doorgeven als waarde betekent dat de waarde van het argument wordt gekopieerd naar een lokale variabele om in de functie te gebruiken. Doorgeven als verwijzing betekent dat alleen een verwijzing naar het argument wordt doorgegeven en niet de feitelijke waarde. Er wordt geen kopie van het eigenlijke argument gemaakt. In plaats daarvan wordt een verwijzing naar de variabele doorgegeven als een argument wordt gemaakt en toegewezen aan een lokale variabele voor gebruik in de functie. Als verwijzing naar een variabele buiten de functie geeft de lokale variabele u de mogelijkheid om de waarde van de oorspronkelijke variabele te wijzigen.
In ActionScript 3.0 worden alle argumenten doorgegeven als verwijzing, omdat alle waarden als objecten worden opgeslagen. Objecten die behoren tot de primitieve gegevenstypen (Boolean, Number, int, uint en String) hebben speciale operatoren waardoor ze gedrag vertonen alsof ze als waarde zijn doorgegeven. Met de volgende code wordt bijvoorbeeld een functie gemaakt met de naam
passPrimitives()
die twee parameters definieert met de naam
xParam
en
yParam
, beide van het type int. Deze parameters lijken op lokale variabelen die worden gedeclareerd in de hoofdtekst van de functie
passPrimitives()
. Wanneer de functie wordt aangeroepen met de argumenten
xValue
en
yValue
, worden de parameters
xParam
en
yParam
geïnitialiseerd met verwijzingen naar de objecten int vertegenwoordigd door
xValue
en
yValue
. Omdat de argumenten primitieven zijn, gedragen deze zich alsof ze als waarde zijn doorgegeven. Hoewel
xParam
en
yParam
eerst alleen verwijzingen bevatten naar de objecten
xValue
en
yValue
, genereren wijzigingen in de variabelen in de hoofdtekst van de functie nieuwe kopieën van de waarden in het geheugen.
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
Binnen de functie
passPrimitives()
worden de waarden van
xParam
en
yParam
verhoogd. Dit heeft echter geen invloed op de waarden van
xValue
en
yValue
, zoals wordt getoond in de laatste instructie
trace
. Dit geldt ook als de parameters dezelfde naam zouden hebben als de variabelen,
xValue
en
yValue
, omdat de
xValue
en
yValue
binnen de functie naar nieuwe locaties in het geheugen zouden wijzen die afzonderlijk bestaan van de variabelen met dezelfde naam buiten de functie.
Alle andere objecten (die niet behoren tot de primitieve gegevenstypen) worden altijd doorgegeven als verwijzing. Dit maakt het mogelijk de waarde van de oorspronkelijke variabele te wijzigen. Met de volgende code wordt bijvoorbeeld een object gemaakt met de naam
objVar
met twee eigenschappen:
x
en
y
. Het object wordt als argument aan de functie
passByRef()
doorgegeven. Aangezien het object geen primitief type is, wordt het object niet alleen als verwijzing doorgegeven, maar blijft het ook een verwijzing. Dit betekent dat wijzigingen in parameters binnen de functie van invloed zijn op de objecteigenschappen buiten de functie.
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
De parameter
objParam
verwijst naar hetzelfde object als de algemene variabele
objVar
. Zoals u kunt zien in de instructies
trace
in het voorbeeld, worden wijzigingen in de eigenschappen
x
en
y
van het object
objParam
weergegeven in het object
objVar
.
Standaardparameterwaarden
In ActionScript 3.0 kunt u voor een functie
standaardparameterwaarden
declareren. Als bij het aanroepen van een functie met standaardparameterwaarden een parameter met standaardwaarden wordt weggelaten, wordt de opgegeven waarde in de functiedefinitie voor die parameter gebruikt. Alle parameters met standaardwaarden moeten aan het eind van de lijst met parameters worden geplaatst. De toegewezen standaardwaarden moeten constanten bij compileren zijn. Het bestaan van een standaardwaarde voor een parameter maakt van die parameter feitelijk een
optionele parameter
. Een parameter zonder standaardwaarde wordt als
vereiste parameter
beschouwd.
Met de volgende code wordt bijvoorbeeld een functie met drie parameters gemaakt, waarvan er twee een standaardwaarde hebben. Wanneer de functie wordt aangeroepen met slechts één parameter, worden de standaardwaarden voor de parameters gebruikt.
function defaultValues(x:int, y:int = 3, z:int = 5):void
{
trace(x, y, z);
}
defaultValues(1); // 1 3 5
Het object arguments
Wanneer parameters worden doorgegeven aan een functie, kunt u het object
arguments
gebruiken voor toegang tot informatie over de parameters die aan de functie worden doorgegeven. Sommige belangrijke aspecten van het object
arguments
zijn onder meer:
-
Het object
arguments
is een array met alle parameters die aan de functie worden doorgegeven.
-
De eigenschap
arguments.length
rapporteert het aantal parameters dat aan de functie wordt doorgegeven.
-
De eigenschap
arguments.callee
zorgt voor een verwijzing naar de functie zelf, wat nuttig is voor recursieve aanroepen van functie-expressies.
Opmerking:
Het object
arguments
is niet beschikbaar als een parameter de naam
arguments
heeft of als u de parameter ... (rest) gebruikt.
Als vanuit het hoofdgedeelte van een functie wordt verwezen naar het object
arguments
, kunnen functieoproepen in ActionScript 3.0 meer parameters bevatten dan in de functiedefinitie zijn gedefinieerd. In de strikte modus wordt echter een compilatiefout gegenereerd als het aantal parameters niet overeenkomt met het aantal vereiste parameters (en desgewenst eventuele optionele parameters). U kunt het arrayaspect van het object
arguments
gebruiken voor toegang tot parameters die aan de functie worden doorgegeven, of de parameter nu is gedefinieerd in de functiedefinitie of niet. In het volgende voorbeeld, dat alleen in de standaardmodus kan worden gecompileerd, wordt de array
arguments
gebruikt samen met de eigenschap
arguments.length
om alle parameters te traceren die aan de functie
traceArgArray()
worden doorgegeven:
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
De eigenschap
arguments.callee
wordt vaak gebruikt in anonieme functies om herhaling te bewerkstelligen. U kunt daarmee flexibiliteit toevoegen aan uw code. Als de naam van een recursieve functie verandert gedurende de ontwikkelingscyclus, hoeft u zich geen zorgen te maken om de recursieve aanroep in de hoofdtekst van de functie te wijzigen als u
arguments.callee
gebruikt in plaats van de functienaam. De eigenschap
arguments.callee
wordt gebruikt in de volgende functie om herhaling mogelijk te maken:
var factorial:Function = function (x:uint)
{
if(x == 0)
{
return 1;
}
else
{
return (x * arguments.callee(x - 1));
}
}
trace(factorial(5)); // 120
Als u de parameter ... (rest) gebruikt in uw functiedeclaratie, is het object
arguments
voor u niet beschikbaar. In plaats daarvan hebt u toegang tot de parameters met de parameternamen die u daarvoor declareert.
Zorg er ook voor dat u de tekenreeks
'arguments'
niet gebruikt als parameternaam, wat als schaduw van het object
arguments
zou werken. Als de functie
traceArgArray()
bijvoorbeeld wordt herschreven zodat een parameter
arguments
wordt toegevoegd, verwijzen de verwijzingen naar
arguments
in de hoofdtekst van de functie naar de parameter in plaats van naar het object
arguments
. De volgende code produceert geen uitvoer:
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
Het object
arguments
in eerdere versies van ActionScript bevatte ook een eigenschap met de naam
caller
, ofwel een verwijzing naar de functie die de huidige functie aanroept. De eigenschap
caller
wordt niet meer gebruikt in ActionScript 3.0. Als u echter moet verwijzen naar de aanroepende functie, kunt u de aanroepende functie een extra parameter laten doorgeven als verwijzing naar de functie zelf.
De parameter ... (rest)
ActionScript 3.0 introduceert een nieuwe parameterdeclaratie: de parameter ... (rest). Met deze parameter kunt u een arrayparameter opgeven die een willekeurig aantal door komma's gescheiden argumenten accepteert. De parameter kan elke naam hebben die geen gereserveerd woord is. Deze parameterdeclaratie moet de laatste parameter zijn die wordt opgegeven. Wanneer u deze parameter gebruikt, is het object
arguments
niet beschikbaar. Hoewel de parameter ... (rest) dezelfde functionaliteit biedt als de array
arguments
en de eigenschap
arguments.length
, ontbreekt de functionaliteit die
arguments.callee
biedt. U moet ervoor zorgen dat u
arguments.callee
niet hoeft te gebruiken voordat u de parameter ... (rest) gebruikt.
In het volgende voorbeeld wordt de functie
traceArgArray()
herschreven met de parameter ... (rest) in plaats van het object
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
U kunt de parameter ... (rest) (als laatste parameter) ook gebruiken met andere parameters. In het volgende voorbeeld wordt de functie
traceArgArray()
zo gewijzigd dat de eerste parameter,
x
, van het type int is en de tweede parameter de parameter ... (rest) gebruikt. Bij de uitvoer wordt de eerste waarde overgeslagen, omdat de eerste parameter geen onderdeel meer vormt van de array die met de parameter ... (rest) wordt gemaakt.
function traceArgArray(x: int, ... args)
{
for (var i:uint = 0; i < args.length; i++)
{
trace(args[i]);
}
}
traceArgArray(1, 2, 3);
// output:
// 2
// 3
Functies als objecten
Functies in ActionScript 3.0 zijn objecten. Wanneer u een functie maakt, maakt u een object dat als parameter aan een andere functie kan worden doorgegeven én waaraan eigenschappen en methoden kunnen worden gekoppeld.
Het doorgeven van functies als argumenten aan een andere functie gebeurt als verwijzing en niet als waarde. Wanneer u een functie doorgeeft als argument, gebruikt u alleen de id en niet de ronde-haakjesoperator waarmee u de methode aanroept. In de volgende code wordt bijvoorbeeld een functie met de naam
clickListener()
doorgegeven als argument aan de methode
addEventListener()
:
addEventListener(MouseEvent.CLICK, clickListener);
Hoewel dit voor programmeurs zonder ervaring in ActionScript wat vreemd kan lijken, kunnen functies eigenschappen en methoden hebben, net als andere objecten. In feite heeft elke functie een alleen-lezen eigenschap met de naam
length
waarin het aantal gedefinieerde parameters voor de functie wordt opgeslagen. Dit verschilt van de eigenschap
arguments.length
, die het aantal argumenten aangeeft dat aan de functie wordt doorgegeven. Zoals al eerder is opgemerkt, kan in ActionScript het aantal doorgegeven argumenten aan een functie hoger zijn dan het aantal gedefinieerde parameters voor die functie. In het volgende voorbeeld wordt het verschil getoond tussen de twee eigenschappen (compilatie kan alleen in de standaardmodus, omdat voor de strikte modus is vereist dat het aantal doorgegeven argumenten en het aantal gedefinieerde parameters exact gelijk zijn):
// 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 */
In de standaardmodus kunt u uw eigen functie-eigenschappen definiëren buiten de hoofdtekst van de functie. U kunt functie-eigenschappen als quasi-statische eigenschappen gebruiken, zodat u de status van een variabele in relatie tot de functie kunt opslaan. U wilt bijvoorbeeld het aantal keren bijhouden dat een bepaalde functie wordt aangeroepen. Een dergelijke functionaliteit kan nuttig zijn als u een spel ontwikkelt en wilt bijhouden hoe vaak een gebruiker een bepaalde opdracht gebruikt, hoewel u daar ook een statische klasseneigenschap voor kunt gebruiken. Met de volgende code wordt een functie-eigenschap gemaakt buiten de functiedeclaratie en wordt de eigenschap verhoogd telkens wanneer de functie wordt aangeroepen. Dit voorbeeld kan alleen worden gecompileerd in de standaardmodus omdat het in de strikte modus niet mogelijk is dynamische eigenschappen toe te voegen aan functies.
// Compiles only in standard mode
var someFunction:Function = function ():void
{
someFunction.counter++;
}
someFunction.counter = 0;
someFunction();
someFunction();
trace(someFunction.counter); // 2
Functiebereik
Het bereik van een functie bepaalt waar in een programma die functie kan worden aangeroepen en tot welke definities de functie toegang heeft. Dezelfde bereikregels die gelden voor variabele-id's gelden ook voor functie-id's. Een functie die wordt gedeclareerd in het algemene bereik, is in de gehele code beschikbaar. ActionScript 3.0 bevat bijvoorbeeld algemene functies, zoals
isNaN()
en
parseInt()
, die overal in de code beschikbaar zijn. Een geneste functie (gedeclareerd binnen een andere functie) kan overal in de functie worden gebruikt waarin het is gedeclareerd.
De bereikketen
Aan het begin wanneer een functie wordt uitgevoerd, wordt een aantal objecten en eigenschappen gemaakt. Eerst wordt een speciaal
activeringsobject
gemaakt met de parameters en de lokale variabelen of functies die in de hoofdtekst van de functie zijn gedeclareerd. U hebt geen directe toegang tot het activeringsobject, omdat het een intern mechanisme betreft. Vervolgens wordt een
bereikketen
gemaakt met een geordende lijst met objecten die tijdens de uitvoering wordt gecontroleerd op id-declaraties. Elke uitgevoerde functie heeft een bereikketen die in een interne eigenschap wordt opgeslagen. Voor een geneste functie begint de bereikketen met het eigen activeringsobject, gevolgd door het activeringsobject van de bovenliggende functie. De keten gaat op deze wijze verder tot het algemene object is bereikt. Het algemene object wordt gemaakt wanneer een ActionScript-programma begint en dit object bevat alle algemene variabelen en functies.
Functie closure
Een
functie closure
is een object met een momentopname van een functie en de bijbehorende
lexicale omgeving
. De lexicale omgeving van een functie omvat alle variabelen, eigenschappen, methoden en objecten in de bereikketen van de functie, samen met de waarden ervan. Een functie closure wordt gemaakt telkens wanneer een functie wordt uitgevoerd apart van een object of een klasse. Het feit dat een functie closure het bereik behoudt waarin deze is gedefinieerd, levert interessante resultaten op wanneer een functie als argument of geretourneerde waarde in een ander bereik wordt doorgegeven.
Met de volgende code worden bijvoorbeeld twee functies gemaakt:
foo()
, die een geneste functie retourneert met de naam
rectArea()
waarmee de oppervlakte van een rechthoek wordt berekend, en
bar()
, die
foo()
aanroept en de geretourneerde functie closure opslaat in een variabele met de naam
myProduct
. Ook al definieert de functie
bar()
de eigen lokale variabele
x
(met een waarde van 2), wordt bij het aanroepen van de functie closure
myProduct()
de variabele
x
behouden (met een waarde van 40) die is gedefinieerd in de functie
foo().
De functie
bar()
retourneert dan ook de waarde
160
in plaats van
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
Methoden vertonen hetzelfde gedrag wat betreft het behouden van informatie over de lexicale omgeving waarin ze zijn gemaakt. Dit valt het meest op wanneer een methode wordt geëxtraheerd uit de instantie ervan, wat resulteert in een gebonden methode. Het belangrijkste verschil tussen een functie closure en een gebonden methode is dat de waarde van het trefwoord
this
in een gebonden methode altijd verwijst naar de instantie waaraan deze eerst was gekoppeld, terwijl in een functie closure de waarde van het trefwoord
this
kan veranderen.
|
|
|