Fonctions

Les fonctions sont des blocs de code qui effectuent des tâches spécifiques et qui peuvent être réutilisés dans votre programme. Il existe deux types de fonctions dans ActionScript 3.0 : les méthodes et les fonctions closure. Une fonction est appelée méthode ou fonction closure selon le contexte dans lequel elle est définie. Une fonction est appelée méthode si vous la définissez comme partie d’une définition de classe ou l’associez à l’occurrence d’un objet. Une fonction est appelée fonction closure si elle est définie de toute autre façon.

Les fonctions ont toujours été très importantes dans ActionScript. Dans ActionScript 1.0, par exemple, le mot-clé class n’existait pas. Par conséquent, les classes étaient définies par des fonctions constructeurs. Même si le mot-clé class a depuis été ajouté au langage, une solide compréhension des fonctions reste importante si vous souhaitez bénéficier de tous les avantages du langage. Ceci peut être un défi pour les programmeurs qui s’attendent à ce que les fonctions ActionScript se comportent de façon identique à celles des langages tels que C++ ou Java. Même si l’appel et la définition des fonctions de base ne devraient pas constituer un défi pour les programmeurs expérimentés, certaines des fonctions ActionScript les plus avancées nécessitent une explication.

Concepts des fonctions de base

Appel de fonctions

Vous appelez une fonction en utilisant son identifiant suivi de l’opérateur parenthèses (()). Vous placez les paramètres de fonction que vous souhaitez envoyer à la fonction entre parenthèses à l’aide de l’opérateur parenthèses. Par exemple, la fonction trace() est une fonction de haut niveau dans ActionScript 3.0 :

trace("Use trace to help debug your script");

Si vous appelez une fonction sans paramètres, vous devez utiliser une paire de parenthèses vide. Par exemple, vous pouvez utiliser la méthode Math.random(), qui ne prend aucun paramètre, pour générer un nombre aléatoire :

var randomNum:Number = Math.random();

Définition de vos fonctions

Dans ActionScript 3.0, deux techniques vous permettent de définir une fonction : vous pouvez utiliser une instruction de fonction ou une expression de fonction. La technique que vous choisissez dépend du style de programmation que vous préférez, plus statique ou dynamique. Définissez vos fonctions à l’aide d’instructions de fonction si vous préférez une programmation en mode strict, ou statique. Définissez vos fonctions à l’aide d’expressions de fonction si vous en avez vraiment besoin. Les expressions de fonction sont utilisées plus souvent dans la programmation en mode standard, ou dynamique.

Instructions de fonction

Les instructions de fonction représentent la technique privilégiée pour définir des fonctions en mode strict. Une instruction de fonction commence par le mot-clé function, suivi :

  • du nom de la fonction ;

  • des paramètres, dans une liste séparée par des virgules, placée entre parenthèses ;

  • du corps de la fonction, c’est-à-dire le code ActionScript à exécuter lors de l’appel de la fonction, placé entre accolades.

Par exemple, le code suivant crée une fonction qui définit un paramètre puis appelle la fonction à l’aide de la chaîne « hello » comme valeur de paramètre :

function traceParameter(aParam:String) 
{ 
    trace(aParam); 
} 
 
traceParameter("hello"); // hello

Expressions de fonction

La deuxième façon de déclarer une fonction est d’utiliser une instruction d’affectation avec une expression de fonction, parfois appelée littéral de fonction ou fonction anonyme. Il s’agit d’une méthode plus détaillée largement utilisée dans les versions précédentes d’ActionScript.

Une instruction d’affectation associée à une expression de fonction commence par le mot-clé var, suivi :

  • du nom de la fonction ;

  • de l’opérateur deux points (.) ;

  • de la classe Function pour indiquer le type de données ;

  • de l’opérateur d’affectation (=) ;

  • du mot-clé function ;

  • des paramètres, dans une liste séparée par des virgules, placée entre parenthèses ;

  • du corps de la fonction, c’est-à-dire le code ActionScript à exécuter lors de l’appel de la fonction, placé entre accolades.

    Par exemple, le code suivant déclare la fonction traceParameter à l’aide d’une expression de fonction :

    var traceParameter:Function = function (aParam:String) 
    { 
        trace(aParam); 
    }; 
    traceParameter("hello"); // hello

    Vous remarquerez que vous ne spécifiez pas de nom de fonction, comme dans une instruction de fonction. Une autre différence importante entre les expressions de fonction et les instructions de fonction est qu’une expression de fonction est plus une expression qu’une instruction. Ceci signifie qu’une expression de fonction ne peut pas être utilisée seule, contrairement à une instruction de fonction. Une expression de fonction peut être utilisée uniquement en tant que partie d’une instruction, généralement une instruction d’affectation. L’exemple suivant représente une expression de fonction affectée à un élément de tableau :

    var traceArray:Array = new Array(); 
    traceArray[0] = function (aParam:String) 
    { 
        trace(aParam); 
    }; 
    traceArray[0]("hello");

Choix d’instructions ou d’expressions

En règle générale, utilisez une instruction de fonction, à moins que des circonstances spécifiques n’exigent l’utilisation d’une expression. Les instructions de fonction sont moins détaillées et renforcent plus la cohérence entre le mode strict et le mode standard que les expressions de fonction.

Les instructions de fonction sont plus lisibles que les instructions d’affectation qui contiennent des expressions de fonction. Les instructions de fonction rendent votre code plus concis ; elles prêtent moins à confusion que les expressions de fonction, qui exigent l’utilisation des mots-clés var et function.

Les instructions de fonction renforcent la cohérence entre les deux modes de compilateur car vous pouvez utiliser la syntaxe à point en mode strict et en mode standard pour appeler une méthode déclarée à l’aide d’une instruction de fonction. Ceci ne s’applique pas nécessairement aux méthodes déclarées avec une expression de fonction. Par exemple, le code suivant définit la classe Example à l’aide de deux méthodes : methodExpression(), qui est déclarée par le biais d’une expression de fonction, et methodStatement(), qui est déclarée par le biais d’une instruction de fonction. En mode strict, vous ne pouvez pas utiliser la syntaxe à point pour appeler la méthode 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

Les expressions de fonction sont plus adaptées à la programmation ciblée sur un comportement d’exécution ou dynamique. Si vous préférez utiliser le mode strict mais que vous souhaitez également appeler une méthode déclarée avec une expression de fonction, vous pouvez utiliser l’une des deux techniques. Premièrement, vous pouvez appeler la méthode à l’aide de l’opérateur crochets ([]) au lieu de l’opérateur point (.). L’appel de méthode suivant a lieu à la fois en mode strict et en mode standard :

myExample["methodLiteral"]();

Deuxièmement, vous pouvez déclarer la classe entière comme classe dynamique. Même si ceci vous permet d’appeler la méthode à l’aide de l’opérateur point, l’inconvénient est que vous sacrifiez une fonctionnalité de mode strict pour toutes les occurrences de cette classe. Par exemple, le compilateur ne génère pas d’erreur si vous tentez d’accéder à une propriété non définie sur une occurrence d’une classe dynamique.

Les expressions de fonction peuvent être utiles dans certains cas. Elles sont couramment utilisées pour des fonctions qui sont utilisées une seule fois. Elles peuvent être utilisées également pour associer une fonction à une propriété de prototype. Pour plus d’informations, voir Objet prototype.

Il existe deux légères différences entre les instructions de fonction et les expressions de fonction dont il faut tenir compte lorsque vous choisissez la technique à utiliser. La première réside dans le fait que les expressions de fonction n’existent pas indépendamment en tant qu’objets en ce qui concerne la gestion de la mémoire et le nettoyage. En d’autres termes, lorsque vous affectez une expression de fonction à un autre objet (un élément de tableau ou une propriété d’objet, par exemple) vous créez l’unique référence à cette expression de fonction dans votre code. Si le tableau ou l’objet auquel est associée l’expression de fonction n’est plus disponible, vous n’avez plus accès à l’expression de fonction. Si le tableau ou l’objet est supprimé, la mémoire que l’expression de fonction utilise peut être nettoyée, ce qui signifie qu’elle peut être réutilisée à d’autres fins.

L’exemple suivant indique que pour une expression de fonction, la fonction n’est plus disponible une fois que la propriété à laquelle l’expression est affectée est supprimée. La classe Test est dynamique, ce qui signifie que vous pouvez ajouter une propriété appelée functionExp qui contient une expression de fonction. La fonction functionExp() peut être appelée avec l’opérateur point, mais une fois que la propriété functionExp est supprimée, la fonction n’est plus accessible.

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

Si, en revanche, la fonction est d’abord définie avec une instruction de fonction, elle existe comme son propre objet et continue à exister, même une fois que vous avez supprimé la propriété à laquelle elle est associée. L’opérateur delete fonctionne uniquement sur les propriétés d’objets, donc même un appel à supprimer la fonction stateFunc() ne fonctionne pas.

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

La deuxième différence entre les instructions de fonction et les expressions de fonction réside dans le fait que les instructions de fonction existent dans le cadre dans lequel elles sont définies, notamment les instructions qui apparaissent avant l’instruction de fonction. Les expressions de fonction, en revanche, sont définies uniquement pour les instructions ultérieures. Par exemple, le code suivant appelle la fonction scopeTest() avant qu’elle soit définie :

statementTest(); // statementTest 
 
function statementTest():void 
{ 
    trace("statementTest"); 
}

Les expressions de fonction ne sont pas disponibles avant d’être définies. Par conséquent, le code suivant provoque une erreur d’exécution :

expressionTest(); // run-time error 
 
var expressionTest:Function = function () 
{ 
    trace("expressionTest"); 
}

Renvoi de valeurs des fonctions

Pour renvoyer une valeur de votre fonction, utilisez l’instruction return suivie de l’expression ou de la valeur littérale que vous souhaitez renvoyer. Par exemple, le code suivant renvoie une expression représentant le paramètre :

function doubleNum(baseNum:int):int 
{ 
    return (baseNum * 2); 
}

Vous remarquerez que l’instruction return termine la fonction, de sorte que les instructions suivant une instruction return ne sont pas exécutées, comme suit :

function doubleNum(baseNum:int):int { 
    return (baseNum * 2); 
    trace("after return"); // This trace statement will not be executed. 
}

En mode strict, vous devez renvoyer une valeur du type approprié si vous choisissez de spécifier un type de renvoi. Par exemple, le code suivant génère une erreur en mode strict car il ne renvoie pas de valeur valide :

function doubleNum(baseNum:int):int 
{ 
    trace("after return"); 
}

Fonctions imbriquées

Vous pouvez imbriquer des fonctions, ce qui signifie que vous pouvez déclarer des fonctions au sein d’autres fonctions. Une fonction imbriquée est disponible uniquement dans sa fonction parent, à moins qu’une référence à la fonction ne soit transmise à un code externe. Par exemple, le code suivant déclare deux fonctions imbriquées à l’intérieur de la fonction getNameAndVersion() :

function getNameAndVersion():String 
{ 
    function getVersion():String 
    { 
        return "10"; 
    } 
    function getProductName():String 
    { 
        return "Flash Player"; 
    } 
    return (getProductName() + " " + getVersion()); 
} 
trace(getNameAndVersion()); // Flash Player 10

Lorsque des fonctions imbriquées sont transmises à un code externe, elles le sont en tant que fonctions closure, ce qui signifie que la fonction conserve les définitions se trouvant dans le domaine au moment de la définition de la fonction. Pour plus d’informations, voir Domaine d’une fonction.

Paramètres de fonction

ActionScript 3.0 permet d’exploiter des paramètres de fonction qui peuvent sembler nouveaux pour les programmeurs qui découvrent le langage. Bien que la plupart des programmeurs connaissent le principe de transfert de paramètres par valeur ou référence, l’objet arguments et le paramètre ... (rest) seront peut-être des nouveautés.

Transfert d’arguments par valeur ou par référence

Dans de nombreux langages de programmation, il est important de comprendre la différence entre le transfert d’arguments par valeur ou par référence car elle peut affecter la façon dont le code est conçu.

Transférer par valeur signifie que la valeur de l’argument est copiée dans une variable locale pour être utilisée dans la fonction. Transférer par référence signifie que seule une référence à l’argument est transmise, au lieu de la valeur réelle. Aucune copie de l’argument réel n’est effectuée. A la place, une référence à la variable transférée en tant qu’argument est créée et affectée à une variable locale pour être utilisée dans la fonction. En tant que référence à une variable en dehors de la fonction, la variable locale vous permet de modifier la valeur de la variable d’origine.

Dans ActionScript 3.0, tous les arguments sont transférés par référence car toutes les valeurs sont stockées en tant qu’objets. Néanmoins, les objets qui appartiennent aux types de données primitifs (Boolean, Number, int, uint et String) possèdent des opérateurs spéciaux qui font qu’ils se comportent comme s’ils étaient transférés par valeur. Par exemple, le code suivant crée une fonction appelée passPrimitives() qui définit deux paramètres appelés xParam et yParam de type int. Ces paramètres sont identiques aux variables locales déclarées dans le corps de la fonction passPrimitives(). Lorsque la fonction est appelée avec les arguments xValue et yValue, les paramètres xParam et yParam sont initialisés avec des références aux objets int représentés par xValue et yValue. Les arguments se comportent comme s’ils étaient transférés par valeur car ils sont primitifs. Bien que xParam et yParam contiennent initialement des références aux objets xValue et yValue uniquement, toute modification apportée aux variables dans le corps de fonction génère de nouvelles copies des valeurs dans la mémoire.

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

Dans la fonction passPrimitives(), les valeurs de xParam et yParam sont incrémentées, mais ceci n’affecte pas les valeurs de xValue et yValue, comme indiqué dans la dernière instruction trace. Ceci s’applique même si les paramètres portent les mêmes noms que les variables, xValue et yValue, car les xValue et yValue se trouvant dans la fonction pointeraient vers de nouveaux emplacements dans la mémoire qui existent indépendamment des variables du même nom en dehors de la fonction.

Tous les autres objets (c’est-à-dire les objets qui n’appartiennent pas aux types de données primitifs) sont toujours transférés par référence, ce qui vous permet de modifier la valeur de la variable d’origine. Par exemple, le code suivant crée un objet appelé objVar avec deux propriétés, x et y. L’objet est transféré en tant qu’argument à la fonction passByRef(). Etant donné que l’objet n’est pas un type primitif, non seulement il est transféré par référence mais il reste également une référence. Les changements apportés aux paramètres dans la fonction affectent donc les propriétés d’objet en dehors de la fonction.

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

Le paramètre objParam référence le même objet que la variable globale objVar. Comme vous pouvez le constater dans les instructions trace de l’exemple, les modifications apportées aux propriétés x et y de l’objet objParam sont visibles dans l’objet objVar.

Valeurs de paramètre par défaut

Dans ActionScript 3.0, vous pouvez déclarer des valeurs de paramètre par défaut pour une fonction. Si un appel à une fonction avec des valeurs de paramètre par défaut omet un paramètre avec des valeurs par défaut, la valeur spécifiée dans la définition de fonction pour ce paramètre est utilisée. Tous les paramètres avec des valeurs par défaut doivent être placés à la fin de la liste des paramètres. Les valeurs affectées comme valeurs par défaut doivent être des constantes de compilation. L’existence d’une valeur par défaut pour un paramètre le rend facultatif. Un paramètre sans valeur par défaut est considéré comme un paramètre obligatoire.

Par exemple, le code suivant crée une fonction avec trois paramètres, dont deux possèdent des valeurs par défaut. Lorsque la fonction est appelée avec un seul paramètre, les valeurs par défaut des paramètres sont utilisées.

function defaultValues(x:int, y:int = 3, z:int = 5):void 
{ 
    trace(x, y, z); 
} 
defaultValues(1); // 1 3 5

Objet arguments

Lorsque les paramètres sont transférés à une fonction, vous pouvez utiliser l’objet arguments pour accéder aux informations concernant les paramètres transférés à votre fonction. Voici certains aspects importants de l’objet arguments :

  • L’objet arguments est un tableau qui comprend tous les paramètres transférés à la fonction.

  • La propriété arguments.length indique le nombre de paramètres transmis à la fonction.

  • La propriété arguments.callee fournit une référence à la fonction elle-même, ce qui est utile pour les appels récursifs à des expressions de fonction.

    Remarque : l’objet arguments n’est pas disponible si un paramètre est appelé arguments ou si vous utilisez le paramètre ... (rest).

    Si l’objet arguments est référencé dans le corps d’une fonction, ActionScript 3.0 permet aux appels de fonction d’inclure plus de paramètres que ceux définis dans la définition de fonction. Mais il génère une erreur de compilateur en mode strict si le nombre de paramètres ne correspond pas au nombre de paramètres obligatoires (et, éventuellement, au nombre de paramètres facultatifs). Vous pouvez utiliser l’aspect de tableau de l’objet arguments pour accéder aux paramètres transférés à la fonction, que ces paramètres soient définis ou non dans la définition de fonction. L’exemple suivant, qui est uniquement compilé en mode standard, utilise le tableau arguments et la propriété arguments.length pour suivre tous les paramètres transférés à la fonction 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

    La propriété arguments.callee est souvent utilisée dans des fonctions anonymes pour créer une récursivité. Vous pouvez l’utiliser pour ajouter de la flexibilité à votre code. Si le nom de la fonction récursive change pendant votre cycle de développement, il est inutile de modifier l’appel récursif dans le corps de votre fonction si vous utilisez arguments.callee au lieu du nom de fonction. La propriété arguments.callee est utilisée dans l’expression de fonction suivante pour activer la récursivité :

    var factorial:Function = function (x:uint) 
    { 
        if(x == 0) 
        { 
            return 1; 
        } 
        else 
        { 
            return (x * arguments.callee(x - 1)); 
        } 
    } 
     
    trace(factorial(5)); // 120

    Si vous utilisez le paramètre ... (rest) dans la déclaration de fonction, l’objet arguments n’est pas disponible. Vous devez accéder aux paramètres à l’aide des noms de paramètre que vous avez déclarés.

    N’utilisez pas la chaîne "arguments" comme nom de paramètre car elle masque l’objet arguments. Par exemple, si la fonction traceArgArray() est réécrite de façon à ce qu’un paramètre arguments soit ajouté, les références à arguments dans le corps de la fonction se réfèrent au paramètre plutôt qu’à l’objet arguments. Le code suivant donne le résultat :

    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

    L’objet arguments des versions précédentes d’ActionScript contenait également une propriété appelée caller, qui est une référence à la fonction qui appelait la fonction actuelle. La propriété caller n’existe pas dans ActionScript 3.0, mais si vous avez besoin d’une référence à la fonction d’appel, vous pouvez modifier celle-ci de façon à ce qu’elle transfère un paramètre supplémentaire qui en soit une référence.

Paramètre ... (rest)

ActionScript 3.0 présente une nouvelle déclaration de paramètre appelée le paramètre .. (rest). Ce paramètre vous permet de spécifier un paramètre de tableau qui accepte n’importe quel nombre d’arguments séparés par des virgules. Veillez à ne pas inclure un mot réservé dans le nom du paramètre. Cette déclaration de paramètre doit être le dernier paramètre spécifié. Ce paramètre rend l’objet arguments non disponible. Bien que le paramètre ... (rest) offre la même fonctionnalité que le tableau arguments et la propriété arguments.length, il ne fournit pas la même fonctionnalité que la propriété arguments.callee. Vérifiez que vous n’avez pas besoin d’utiliser arguments.callee avant d’utiliser le paramètre ... (rest).

L’exemple suivant réécrit la fonction traceArgArray() à l’aide du paramètre ... (rest) plutôt que de l’objet 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

Le paramètre ... (rest) peut également être utilisé avec d’autres paramètres, sous réserve qu’il soit le dernier de la liste. L’exemple suivant modifie la fonction traceArgArray() de façon à ce que son premier paramètre, x, soit de type int, et que le second utilise le paramètre ... (rest). Le résultat ignore la première valeur car le premier paramètre ne fait plus partie du tableau créé par le paramètre ... (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

Fonctions comme objets

Dans ActionScript 3.0, les fonctions sont des objets. Lorsque vous créez une fonction, vous créez un objet qui peut non seulement être transmis en tant que paramètre à une autre fonction, mais auquel sont également associées des propriétés et des méthodes.

Les fonctions transférées en tant qu’arguments à une autre fonction sont transmises par référence et non par valeur. Lorsque vous transférez une fonction en tant qu’argument, vous utilisez uniquement l’identifiant et non l’opérateur parenthèses qui permet d’appeler la méthode. Par exemple, le code suivant transfère une fonction appelée clickListener() en tant qu’argument à la méthode addEventListener() :

addEventListener(MouseEvent.CLICK, clickListener);

Même si cela peut sembler étrange pour les programmeurs découvrant ActionScript, les fonctions peuvent avoir des propriétés et des méthodes, comme les objets. Chaque fonction a en réalité une propriété en lecture seule appelée length qui stocke le nombre de paramètres définis pour la fonction. Ceci est différent de la propriété arguments.length qui indique le nombre d’arguments envoyés à la fonction. Dans ActionScript, le nombre d’arguments envoyés à une fonction peut dépasser le nombre de paramètres définis pour cette dernière. L’exemple suivant (qui compile uniquement en mode standard car le mode strict exige une correspondance exacte entre le nombre d’arguments transférés et le nombre de paramètres définis) illustre la différence entre les deux propriétés :

// 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 */

En mode standard, vous pouvez définir vos propriétés en dehors du corps de la fonction. Les propriétés de fonction peuvent servir de propriétés quasi statiques vous permettant de sauvegarder l’état d’une variable liée à la fonction. Par exemple, vous pouvez suivre le nombre d’appels d’une fonction particulière. Une telle fonctionnalité peut être utile si vous écrivez un jeu et souhaitez suivre le nombre de fois qu’un utilisateur se sert d’une certaine commande (vous pouvez également utiliser une propriété de classe statique). L’exemple suivant (qui compile uniquement en mode standard car le mode strict n’autorise pas l’ajout de propriétés dynamiques aux fonctions) crée une propriété de fonction en dehors de la déclaration de la fonction et incrémente cette propriété à chaque appel de la fonction :

// Compiles only in standard mode 
var someFunction:Function = function ():void 
{ 
    someFunction.counter++; 
} 
 
someFunction.counter = 0; 
 
someFunction(); 
someFunction(); 
trace(someFunction.counter); // 2

Domaine d’une fonction

Le domaine d’une fonction détermine non seulement l’endroit où cette fonction peut être appelée dans un programme, mais également les définitions auxquelles la fonction peut accéder. Les mêmes règles de domaine qui s’appliquent aux identifiants de variable s’appliquent aux identifiants de fonction. Une fonction déclarée dans le domaine global est disponible dans tout votre code. Par exemple, ActionScript 3.0 contient des fonctions globales (isNaN() et parseInt(), par exemple) disponibles n’importe où dans votre code. Une fonction imbriquée (une fonction déclarée dans une autre fonction) peut être utilisée n’importe où dans la fonction dans laquelle elle a été déclarée.

Chaîne de domaine

Chaque fois qu’une fonction commence une exécution, des objets et des propriétés sont créés. Premièrement, un objet spécial appelé objet d’activation est créé. Il stocke les paramètres et les variables locales ou fonctions déclarées dans le corps de la fonction. Vous ne pouvez pas accéder directement à l’objet d’activation car il s’agit d’un mécanisme interne. Deuxièmement, une chaîne de domaine est créée. Elle contient une liste ordonnée d’objets dans laquelle le moteur d’exécution recherche des déclarations d’identifiant. Chaque fonction qui s’exécute a une chaîne de domaine stockée dans une propriété interne. Dans le cas d’une fonction imbriquée, la chaîne de domaine commence avec son objet d’activation, suivi par l’objet d’activation de sa fonction parent. La chaîne continue de cette façon jusqu’à ce que l’objet global soit atteint. L’objet global est créé lorsqu’un programme ActionScript commence, et contient toutes les fonctions et les variables globales.

Fonctions closure

Une fonction closure est un objet qui contient un instantané d’une fonction et de son environnement lexical. L’environnement lexical d’une fonction comprend toutes les variables, propriétés, méthodes et les objets dans la chaîne de domaine de la fonction, ainsi que leurs valeurs. Les fonctions closure sont créées chaque fois qu’une fonction est exécutée à part d’un objet ou d’une classe. Le fait que les fonctions closure conservent le domaine dans lequel elles ont été définies crée des résultats intéressants lorsqu’une fonction est transférée en tant qu’argument ou valeur de renvoi dans un domaine différent.

Par exemple, le code suivant crée deux fonctions : foo(), qui renvoie une fonction imbriquée appelée rectArea() qui calcule la surface d’un rectangle, et bar(), qui appelle foo() et stocke la fonction closure renvoyée dans une variable appelée myProduct. Même si la fonction bar() définit sa propre variable locale x (avec une valeur de 2), lorsque la fonction closure myProduct() est appelée, elle conserve la variable x (avec une valeur de 40) définie dans la fonction foo(). La fonction bar() renvoie par conséquent la valeur 160 au lieu de 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

Les méthodes se comportent de la même façon car elles conservent également les informations concernant l’environnement lexical dans lequel elles ont été créées. Cette caractéristique se remarque plus particulièrement lorsqu’une méthode est extraite de son occurrence, ce qui crée une méthode liée. La différence principale entre une fonction closure et une méthode liée est que la valeur du mot-clé this dans une méthode liée se réfère toujours à l’occurrence à laquelle elle était associée à l’origine, alors que dans une fonction closure, la valeur du mot-clé this peut changer.