Je viens de découvrir une situation intéressante en JavaScript. J'ai une classe avec une méthode qui définit plusieurs objets en utilisant la notation littérale objet. À l'intérieur de ces objets, le this
pointeur est utilisé. Du comportement du programme, j'ai déduit que le this
pointeur fait référence à la classe sur laquelle la méthode a été invoquée, et non à l'objet créé par le littéral.
Cela semble arbitraire, bien que ce soit la façon dont je m'attendrais à ce que cela fonctionne. Est-ce un comportement défini? Est-il sûr pour tous les navigateurs? Y a-t-il un raisonnement sous-jacent expliquant pourquoi cela se situe au-delà de "la spécification le dit" (par exemple, est-ce une conséquence d'une décision / philosophie de conception plus large)? Exemple de code simplifié:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};
Réponses:
Cannibalisé d'un autre poste à moi, voici plus que vous ne l'avez jamais voulu savoir à ce sujet .
Avant de commencer, voici la chose la plus importante à garder à l'esprit à propos de Javascript et à répéter lorsque cela n'a pas de sens. Javascript n'a pas de classes (ES6
class
est du sucre syntaxique ). Si quelque chose ressemble à une classe, c'est une astuce astucieuse. Javascript a des objets et des fonctions . (ce n'est pas précis à 100%, les fonctions ne sont que des objets, mais il peut parfois être utile de les considérer comme des choses distinctes)La variable this est attachée aux fonctions. Chaque fois que vous appelez une fonction, celle -ci reçoit une certaine valeur, selon la façon dont vous appelez la fonction. Ceci est souvent appelé le modèle d'invocation.
Il existe quatre façons d'invoquer des fonctions en javascript. Vous pouvez appeler la fonction en tant que méthode , en tant que fonction , en tant que constructeur et avec apply .
Comme méthode
Une méthode est une fonction attachée à un objet
Lorsqu'elle est invoquée en tant que méthode, elle sera liée à l'objet dont la fonction / méthode fait partie. Dans cet exemple, cela sera lié à foo.
En tant que fonction
Si vous avez une fonction autonome, la variable this sera liée à l'objet "global", presque toujours l' objet window dans le contexte d'un navigateur.
C'est peut-être ce qui vous fait trébucher , mais ne vous sentez pas mal. Beaucoup de gens considèrent cela comme une mauvaise décision de conception. Puisqu'un rappel est invoqué en tant que fonction et non en tant que méthode, c'est pourquoi vous voyez ce qui semble être un comportement incohérent.
Beaucoup de gens contournent le problème en faisant quelque chose comme, euh, ce
Vous définissez une variable qui qui pointe vers ce . La fermeture (un sujet qui lui est propre) conserve cela , donc si vous appelez la barre en tant que rappel, elle a toujours une référence.
REMARQUE: en
use strict
mode si utilisé comme fonction,this
n'est pas lié à global. (C'estundefined
).En tant que constructeur
Vous pouvez également appeler une fonction en tant que constructeur. Selon la convention de dénomination que vous utilisez (TestObject), cela peut également être ce que vous faites et c'est ce qui vous fait trébucher .
Vous appelez une fonction en tant que constructeur avec le nouveau mot clé.
Lorsqu'il est invoqué comme constructeur, un nouvel objet sera créé, et ce sera lié à cet objet. Encore une fois, si vous avez des fonctions internes et qu'elles sont utilisées comme rappels, vous les invoquerez en tant que fonctions, et cela sera lié à l'objet global. Utilisez ce var qui = cette astuce / modèle.
Certaines personnes pensent que le constructeur / nouveau mot-clé était un os jeté aux programmeurs Java / OOP traditionnels comme un moyen de créer quelque chose de similaire aux classes.
Avec la méthode Apply
Enfin, chaque fonction a une méthode (oui, les fonctions sont des objets en Javascript) nommée "appliquer". Appliquer vous permet de déterminer la valeur de cette valeur et vous permet également de passer un tableau d'arguments. Voici un exemple inutile.
la source
this
seraundefined
pour les invocations de fonctions.this
n'a rien à voir avec la portée. Vous voulez dire l' objet global .this.confusing = 'hell yeah';
le même quevar confusing = 'hell yeah';
? Alors les deux permettrontmyObject.confusing
? Ce serait bien si ce n'est pas seulement pour que vous puissiez utiliserthis
pour créer les propriétés et autres variables pour le travail interne.function Foo(thought){ this.confusing = thought; }
puisvar myObject = new Foo("hell yeah");
Appels de fonction
Les fonctions ne sont qu'un type d'objet.
Tous les objets Function ont des méthodes d' appel et d' application qui exécutent l'objet Function auquel ils sont appelés.
Lorsqu'il est appelé, le premier argument de ces méthodes spécifie l'objet qui sera référencé par le
this
mot clé lors de l'exécution de la fonction - si c'estnull
ouundefined
, l'objet globalwindow
, est utilisé pourthis
.Ainsi, appeler une fonction ...
... avec des parenthèses -
foo()
- est équivalent àfoo.call(undefined)
oufoo.apply(undefined)
, ce qui est en fait identique àfoo.call(window)
oufoo.apply(window)
.Des arguments supplémentaires à
call
sont passés comme arguments à l'appel de fonction, tandis qu'un seul argument supplémentaire àapply
peut spécifier les arguments de l'appel de fonction en tant qu'objet de type tableau.Ainsi,
foo(1, 2, 3)
est équivalent àfoo.call(null, 1, 2, 3)
oufoo.apply(null, [1, 2, 3])
.Si une fonction est une propriété d'un objet ...
... accéder à une référence à la Fonction via l'objet et l'appeler entre parenthèses -
obj.foo()
- est équivalent àfoo.call(obj)
oufoo.apply(obj)
.Cependant, les fonctions détenues comme propriétés d'objets ne sont pas "liées" à ces objets. Comme vous pouvez le voir dans la définition
obj
ci-dessus, puisque les fonctions ne sont qu'un type d'objet, elles peuvent être référencées (et peuvent donc être passées par référence à un appel de fonction ou renvoyées par référence à partir d'un appel de fonction). Lorsqu'une référence à une fonction est passée, aucune autre information sur l' endroit où il a été passé de se fait avec elle, ce qui explique pourquoi les éléments suivants se produit:L'appel à notre référence Function
baz
, ne fournit aucun contexte pour l'appel, il est donc en fait le même quebaz.call(undefined)
, doncthis
finit par faire référencewindow
. Si nous voulonsbaz
savoir à quoi il appartientobj
, nous devons d'une manière ou d'une autre fournir ces informations lors de l'baz
appel, c'est là que le premier argument decall
ouapply
et les fermetures entrent en jeu.Chaînes de portée
Lorsqu'une fonction est exécutée, elle crée une nouvelle étendue et a une référence à toute étendue englobante. Lorsque la fonction anonyme est créée dans l'exemple ci-dessus, elle fait référence à l'étendue dans laquelle elle a été créée, qui est
bind
l'étendue de. C'est ce qu'on appelle une «fermeture».Lorsque vous essayez d'accéder à une variable, cette "chaîne de portée" est parcourue pour trouver une variable avec le nom donné - si la portée actuelle ne contient pas la variable, vous regardez la portée suivante de la chaîne, et ainsi de suite jusqu'à ce que vous atteigniez la portée mondiale. Lorsque la fonction anonyme est renvoyée et
bind
termine son exécution, la fonction anonyme a toujours une référence àbind
la portée de ', doncbind
la portée de' ne disparaît pas '.Compte tenu de tout ce qui précède, vous devriez maintenant être en mesure de comprendre comment fonctionne la portée dans l'exemple suivant, et pourquoi la technique pour passer une fonction autour de "pré-lié" avec une valeur particulière
this
aura quand elle sera appelée fonctionne:la source
Oui. Et oui.
Le sens de
this
est assez simple à déduire:this
est utilisé dans une fonction constructeur et que la fonction a été invoquée avec lenew
mot clé,this
fait référence à l'objet qui sera créé.this
continuera à signifier l'objet même dans les méthodes publiques.this
est utilisé ailleurs, y compris les fonctions protégées imbriquées , il se réfère à la portée globale (qui dans le cas du navigateur est l'objet fenêtre).Le deuxième cas est évidemment un défaut de conception, mais il est assez facile de le contourner en utilisant des fermetures.
la source
Dans ce cas, l'intérieur
this
est lié à l'objet global au lieu de lathis
variable de la fonction extérieure. C'est la façon dont la langue est conçue.Voir «JavaScript: The Good Parts» de Douglas Crockford pour une bonne explication.
la source
J'ai trouvé un joli tutoriel sur l' ECMAScript ce
Tout objet peut être utilisé comme cette valeur du contexte.
Cette fonctionnalité est très importante, car contrairement aux variables, cette valeur ne participe jamais au processus de résolution des identifiants. C'est-à-dire lorsque vous accédez à cela dans un code, sa valeur est prise directement du contexte d'exécution et sans aucune recherche de chaîne de portée. La valeur de ceci n'est déterminée qu'une seule fois lors de la saisie du contexte.
Dans le contexte global, cette valeur est l'objet global lui-même (cela signifie que cette valeur est ici égale à l'objet variable)
Dans le cas d'un contexte de fonction, cette valeur dans chaque appel de fonction peut être différente
Référence Javascript-the-core et Chapter-3-this
la source