FunktionenFunktionen sind Codeblöcke, die bestimmte Aufgaben ausführen und an anderer Stelle in einem Programm wiederverwendet werden können. In ActionScript 3.0 wird zwischen zwei Funktionstypen unterschieden: Methoden und Funktionshüllen. Ob eine Funktion als eine Methode oder Funktionshülle bezeichnet wird, hängt von dem Kontext ab, in dem die Funktion definiert ist. Eine Funktion wird als eine Methode bezeichnet, wenn Sie sie als Teil der Klassendefinition definieren oder an eine Instanz eines Objekts anhängen. Eine Funktion wird als ein Funktionshülle bezeichnet, wenn sie auf eine andere Weise definiert wurde. Funktionen waren in ActionScript schon immer extrem wichtig. In ActionScript 1.0 war beispielsweise das Schlüsselwort class noch nicht bekannt, daher wurden „Klassen“ durch Konstruktorfunktionen definiert. Obwohl das Schlüsselwort class der Programmsprache inzwischen hinzugefügt wurde, ist noch immer ein solides Grundwissen über Funktionen wichtig, wenn Sie alle Vorteile der Sprache nutzen möchten. Dies kann eine schwierige Aufgabe für Programmierer sein, die davon ausgehen, dass sich Funktionen in ActionScript ähnlich wie in anderen Sprachen, z. B. C++ oder Java, verhalten. Obwohl das allgemeine Definieren und Aufrufen von Funktionen keine Herausforderung für einen erfahrenen Programmierer darstellt, erfordern einige erweiterte ActionScript-Funktionen doch eine Erklärung. GrundfunktionenAufrufen von FunktionenEine Funktion wird mit ihrem Bezeichner und anschließender Eingabe des Klammernoperators (()) aufgerufen. Der Klammernoperator nimmt alle Funktionsparameter auf, die Sie an die Funktion übergeben möchten. Beispielsweise ist trace() eine Funktion der obersten Ebene in ActionScript 3.0: trace("Use trace to help debug your script"); Wenn Sie eine Funktion ohne Parameter aufrufen, müssen Sie ein leeres Paar runder Klammern angeben. Zum Erzeugen einer Zufallszahl können Sie beispielsweise die Math.random()-Methode verwenden, die ohne Parameter arbeitet: var randomNum:Number = Math.random(); Definieren eigener FunktionenFunktionen können in ActionScript 3.0 auf zwei Arten definiert werden: mit einer Funktionsanweisung oder einem Funktionsausdruck. Die von Ihnen gewählte Technik hängt davon ab, ob Sie einen statischen oder dynamischen Programmierstil bevorzugen. Wenn Sie das statische Programmieren bzw. den strikten Modus bevorzugen, definieren Sie Ihre Funktionen mit Funktionsanweisungen. Definieren Sie Ihre Funktionen mit Funktionsausdrücken, wenn dies aus bestimmten Gründen erforderlich ist. Funktionsausdrücke werden häufiger bei der dynamischen Programmierung bzw. im Standardmodus eingesetzt. FunktionsanweisungenFunktionsanweisungen stellen die bevorzugte Technik bei der Definition von Funktionen im strikten Modus dar. Eine Funktionsanweisung beginnt mit dem Schlüsselwort function, gefolgt von:
Im folgenden Beispielcode wird eine Funktion erstellt, die einen Parameter definiert und dann die Funktion mit dem String „ hello“ als Parameterwert aufruft: function traceParameter(aParam:String) { trace(aParam); } traceParameter("hello"); // hello FunktionsausdrückeDas zweite Verfahren zum Deklarieren einer Funktion verwendet eine Funktionsanweisung mit einem Funktionsausdruck, der manchmal auch als ein Funktionsliteral oder als eine anonyme Funktion bezeichnet wird. Dies ist eine wesentlich ausführlichere Methode, die häufig in früheren Versionen von ActionScript verwendet wurde. Eine Funktionsanweisung mit einem Funktionsausdruck beginnt mit dem Schlüsselwort var, gefolgt von:
Auswählen zwischen Anweisungen und AusdrückenIm Allgemeinen verwenden Sie eine Funktionsanweisung, es sei denn, besondere Umstände verlangen nach einem Ausdruck. Funktionsanweisungen sind weniger ausführlich und bieten eine einheitlichere Führung zwischen dem strikten Modus und dem Standardmodus als Funktionsausdrücke. Funktionsanweisungen sind einfacher zu lesen als Zuweisungsanweisung, die Funktionsausdrücke enthalten. Funktionsanweisungen halten den Code kurz und sind einfacher zu verstehen als Funktionsausdrücke, für die Sie die beiden Schlüsselwörter var und function verwenden müssen. Funktionsanweisungen sorgen für eine einheitlichere Führung zwischen den beiden Compiler-Modi, da Sie die Punktsyntax sowohl im strikten als auch im Standardmodus verwenden können, um eine Methode aufzurufen, die mit einer Funktionsanweisung deklariert wurde. Dies gilt nicht unbedingt für Methoden, die mit einem Funktionsausdruck deklariert wurden. Der folgende Code generiert beispielsweise eine Klasse namens „Example“ mit zwei Methoden: methodExpression(), die mit einem Funktionsausdruck deklariert ist, und methodStatement(), die mit einer Funktionsanweisung deklariert ist. Im strikten Modus können Sie die Punktsyntax nicht verwenden, um die methodExpression()-Methode aufzurufen. 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 Funktionsausdrücke sind wesentlich besser zum Programmieren geeignet, wenn das Hauptaugenmerk auf dem Echtzeit- bzw. dynamischen Verhalten liegt. Wenn Sie den strikten Modus bevorzugen, aber ebenfalls eine Methode aufrufen müssen, die mit einem Funktionsausdruck deklariert wurde, können Sie beide Verfahren verwenden. Zunächst können Sie die Methode mit eckigen Klammern ([]) anstelle des Punktoperators (.) aufrufen. Der folgende Methodenaufruf wird sowohl im strikten als auch im Standardmodus erfolgreich ausgeführt: myExample["methodLiteral"](); Alternativ können Sie die gesamte Klasse als dynamische Klasse deklarieren. Obwohl Ihnen dieses Verfahren ermöglicht, die Methode mit dem Punktoperator aufzurufen, gibt es einen Nachteil: Sie opfern einen Teil der Funktionsmerkmale im strikten Modus für alle Instanzen dieser Klasse. Beispielsweise erzeugt der Compiler keinen Fehler, wenn Sie versuchen, bei einer Instanz einer dynamischen Klasse auf eine undefinierte Eigenschaft zuzugreifen. Es gibt einige Situationen, in denen Funktionsausdrücke sinnvoll sind. Häufig werden Funktionsausdrücke für Funktionen genutzt, die nur einmal verwendet und dann verworfen werden. Eine weitere weniger übliche Anwendungsmöglichkeit ist das Anfügen einer Funktion an eine Prototypeigenschaft. Weitere Informationen finden Sie unter Prototypobjekt. Es gibt zwei feine Unterschiede zwischen Funktionsanweisungen und Funktionsausdrücken, die Sie unbedingt bei der Auswahl der zu verwendenden Technik berücksichtigen sollten. Der erste Unterschied ist, dass Funktionsausdrücke hinsichtlich der Speicherverwaltung und -bereinigung (Garbage Collection) nicht unabhängig als Objekte existieren. Anders ausgedrückt, wenn Sie einen Funktionsausdruck einem anderen Objekt zuweisen (beispielsweise einem Array-Element oder einer Objekteigenschaft), erstellen Sie in Ihrem Code lediglich einen Verweis auf diesen Funktionsausdruck. Wenn das Array oder Objekt, an das Ihr Funktionsausdruck angehängt ist, außerhalb des Gültigkeitsbereichs gerät oder aus anderen Gründen nicht mehr zur Verfügung steht, ist kein Zugriff auf den Funktionsausdruck mehr möglich. Wenn das Array oder Objekt gelöscht wurde, wird der vom Funktionsausdruck belegte Speicher für die Garbage Collection verfügbar. Dies bedeutet, dass der Speicherbereich für andere Zwecke neu vergeben werden kann. Das folgende Beispiel zeigt einen Funktionsausdruck, in dem die Funktion nicht mehr zur Verfügung steht, nachdem die Eigenschaft, welcher der Ausdruck zugewiesen war, gelöscht wurde. Die Test-Klasse ist dynamisch. Dies bedeutet, Sie können eine Eigenschaft namens functionExp hinzufügen, die einen Funktionsausdruck aufnimmt. Die functionExp()-Funktion kann mit dem Punktoperator aufgerufen werden, aber nachdem die Eigenschaft functionExp gelöscht wurde, kann nicht mehr auf die Funktion zugegriffen werden. 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 Wenn die Funktion andererseits zuerst mit einer Funktionsanweisung definiert wird, existiert sie als eigenständiges Objekt und kann auch weiterhin verwendet werden, nachdem die Eigenschaft gelöscht wurde, an die sie angefügt wurde. Der Operator delete kann nur mit Eigenschaften von Objekten verwendet werden. Daher hat auch ein Aufruf zum Löschen der Funktion stateFunc() keine Auswirkungen. 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 Der zweite Unterschied zwischen Funktionsanweisungen und Funktionsausdrücken besteht darin, dass Funktionsanweisungen im gesamten Gültigkeitsbereich existieren, in dem sie definiert wurden. Hierzu zählen auch die Anweisungen, die vor der Funktionsanweisung stehen. Im Gegensatz dazu sind Funktionsausdrücke nur für nachfolgende Anweisungen definiert. Im folgenden Codebeispiel wird die scopeTest()-Funktion erfolgreich aufgerufen, bevor sie definiert wird: statementTest(); // statementTest function statementTest():void { trace("statementTest"); } Funktionsausdrücke sind erst verfügbar, nachdem sie definiert wurden. Aus diesem Grund führt der folgende Code zu einem Laufzeitfehler: expressionTest(); // run-time error var expressionTest:Function = function () { trace("expressionTest"); } Zurückgeben von Werten aus FunktionenWenn Ihre Funktion einen Wert zurückgeben soll, verwenden Sie die return-Anweisung gefolgt von dem Ausdruck oder Literalwert, der zurückgegeben werden soll. Der folgende Code gibt beispielsweise einen Ausdruck zurück, der einen Parameter darstellt: function doubleNum(baseNum:int):int { return (baseNum * 2); } Beachten Sie, dass die return-Anweisung die Funktion beendet. Das heißt, alle Anweisungen nach einer return-Anweisung werden nicht ausgeführt, wie im folgenden Code dargestellt: function doubleNum(baseNum:int):int { return (baseNum * 2); trace("after return"); // This trace statement will not be executed. } Im strikten Modus müssen Sie einen Wert des entsprechenden Typs zurückgeben, wenn Sie einen Rückgabetyp festgelegt haben. Mit dem folgenden Code wird im strikten Modus eine Fehlermeldung erzeugt, da er keinen gültigen Wert zurückgibt: function doubleNum(baseNum:int):int { trace("after return"); } Verschachtelte FunktionenSie können Funktionen verschachteln; anders ausgedrückt, Sie können Funktionen innerhalb von anderen Funktionen deklarieren. Eine verschachtelte Funktion steht nur innerhalb ihrer übergeordneten Funktion zur Verfügung, es sei denn, dem externen Code wurde ein Verweis auf die Funktion übergeben. Im folgenden Codebeispiel werden zwei verschachtelte Funktionen in der Funktion getNameAndVersion() deklariert: function getNameAndVersion():String { function getVersion():String { return "10"; } function getProductName():String { return "Flash Player"; } return (getProductName() + " " + getVersion()); } trace(getNameAndVersion()); // Flash Player 10 Verschachtelte Funktionen werden als Funktionshüllen an einen externen Code übergeben. Dies bedeutet, dass die Funktion alle Definitionen beibehält, die sich beim Definieren der Funktion in ihrem Gültigkeitsbereich befanden. Weitere Informationen finden Sie unter Gültigkeitsbereich von Funktionen. FunktionsparameterActionScript 3.0 umfasst einige Funktionsmerkmale für Funktionsparameter, die weniger erfahrenen ActionScript-Programmierern wahrscheinlich unbekannt sind. Die Idee der Übergabe von Parametern als Wert oder als Verweis dürfte den meisten Programmierern vertraut sein, während das arguments-Objekt und der ...-Parameter (Rest) wohl vielen unbekannt sein dürften. Übergeben von Argumenten als Wert oder als VerweisBei vielen Programmiersprachen ist es wichtig, den Unterschied zwischen der Übergabe von Argumenten als Wert (Englisch „pass by value“) oder als Verweis (Englisch „pass by reference“) zu verstehen. Der Unterschied kann sich auf das Codedesign auswirken. Eine Übergabe als Wert bedeutet, dass der Wert des Arguments in ein lokale Variable kopiert wird, damit er innerhalb der Funktion verwendet werden kann. Eine Übergabe als Verweis bedeutet, dass nur ein Verweis auf das Argument anstelle des tatsächlichen Wertes übergeben wird. Es wird keine Kopie des tatsächlichen Arguments erstellt. Stattdessen wird ein Verweis auf die als Argument übergebene Variable erstellt und einer lokalen Variablen für die Verwendung innerhalb der Funktion zugewiesen. Als Verweis auf eine Variable außerhalb der Funktion ermöglicht die lokale Variable das Ändern des Wertes der Ursprungsvariablen. In ActionScript 3.0 werden alle Argumente als Verweis übergeben, da alle Werte als Objekte gespeichert sind. Objekte, die zu den Grunddatentypen gehören (Boolean, Number, int, uint und String), haben besondere Operatoren, durch die sich Objekte so verhalten können, als würden sie als Wert übergeben. Im folgenden Beispielcode wird eine Funktion namens passPrimitives() erstellt, die zwei Parameter namens xParam und yParam definiert; beides Parameter des Datentyps „int“. Diese Parameter ähneln lokalen Variablen, die innerhalb des Rumpfs der passPrimitives()-Funktion deklariert wurden. Wenn die Funktion mit den Argumenten xValue und yValue aufgerufen wird, werden die Parameter xParam und yParam mit Verweisen auf die int-Objekte initiiert, die von xValue und yValue dargestellt werden. Da diese Argumente Grundtypen sind, verhalten sie sich so, als wenn sie als Wert übergeben worden wären. Obwohl xParam und yParam zunächst nur Verweise auf die Objekte xValue und yValue enthalten, erzeugen alle Änderungen an den Variablen innerhalb des Funktionsrumpfs neue Kopien der Werte im Arbeitsspeicher. 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 In der passPrimitives()-Funktion werden die Werte von xParam und yParam erhöht. Dies wirkt sich jedoch nicht auf die Werte von xValue und yValue aus, wie aus der letzten trace-Anweisung ersichtlich ist. Dies würde eintreten, wenn die Parameter mit den gleichen Namen wie die Variablen xValue und yValue benannt wären, da xValue und yValue innerhalb der Funktion auf neue Speicherstellen im Arbeitsspeicher verweisen würden, die separat von den Variablen mit dem gleichen Namen außerhalb der Funktion existieren würden. Alle anderen Objekte, also Objekte, die nicht zu den Grundtypen gehören, werden immer als Verweis übergeben, sodass Sie die Werte der Ursprungsvariablen ändern können. Im folgenden Beispielcode wird ein Objekt namens objVar mit zwei Eigenschaften erstellt, x und y. Das Objekt wird als Argument an die Funktion passByRef() übergeben. Da das Objekt nicht zu den Grundtypen gehört, wird es nicht nur als Verweis übergeben, sondern bleibt auch ein Verweis. Dies bedeutet, dass sich Änderungen an den Parametern innerhalb der Funktion auf die Objekteigenschaften außerhalb der Funktion auswirken. 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 Der objParam-Parameter verweist auf das gleiche Objekt wie die globale Variable objVar. Wie Sie anhand der trace-Anweisungen im Codebeispiel sehen können, werden Änderungen an den Eigenschaften x und y des objParam-Objekts im objVar-Objekt widergespiegelt. Standard-ParameterwerteIn ActionScript 3.0 können Sie Standardparameterwerte für eine Funktion deklarieren. Wenn ein Aufruf einer Funktion mit Standard-Parameterwerten einen Parameter mit Standardwerten weglässt, wird der in der Funktionsdefinition angegebene Wert für diesen Parameter verwendet. Alle Parameter mit Standardwerten müssen am Ende der Parameterliste platziert werden. Bei den als Standardwerte zugewiesenen Werten muss es sich um Konstanten zur Kompilierzeit handeln. Das Vorhandensein eines Standardwerts für einen Parameter macht diesen Parameter zu einem optionalen Parameter. Ein Parameter ohne Standardwert wird als erforderlicher Parameter betrachtet. Im folgenden Codebeispiel wird eine Funktion mit drei Parametern erstellt, von denen zwei Standardwerte aufweisen. Wenn die Funktion mit nur einem Parameter aufgerufen wird, werden die Standardwerte für die Parameter verwendet. function defaultValues(x:int, y:int = 3, z:int = 5):void { trace(x, y, z); } defaultValues(1); // 1 3 5 arguments-ObjektWenn Parameter an eine Funktion übergeben werden, können Sie mit dem arguments-Objekt auf Informationen über die an Ihre Funktion übergebenen Parameter zugreifen. Einige wichtige Aspekte des arguments-Objekts sind:
... (rest)-ParameterMit ActionScript 3.0 wurde eine neue Parameterdeklaration mit der Bezeichnung ... (rest)-Parameter eingeführt. Mit diesem Parameter können Sie einen Array-Parameter angeben, der mit einer beliebigen Anzahl von kommagetrennten Argumenten arbeitet. Der Parameter kann jeden Namen annehmen, der kein reserviertes Wort ist. Diese Parameterdeklaration muss der letzte angegebene Parameter sein. Wenn Sie diesen Parameter verwenden, steht das Objekt arguments nicht mehr zur Verfügung. Obwohl Ihnen der Parameter „... (rest)“ die gleichen Funktionsmerkmale wie das arguments-Array und die arguments.length-Eigenschaft zur Verfügung stellt, verfügt es nicht über die Funktionsmerkmale, der Ihnen von arguments.callee bereitgestellt werden. Bevor Sie den ... (rest)-Parameter einsetzen, müssen Sie sicherstellen, dass Sie arguments.callee nicht benötigen. Im folgenden Beispielcode wird die traceArgArray()-Funktion mit dem ... (rest)-Parameter anstelle des arguments-Objekts neu geschrieben: function traceArgArray(... args):void { for (var i:uint = 0; i < args.length; i++) { trace(args[i]); } } traceArgArray(1, 2, 3); // output: // 1 // 2 // 3 Der ... (rest)-Parameter kann zusammen mit anderen Parametern verwendet werden, er muss jedoch der letzte angegebene Parameter sein. Im folgenden Beispielcode wird die traceArgArray()-Funktion so geändert, dass der erste Parameter x den Datentyp „int“ aufweist und der zweite Parameter den ... (rest)-Parameter verwendet: Die Ausgabe überspringt den ersten Wert, weil der Parameter jetzt kein Teil des Arrays mehr ist, das vom ... (rest)-Parameter erstellt wurde. function traceArgArray(x: int, ... args) { for (var i:uint = 0; i < args.length; i++) { trace(args[i]); } } traceArgArray(1, 2, 3); // output: // 2 // 3 Funktionen als ObjekteFunktionen in ActionScript 3.0 sind Objekte. Beim Erstellen einer Funktion erstellen Sie ein Objekt, das nicht nur als Parameter an eine andere Funktion übergeben werden kann, sondern dem auch Eigenschaften und Methoden angefügt werden können. Funktionen, die als Argumente an eine weitere Funktion übergeben werden, werden als Verweis und nicht als Wert übergeben. Wenn Sie eine Funktion als ein Argument übergeben, verwenden Sie nur den Bezeichner und nicht den Klammernoperator, der zum Aufrufen der Methode verwendet wird. Im folgenden Beispielcode wird eine Funktion namens clickListener() als ein Argument an die addEventListener()-Methode übergeben: addEventListener(MouseEvent.CLICK, clickListener); Obwohl es in ActionScript unerfahrenen Programmierern seltsam erscheinen mag, können Funktionen ebenso wie jedes andere Objekte Eigenschaften und Methoden aufweisen. Tatsächlich verfügt jede Funktion über eine schreibgeschützte Eigenschaft namens length, in der die Anzahl der Parameter gespeichert wird, die für die Funktion definiert wurden. Dies unterscheidet sich von der arguments.length-Eigenschaft, welche die Anzahl der Argumente meldet, die an die Funktion gesendet werden. Sie erinnern sich, dass in ActionScript die Anzahl der Argumente, die an eine Funktion gesendet werden, die Anzahl der Parameter übersteigen kann, die für diese Funktion definiert wurden. Das folgende Beispiel, das nur im Standardmodus kompiliert wird, da im strikten Modus die Anzahl der übergebenen Argumente und der definierten Parameter exakt übereinstimmen muss, zeigt die Unterschiede zwischen den beiden Eigenschaften: // 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 */ Im Standardmodus können Sie eigene Funktionseigenschaften definieren, indem Sie die Definition außerhalb des Funktionsrumpfes durchführen. Funktionseigenschaften dienen als quasi-statische Eigenschaften, mit denen Sie den Status einer mit der Funktion verwandten Variablen speichern können. Angenommen Sie möchten verfolgen, wie oft eine bestimmte Funktion aufgerufen wird. Eine solche Funktion ist sinnvoll, wenn Sie ein Spiel schreiben und verfolgen möchten, wie oft ein Benutzer einen bestimmten Befehl verwendet hat. Natürlich können Sie auch die Eigenschaft einer statischen Klasse für diesen Zweck verwenden. Im folgenden Beispielcode wird eine Funktionseigenschaft außerhalb der Funktionsdeklaration erstellt und die Eigenschaft bei jedem Funktionsaufruf inkrementiert. Dieser Beispielcode wird nur im Standardmodus kompiliert, da im strikten Modus keine dynamischen Eigenschaften zu Funktionen hinzugefügt werden können. // Compiles only in standard mode var someFunction:Function = function ():void { someFunction.counter++; } someFunction.counter = 0; someFunction(); someFunction(); trace(someFunction.counter); // 2 Gültigkeitsbereich von FunktionenDer Gültigkeitsbereich einer Funktion legt nicht nur fest, an welcher Stelle im Programm diese Funktion aufgerufen werden kann, sondern auch, welche Definitionen auf die Funktion zugreifen können. Für Funktionsbezeichner gelten die gleichen Gültigkeitsbereichsregeln wie für Variablenbezeichner. Eine Funktion, die im globalen Gültigkeitsbereich deklariert ist, steht im gesamten Code zur Verfügung. Beispielsweise enthält ActionScript 3.0 globale Funktionen wie isNaN() und parseInt(), die sich an beliebigen Stellen im Code befinden können. Eine verschachtelte Funktion, d. h. eine Funktion, die innerhalb einer anderen Funktion deklariert ist, kann an beliebiger Stelle innerhalb der Funktion verwendet werden, in der sie deklariert wurde. GültigkeitsbereichsketteJedes Mal, wenn eine Funktion die Ausführung beginnt, wird eine Reihe von Objekten und Eigenschaften erstellt. Zunächst wird ein besonderes, als Aktivierungsobjekt bezeichnetes Objekt erstellt, das alle im Funktionsrumpf erstellten Parameter und lokalen Variablen oder Funktionen speichert. Ein direkter Zugriff auf das Aktivierungsobjekt ist nicht möglich, da es sich um einen internen Mechanismus handelt. Zweitens wird eine Gültigkeitsbereichskette erstellt, die eine sortierte Liste der Objekte enthält, die zur Laufzeit nach Bezeichnerdeklarationen durchsucht werden. Jede ausgeführte Funktion verfügt über eine Gültigkeitsbereichskette, die in einer internen Eigenschaft gespeichert ist. Bei einer verschachtelten Funktion beginnt die Gültigkeitsbereichskette mit ihrem eigenen Aktivierungsobjekt, gefolgt vom Aktivierungsobjekt der übergeordneten Funktion. Die Kette wird in dieser Weise fortgesetzt, bis sie das globale Objekt erreicht. Das globale Objekt wird erstellt, wenn ein ActionScript-Programm beginnt, und enthält alle globalen Variablen und Funktionen. FunktionshüllenEine Funktionshülle (Function Closure) ist ein Objekt, das eine Momentaufnahme einer Funktion und ihrer lexikalischen Umgebung enthält. Die lexikalische Umgebung einer Funktion enthält alle Variablen, Eigenschaften, Methoden und Objekte in der Gültigkeitsbereichskette einer Funktion sowie deren Werte. Funktionshüllen werden immer dann erstellt, wenn eine Funktion unabhängig von einem Objekt oder einer Klasse ausgeführt wird. Die Tatsache, dass Funktionshüllen den Gültigkeitsbereich beibehalten, in dem sie erstellt wurden, führt zu interessanten Ergebnissen, wenn eine Funktion als Argument oder Rückgabewert an einen anderen Gültigkeitsbereich übergeben wird. Im folgenden Beispielcode werden zwei Funktionen erstellt: foo(), die eine verschachtelte Funktion namens rectArea() zurückgibt, mit der die Fläche eines Rechtecks berechnet wird, und bar(), die foo() aufruft und die zurückgegebene Funktionshülle in einer Variablen namens myProduct speichert. Obwohl die Funktion bar() ihre eigene lokale Variable x (mit einem Wert von 2) definiert, behält Sie beim Aufruf der Funktionshülle myProduct() die Variable x (mit einem Wert von 40) bei, der in der Funktion foo() definiert ist. Die bar()-Funktion gibt daher den Wert 160 anstelle von 8 zurück. 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 verhalten sich insofern ähnlich, als dass sie ebenfalls Informationen über die lexikalische Umgebung beibehalten, in der sie erstellt wurden. Diese Eigenschaft macht sich insbesondere dann bemerkbar, wenn eine Methode aus ihrer Instanz extrahiert wird, wodurch eine gebundene Methode entsteht. Der wesentliche Unterschied zwischen einer Funktionshülle und einer gebundenen Methode besteht darin, dass sich der Wert des Schlüsselwortes this in einer gebundenen Methode immer auf die Instanz bezieht, an die sie ursprünglich angefügt wurde, während sich der Wert des Schlüsselwortes this in einer Funktionshülle ändern kann. |
|