conseil
Tout d'abord, je sais que cet article est ennuyeux, ce n'est rien de plus que cela dans JS, et il y a eu des milliers d'articles écrivant cette partie;
Cependant, je veux toujours écrire un article à ce sujet dans JS, qui peut être considéré comme un résumé; (Les dieux peuvent faire le tour et lire mes autres articles)
Dans JS, le contexte de cela est toujours imprévisible et souvent les bugs sont toujours confus. En fait, tant que vous distinguez clairement la façon de s'exécuter dans différentes circonstances, ce sera OK.
Exécution mondiale
Tout d'abord, jetons un coup d'œil à ce que c'est dans l'environnement mondial:
d'abord. Navigateur:
Console.log (this); // Window {SpeechSynthesis: SpeechSynthesis, Caches: CacheStorage, Localstorage: Storage, SessionStorage: Storage, WebKitStorageInfo: DemongatedStorageInfo…}Vous pouvez voir que l'objet Window est imprimé;
deuxième. nœud:
console.log (this); // global
Vous pouvez voir que l'objet global est imprimé;
Résumé: Dans la portée globale, elle exécute l'objet global actuel (fenêtre sur le navigateur, global dans le nœud).
Exécuter dans la fonction
Appels de fonction purs
C'est le moyen le plus courant d'utiliser la fonction:
Function test () {console.log (this);}; test (); // fenêtre {SpeechSynthesis: SpeechSynthesis, Caches: CacheStorage, Localstorage: Storage, SessionStorage: Storage, WebKitStorageInfo: DepreatedStorageInfo…}Nous pouvons voir que lorsqu'une fonction est appelée directement, elle appartient à un appel global, et à l'heure actuelle, cela pointe vers l'objet global;
Mode strict «Utiliser Strict»;
Si les appels de fonction purs sont exécutés en mode strict, cela ne pointe pas ici, mais n'est pas défini. Il s'agit d'éliminer un comportement désactivé dans JS:
'use strict'; fonction test () {console.log (this);}; test (); // undefinedBien sûr, le mettre dans une fonction d'exécution immédiate serait mieux, éviter de polluer la situation mondiale:
(function () {"utiliser strict"; console.log (this);}) (); // undefinedL'appel de la méthode comme objet
Lorsqu'une fonction est appelée la méthode d'un objet:
var obj = {name: 'qiUtc', foo: function () {console.log (this.name); }} obj.foo (); // 'qiutc'À l'heure actuelle, cela pointe vers l'objet actuel;
Bien sûr, nous pouvons le faire:
fonction test () {console.log (this.name);} var obj = {name: 'qiutc', foo: test} obj.foo (); // 'qiUtc'Également inchangé, car en js, tout est un objet, et une fonction est également un objet. Pour le test, ce n'est qu'un nom de fonction, une référence à la fonction, qui pointe vers cette fonction. Lorsque FOO = TEST, FOO pointe également vers cette fonction.
Et si vous attribuez la méthode de l'objet à une variable, puis appelez directement cette variable:
var obj = {name: 'qiUtc', foo: function () {console.log (this); }} var test = obj.foo; test (); // fenêtreOn peut voir que cela exécute le monde mondial pour le moment. Lorsque nous plaçons Test = obj.foo, le test pointe directement vers une référence à une fonction. Pour le moment, cela n'a en fait rien à voir avec l'objet OBJ, il est donc appelé directement comme une fonction ordinaire, ce qui indique l'objet global.
Quelques pièges
Nous rencontrons souvent des pièges dans les fonctions de rappel:
var obj = {name: 'qiUtc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (this.foo, 1000); }} obj.foo2 ();Après avoir exécuté ce code, nous constaterons que les impressions sont différentes les unes des autres:
La première fois, c'est l'imprimer directement dans FOO2, pointant l'objet OBJ ici, nous n'avons aucun doute;
Cependant, ce.foo exécuté dans Settimeout pointe vers l'objet global. N'est-il pas utilisé comme méthode de fonction ici? Cela repousse souvent de nombreux débutants;
En fait, SetTimeout n'est qu'une fonction et la fonction peut nécessiter des paramètres. Nous passons ceci.foo en tant que paramètre à la fonction Settimeout, tout comme cela nécessite un paramètre amusant. Lors du passage du paramètre, nous avons en fait fait une telle opération Fun = this.foo. Voyant qu'il n'y a pas, nous soulignons directement la référence de ce.foo; Lors de l'exécution, Fun () est réellement exécuté, cela n'a donc rien à voir avec OBJ. Il est appelé directement comme une fonction ordinaire, ce qui pointe vers l'objet global.
Ce problème est couramment rencontré dans de nombreuses fonctions de rappel asynchrones;
résoudre
Pour résoudre ce problème, nous pouvons utiliser la fonction de fermeture pour y faire face:
var obj = {name: 'qiUtc', foo: function () {console.log (this); }, foo2: function () {console.log (this); var _this = this; setTimeout (function () {console.log (this); // fenêtre console.log (_This); // objet {name: "qiUtc"}}, 1000); }} obj.foo2 ();Vous pouvez voir que l'utilisation directement est toujours de la fenêtre; Parce que cela dans FOO2 pointe vers OBJ, nous pouvons d'abord utiliser une variable _Ce pour la stocker, puis utiliser _Ce dans la fonction de rappel pour pointer vers l'objet actuel;
Une autre fosse de settimeout
Comme mentionné précédemment, si la fonction de rappel est exécutée directement sans portée de liaison, alors c'est ce point vers l'objet global (fenêtre), qui pointera à un non-défini en mode strict. Cependant, la fonction de rappel dans Settimeout montre différentes en mode strict:
'use strict'; fonction foo () {console.log (this);} setTimeout (foo, 1); // fenêtreLogiquement parlant, nous avons ajouté un mode strict, et l'appel FOO ne l'a pas spécifié, il devrait donc être indéfini, mais il y a toujours un objet global ici. Est-ce parce que le mode strict a échoué?
Non, même en mode strict, lorsque la méthode Settimeout appelle la fonction entrante, si la fonction ne le spécifie pas, elle fera une opération implicite - injectera automatiquement le contexte global, ce qui équivaut à appeler foo.apply (fenêtre) au lieu de foo ();
Bien sûr, si nous le spécifions déjà lors du passage de la fonction, nous ne serons pas injectés dans l'objet global, tel que: setTimeout (foo.bind (obj), 1) ;;
Utiliser comme constructeur
Dans JS, afin d'implémenter la classe, nous devons définir certains constructeurs, et le mot-clé nouveau est nécessaire pour être ajouté lors de l'appel d'un constructeur:
fonction personne (name) {this.name = name; console.log (this);} var p = new personne ('qiUtc'); // personne {nom: "qiUtc"}Nous pouvons voir que lorsqu'elle est appelée comme constructeur, cela pointe vers l'objet instancié lorsque ce constructeur est appelé;
Bien sûr, le constructeur est en fait une fonction. Si nous l'exécutons en fonction normale, cela s'exécutera toujours à l'échelle mondiale:
fonction personne (name) {this.name = name; console.log (this);} var p = personne ('qiutc'); // fenêtreLa différence est de savoir comment appeler la fonction (nouveau).
Fonction de flèche
Dans la nouvelle spécification ES6, une fonction flèche a été ajoutée. La chose la plus différente des fonctions ordinaires est ce pointage. Vous souvenez-vous que nous utilisons des fermetures pour résoudre ce problème de pointage? Si nous utilisons la fonction Arrow, nous pouvons le résoudre plus parfaitement:
var obj = {name: 'qiUtc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (() => {console.log (this); // objet {name: "qiUtc"}}, 1000); }} obj.foo2 ();Comme vous pouvez le voir, dans la fonction exécutée par Settimeout, il aurait dû être imprimé sur la fenêtre, mais cela pointe vers OBJ ici. La raison en est que la fonction (paramètre) transmise à Settimeout est une fonction flèche:
Cet objet dans le corps de fonction est l'objet défini, pas l'objet utilisé.
Sur la base d'exemples, comprenons cette phrase:
Lorsque obj.foo2 () est exécuté, le courant cela pointe vers OBJ; Lors de l'exécution de SetTimeout, nous définissons d'abord une fonction flèche anonyme, et le point clé est ici. L'objet de la fonction flèche où cela est exécuté lors de la définition de cette fonction flèche est indiqué à cette portée lors de la définition de cette fonction de flèche, c'est-à-dire ceci dans obj.foo2, c'est-à-dire obj; Ainsi, lors de l'exécution de la fonction de flèche, c'est ce -> obj dans obj.foo2 -> obj;
Autrement dit, cela dans la fonction de flèche est lié à cela dans la portée lors de la définition, et n'a rien à voir avec où et comment il est appelé. En même temps, c'est ce pointage est immuable.
Appelez, appliquez, liez
Dans JS, les fonctions sont également des objets et il existe également certaines méthodes. Ici, nous introduisons trois méthodes, ils peuvent changer ce pointeur dans la fonction:
appel
fun.call (thisarg [, arg1 [, arg2 [, ...]]])
Il exécutera immédiatement la fonction. Le premier paramètre spécifie le contexte de celui-ci dans la fonction d'exécution, et le paramètre suivant est les paramètres qui doivent être transmis dans la fonction d'exécution;
appliquer
fun.apply (thisarg [, [arg1, arg2, ...]]))
Il exécutera immédiatement la fonction. Le premier paramètre spécifie le contexte de celui-ci dans la fonction d'exécution, et le deuxième paramètre est un tableau, qui est le paramètre transmis à la fonction d'exécution (la différence par rapport à l'appel);
lier
var foo = fun.bind (thisarg [, arg1 [, arg2 [, ...]]]);
Il n'exécute pas la fonction, mais renvoie une nouvelle fonction. Cette nouvelle fonction spécifie le contexte de cela, et les paramètres suivants sont les paramètres qui doivent être transmis pour exécuter la fonction;
Ces trois fonctions sont en fait similaires. Le but général est de spécifier le contexte d'une fonction (ceci). Prenons la fonction d'appel comme exemple;
Spécifiez cela pour une fonction normale
var obj = {name: 'qiUtc'}; fonction foo () {console.log (this);} foo.call (obj); // objet {name: "qiUtc"}On peut voir que lors de l'exécution de Foo.Call (OBJ), cela dans la fonction pointe vers l'objet OBJ, qui réussit;
Spécifiez un pour la méthode dans l'objet
var obj = {name: 'qiUtc', foo: function () {console.log (this); }} var obj2 = {name: 'tcqiu222222'}; obj.foo.call (obj2); // objet {name: "tcqiu222222"}Vous pouvez voir que lors de l'exécution de la fonction, cela souligne l'OBJ2, qui réussit;
Spécifiez cela pour le constructeur
fonction personne (name) {this.name = name; console.log (this);} var obj = {name: 'qiUtc2222222'}; var p = new Person.Call (obj, 'qiUtc'); // non apparié TypeError: Person.Call n'est pas un constructeur (…)Une erreur a été signalée ici parce que nous sommes allés à une nouvelle personne.
Changer pour lier et essayer:
fonction personne (name) {this.name = name; console.log (this);} var obj = {nom: 'qiUtc2222222'}; var person2 = personne.bind (obj); var p = new Person2 ('qiUtc'); // personne {name: "Qiutc"} console.log (obj); //Ce qui est imprimé, c'est l'objet instancié par la personne, ce qui n'a rien à voir avec Obj, et OBJ n'a pas changé, indiquant que nous spécifions ce contexte à la personne sans prendre effet;
Par conséquent, on peut conclure que l'utilisation de Bind pour le spécifier pour un constructeur. Lorsque le nouveau constructeur, cette fonction spécifiée par Bind ne prendra effet;
Bien sûr, Bind peut non seulement spécifier cela, mais aussi passer des paramètres. Essayons cette opération:
fonction personne (name) {this.name = name; console.log (this);} var obj = {name: 'qiUtc2222222'}; var person2 = personne.bind (obj, 'qiUtc11111'); var p = new person2 ('qiutc'); // personne {name: "qiutc1111"}}Comme vous pouvez le voir, bien que cela ne fonctionne pas, les paramètres entrants fonctionnent toujours;
Spécifiez ceci pour la fonction de flèche
Définissons une fonction de flèche sous le global, de sorte que dans cette fonction flèche, indiquera inévitablement l'objet global. Et si cela est modifié en utilisant la méthode d'appel:
var afoo = (a) => {console.log (a); console.log (this);} afoo (1); // 1 // windowvar obj = {name: 'qiutc'}; afoo.call (obj, 2); // 2 // fenêtreComme vous pouvez le voir, le fonctionnement de l'appel pointant vers cela ici n'a pas réussi, il peut donc être conclu que cela dans la fonction Arrow a déjà décidé lors de la définition (exécutez cela dans la portée qui le définit), et n'a rien à voir avec la façon de l'appeler et où l'appeler. Aucune opération, notamment (appel, appliquer, lier) et d'autres opérations ne peuvent changer ceci.
N'oubliez pas que la fonction de flèche est bonne et cela reste inchangé.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.