Compréhension approfondie des portées JavaScript
Introduction
JavaScript est un langage full stack, en particulier en 2016, j'entends souvent dire que JavaScript va dominer le monde. Il y a même des rumeurs selon lesquelles vous pouvez trouver un emploi si vous connaissez Vue.js en 2016, tout comme vous pouvez trouver un emploi si vous connaissez TableView sur iOS à l'époque. (tableView est assez basé sur ListView d'Android, mais maintenant ils utilisent essentiellement RecyclerView)
Les technologies frontales populaires en 2016 sont essentiellement liées à JavaScript, comme le multiplateforme mobile React Native produit par Facebook et Alibaba. Weex, la technologie de réparation à chaud JSPath et Node.js sur le backend (une pile technologique que j'aime beaucoup). Je suis allé sur gibhub hier soir pour le vérifier. Le nombre d'étoiles pour Vue a dépassé celui de jQuery. le nombre d'étoiles ne prouve rien, du moins nous l'avons déjà fait. Je peux voir que la pensée frontale a changé depuis l'opération de document précédente vers un développement basé sur les données (si vous êtes intéressé, je peux combiner Android, iOS et Vue plus tard pour démontrer ce changement de pensée avec une petite démo). Certaines entreprises ont même commencé à essayer d'utiliser Hungry Element produit par cette société pour remplacer EasyUI (les étudiants qui ont fait du back-end doivent savoir qu'EasyUI est vraiment de qualité AV...)
La technologie JS émerge sans fin, et il y avait déjà eu un article très populaire, apprendre JS en 2016. De quel genre d'expérience il s'agissait, cela a effrayé de nombreuses personnes en un instant. Tout le monde s'est concentré sur les frameworks et les nouvelles technologies. , mais JS natif a été laissé de côté, je voulais donc partager avec vous quelques problèmes de base de JS. Communiquons ensemble (j'espère que tout le monde m'emmènera voler, mais ne me laissez pas voler sur Malaysia Airlines...)
Portée en JavaScript
Une question simple :
<script> var str1 = "hello"; var str2 = "world"; function t1() { console.log(str1); console.log(str2); var str2 = "toby"; console.log(str2); } //这里会输出什么? t1(); </script>
Il s'agit d'un problème de portée JS très simple, mais plus vous insistez sur le mot "simple", plus il est facile pour les gens de relâcher leur vigilance, ce qui amène certains étudiants à répondre sans réfléchir
gir bonjour
gird monde
gi toby
Mais le résultat est la sortie
gi bonjour
gi non défini
Quantity toby
Alors c'est étrange, pourquoi y a-t-il undefined ? Non Devrait-il être world ? Tout d'abord, il faut comprendre que la recherche de variables suivra le principe de proximité, donc js le fera ? recherchez d'abord dans la fonction, puis regardez à l'extérieur si elle est introuvable. Il y a str2 dans la fonction, mais lors de l'exécution vers console.log(str2 ) lorsque str2 n'est pas défini, donc indéfini
analyse lexicale
Pour savoir ce qui se passe, il faut savoir pourquoi, alors regardons un quelques exemples supplémentaires
Exemple 1
<script> function t(userName) { console.log(userName);//这里输出什么? function userName() { console.log('tom'); } } t('toby'); </script>
Quel est le résultat de sortie Cet exemple semble être différent de celui ci-dessus. les mathématiques scolaires et la confusion lorsque le type de question change. À ce moment-là, certains élèves peuvent penser que c'est Toby, mais le résultat réel est
function userName() { console.log('tom'); }
Pourquoi est-ce fonctionnel Quoi ? Le problème de portée peut être obtenu grâce à un "ensemble de formules". Cette formule est une analyse lexicale dans JS. L'une des choses qui doivent être faites avant que la fonction dans JS ne soit exécutée est une analyse lexicale. Alors, qu'est-ce que c'est exactement ? ? Analyser les paramètres, analyser les déclarations de variables, analyser les déclarations de fonctions, puis nous utiliserons cette question pour appliquer la formule
Lorsque t('toby') sera exécuté, deux étapes commenceront, une C'est l'étape d'analyse. Après l'analyse, elle passe à l'étape d'exécution
Étape d'analyse :
● Au moment où la fonction s'exécute, un objet actif (ci-après dénommé l'objet AO) sera généré, qui pourra être trouvé dans la portée d'une fonction. Toutes les variables de sont sur AO À ce stade, le code est exprimé comme : t.AO = {}
● Paramètres d'analyse : recevoir les paramètres, utiliser les noms de paramètres comme attributs et. valeurs des paramètres en tant que valeurs d'attribut, car il n'y a pas de paramètres, donc le résultat de l'analyse est exprimé en code : t.AO = {userName : toby}
● Analyse de l'instruction var : il n'y a pas d'instruction var. dans la fonction t, sautez
● Analyse de l'instruction de fonction : cette déclaration de fonction a une caractéristique S'il y a un attribut du même nom que le nom de la fonction sur l'AO, il sera écrasé par cette fonction. Étant donné que la fonction est également un type de variable dans le champ JS, elle est exprimée en code comme suit : t.AO = { userName: function userName() {console.log('tom');}}
Phase d'exécution :
Lors de l'exécution de t('toby'), lors de l'exécution sur console.log(userName) Lorsque , t.AO.userName est appelé, le résultat final est donc function userName() {console. log('tom');}
Exemple 2
<script> function t(userName) { console.log(userName);//这里输出什么? var userName = function () { console.log('tom'); } } t('toby'); </script>
Alors quel est le résultat ici Cela semble être différent de l'exemple ci-dessus, et il ? est à nouveau tombé dans la confusion ? N'ayez pas peur des ennuis, et suivez fermement le processus selon la formule (l'exemple ci-dessus est écrit comme Plus détaillé, l'analyse suivante sera simplement écrite)
Avant l'analyse, vous devez d'abord comprendre deux concepts, l'un est appelé déclaration de fonction et l'autre est appelé expression de fonction
//这个叫函数声明 function userName() { console.log('tom'); } //这个叫函数表达式 var userName = function () { console.log('tom'); }
Étape d'analyse :
● Créer un objet AO, t.AO = {}
● Paramètres d'analyse : t.AO = {userName : toby}
● 分析var声明: 在AO上,形成一个属性,以var的变量名为属性名,值为undefined,(因为是先分析,后执行,这只是词法分析阶段,并不是执行阶段,分析阶段值都是undefined,如果执行阶段有赋值操作,那值会按照正常赋值改变),也就是说代码应该表示为:t.AO = {userName : undefined},但是还有另外一个原则,那就是如果AO有已经有同名属性,则不影响(也就是什么事都不做),由于分析参数时,AO上已经有userName这个属性了,所以按照这个原则,此时什么事都不做,也就是说,此时按照分析参数时的结果t.AO = {userName : toby}
● 分析函数声明: 此时没有函数声明,略过
执行阶段:
调用t.AO.userName,所以,最后的输出结果是toby
例子3
<script> t(); t2(); function t() { console.log('toby');//这里会输出什么? } var t2 = function () { console.log('hello toby');//这里会输出什么? }; </script>
那么我们再来看一个例子,这下彻底回到高中时代,做了两个例子好像感觉掌握了,结果考试你给来看这个?
答案是,t()输出为toby,t2()则会报错.这又是为什么?
● t()可以调用是因为在词法分析的过程,就已经完成了t函数的分析,所以可以调用
● t2()不能调用是因为在词法分析的阶段,分析到有一个t2声明,在AO上只是形成了一个属性,但是值为undefined
例子4
<script> function t(userName) { console.log(userName);//这里输出什么? function userName() { console.log(userName);//这里输出什么? } userName(); } t('toby'); </script>
函数里面套函数,这次竟然又和前面不一样了...这次我不说答案了,直接先套公式走一波
t('toby')的分析和执行阶段
分析阶段:
● 创建AO对象,t.AO = {}
● 分析参数: t.AO = {userName : toby}
● 分析var声明: 有同名属性,不做任何事,还是t.AO = {userName : toby}
● 分析函数声明: 有同名属性,覆盖: t.AO = {userName : function userName() {console.log(userName);}}
执行阶段: t.AO.userName 输出为function userName() {console.log(userName);}}
userName()的分析和执行阶段
这里也要搞清楚两个概念
//执行userName()分析的是 function () { console.log(userName); }; //而不是 var userName = function () { console.log(userName); };
分析阶段:
● 创建AO对象,userName.AO = {}
● 分析参数: 无,略过
● 分析var声明: 无,略过
● 分析函数声明: 无,略过
执行阶段: 因为此时userName.AO = {}是个空对象,无法执行userName.AO.userName,所以会向上一层找,所以输出t.AO.userName的结果,也就是function userName() {console.log(userName);}}
例子5
<script> function t(userName) { console.log(userName);//这里输出什么? var userName = function () { console.log(userName);//这里输出什么? } userName(); } t('toby'); </script>
好吧,我保证这个是最后一道...这个输出结果是什么呢?我们只要坚定公式没问题,就一定能得出结果,那么再套公式走一波
t('toby')的分析和执行阶段
分析阶段:
● 创建AO对象,t.AO = {}
● 分析参数: t.AO = {userName : toby}
● 分析var声明: 有同名属性,不做任何事,还是t.AO = {userName : toby}
● 分析函数声明: 无,略过
执行阶段: 执行console.log(userName);时调用t.AO.userName 输出为toby,执行完后,代码继续往下执行,那么就到了进行var的赋值操作(var的分析和执行的区别看例子2中我有解释),此时t.AO = {userName : function userName() {console.log(userName);}}},代码继续往下执行,接着就执行到了userName()
userName()的分析和执行阶段
分析阶段:
● 创建AO对象,userName.AO = {}
● 分析参数: 无,略过
● 分析var声明: 无,略过
● 分析函数声明: 无,略过
执行阶段: 按照例子4我们知道userName.AO是个空对象,所以会往上调用t.AO.userName,所以输出为:function userName() {console.log(userName);}}}
总结
JavaScript作用域会先在自己的AO上找,找不到就到父函数的AO上找,再找不到再找上一层的AO,直到找到window.这样就形成一条链,这条AO链就是JavaScript中的作用域链.JavaScript中有两条很重要的链,一条是作用域链,一条是原型链,

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

typedef struct est utilisé en langage C pour créer des alias de type de structure afin de simplifier l'utilisation des structures. Il crée un alias pour un nouveau type de données sur une structure existante en spécifiant l'alias de la structure. Les avantages incluent une lisibilité améliorée, la réutilisation du code et la vérification du type. Remarque : La structure doit être définie avant d'utiliser un alias. L'alias doit être unique dans le programme et valide uniquement dans le périmètre dans lequel il est déclaré.

Les exceptions de valeur attendue des variables en Java peuvent être résolues en : initialisant les variables ; en utilisant des valeurs par défaut ; en utilisant des contrôles et des affectations et en connaissant la portée des variables locales ;

Les avantages des fermetures JavaScript incluent le maintien d'une portée variable, l'activation du code modulaire, l'exécution différée et la gestion des événements ; les inconvénients incluent les fuites de mémoire, la complexité accrue, la surcharge de performances et les effets de chaîne de portée.

La directive de préprocesseur #include en C++ insère le contenu d'un fichier source externe dans le fichier source actuel, en copiant son contenu à l'emplacement correspondant dans le fichier source actuel. Principalement utilisé pour inclure des fichiers d'en-tête contenant les déclarations nécessaires dans le code, telles que #include <iostream> pour inclure des fonctions d'entrée/sortie standard.

Cycle de vie des pointeurs intelligents C++ : Création : Les pointeurs intelligents sont créés lors de l'allocation de mémoire. Transfert de propriété : Transférer la propriété via une opération de déménagement. Libération : la mémoire est libérée lorsqu'un pointeur intelligent sort de la portée ou est explicitement libéré. Destruction d'objet : lorsque l'objet pointé est détruit, le pointeur intelligent devient un pointeur invalide.

Peut. C++ autorise les définitions et les appels de fonctions imbriquées. Les fonctions externes peuvent définir des fonctions intégrées et les fonctions internes peuvent être appelées directement dans la portée. Les fonctions imbriquées améliorent l'encapsulation, la réutilisabilité et le contrôle de la portée. Cependant, les fonctions internes ne peuvent pas accéder directement aux variables locales des fonctions externes et le type de valeur de retour doit être cohérent avec la déclaration de la fonction externe. Les fonctions internes ne peuvent pas être auto-récursives.

Dans Vue, il existe une différence de portée lors de la déclaration de variables entre let et var : Scope : var a une portée globale et let a une portée au niveau du bloc. Portée au niveau du bloc : var ne crée pas de portée au niveau du bloc, let crée une portée au niveau du bloc. Redéclaration : var permet de redéclarer les variables dans la même portée, ce qui n'est pas le cas.

En JavaScript, les types de pointage de this incluent : 1. Objet global ; 2. Appel de fonction ; 3. Appel de constructeur 4. Gestionnaire d'événements 5. Fonction de flèche (héritant de this). De plus, vous pouvez définir explicitement ce que cela désigne à l'aide des méthodes bind(), call() et apply().
