Maison > interface Web > js tutoriel > Une explication détaillée de la portée en JavaScript

Une explication détaillée de la portée en JavaScript

阿神
Libérer: 2017-03-04 14:44:52
original
1229 Les gens l'ont consulté

Introduction

JavaScript est un langage full-stack Surtout en 2016, j'entends souvent des rumeurs selon lesquelles JavaScript dominerait le monde, et il y a même des rumeurs. . On dit que 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 équivalent à ListView d'Android, mais maintenant ils utilisent essentiellement RecyclerView).

2016 Les technologies front-end populaires sont essentiellement liées à JavaScript, comme le multiplateforme mobile React Native produit par Facebook et Weex d'Alibaba, la technologie de réparation à chaud JSPath et le back-end Node.js ( une pile technologique que j'aime beaucoup). Hier, je suis allé sur gibhub plus tard et j'ai jeté un œil. Le nombre d'étoiles de Vue a dépassé celui de jQuery. Bien que le nombre d'étoiles ne prouve rien, au moins nous avons vu que le nombre d'étoiles est supérieur à celui de jQuery. la pensée frontale est passée de l'opération de document précédente au développement basé sur les données (si vous êtes intéressé (je peux combiner Android, iOS et Vue plus tard pour utiliser une petite démo pour démontrer ce changement de pensée). Certaines entreprises ont même commencé). essayer d'utiliser Element produit par Ele.me pour remplacer EasyUI (les étudiants qui ont fait du back-end doivent savoir qu'EasyUI est vraiment une qualité de peinture AV....)

Les technologies JS émergent les unes après les autres Il y a eu un article très populaire sur ce que c'était que d'apprendre JS en 2016. Cela a effrayé beaucoup de gens. En ce qui concerne les frameworks et les nouvelles technologies, le JS natif a été laissé de côté, j'aimerais donc. pour partager quelques problèmes de base de JS avec tout le monde


Portée en JavaScript

Ce qui suit est 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>
Copier après la connexion

Il s'agit d'un problème JS Scope 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 conduit certains élèves à répondre sans réfléchir

Quantity bonjour

Quantity world

weight toby

Mais le résultat est la sortie

weight bonjour

● indéfini

● Toby

Alors c'est étrange, pourquoi y a-t-il un indéfini ne devrait-il pas être du monde ? les variables suivront le principe de proximité, donc js recherchera d'abord dans la fonction, puis regardera à l'extérieur si elle ne peut pas être trouvée, et il y a str2 dans la fonction. Mais lors de l'exécution vers console.log(str2), str2 n'est pas défini. , donc indéfini


analyse lexicale

Il faut Je sais pourquoi, alors regardons quelques exemples supplémentaires

Exemple 1

<script>
    function t(userName) {
        console.log(userName);//这里输出什么?

        function userName() {
            console.log(&#39;tom&#39;);
        }
    }
    t(&#39;toby&#39;);
</script>
Copier après la connexion

Quel est le résultat de sortie Cet exemple semble être différent de celui ci-dessus ? C'est comme retourner aux mathématiques du lycée et être confus 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(&#39;tom&#39;);
}
Copier après la connexion

Pourquoi est-ce une fonction ? En fait, ce type de problème de portée peut être obtenu grâce à un "ensemble de formules". Cette formule est l'analyse lexicale en JS, ce qui doit être fait avant que la fonction en JS ne soit exécutée. Le premier travail est l'analyse lexicale, et alors. exactement est requis ? Analyser les paramètres, analyser les déclarations de variables, analyser les déclarations de fonctions, alors utilisons cette question pour appliquer la formule

lors de l'exécution de t('toby') , commencera deux phases, l'une est la phase d'analyse, après l'analyse, elle passera à la phase d'exécution

Phase d'analyse :

● Au moment où la fonction s'exécute, un Objet Actif sera généré Objet (ci-après dénommé en tant qu'objet AO), toutes les variables que l'on peut trouver dans une portée de fonction sont sur AO. A ce moment, le code est exprimé comme suit : t.AO = {}

● Paramètres d'analyse : Paramètres de réception, avec Le. le nom du paramètre est un attribut et la valeur du paramètre est une valeur d'attribut. Comme il n'y a pas de paramètres, le résultat de l'analyse est exprimé en code : t.AO = {userName : toby}

● Analyse de l'instruction var : Il y a. pas d'instruction var dans la fonction t. Sauter

● Analyser la déclaration de fonction : Cette déclaration de fonction a une particularité. S'il y a un attribut avec le même nom que le nom de la fonction sur l'AO, il sera écrasé par. cette fonction, car la fonction est aussi un type de variable dans le champ JS, donc exprimé en code : t.AO = { userName : function userName() {console.log('tom');}}

Phase d'exécution :

Lors de l'exécution de t('toby'), lorsque console.log(userName) est exécuté, t.AO.userName est appelé, donc le résultat final est function userName() {console.log('tom') ;}

Exemple 2

<script>
    function t(userName) {
        console.log(userName);//这里输出什么?

        var userName = function () {
            console.log(&#39;tom&#39;);
        }
    }
    t(&#39;toby&#39;);
</script>
Copier après la connexion

Alors quel est le résultat ici Cela semble être différent ? de l'exemple ci-dessus, et je suis à nouveau confus. ?N'ayez pas peur des ennuis et suivez résolument la formule et recommencez le processus (l'exemple ci-dessus est écrit plus en détail, l'analyse suivante est simplement écrite)

Avant l'analyse, vous devez d'abord comprendre deux concepts, l'un s'appelle une instruction de fonction, une expression de fonction appelée

//这个叫函数声明
function userName() {
    console.log(&#39;tom&#39;);
}

//这个叫函数表达式
var userName = function () {
    console.log('tom');
}
Copier après la connexion

Étape d'analyse :

● Créer un objet AO, t. AO = {}

Quantity 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(&#39;toby&#39;);//这里会输出什么?
    }

    var t2 = function () {
        console.log(&#39;hello toby&#39;);//这里会输出什么?
    };
</script>
Copier après la connexion

那么我们再来看一个例子,这下彻底回到高中时代,做了两个例子好像感觉掌握了,结果考试你给来看这个?

答案是,t()输出为toby,t2()则会报错.这又是为什么?

● t()可以调用是因为在词法分析的过程,就已经完成了t函数的分析,所以可以调用

● t2()不能调用是因为在词法分析的阶段,分析到有一个t2声明,在AO上只是形成了一个属性,但是值为undefined

例子4

<script>
    function t(userName) {
        console.log(userName);//这里输出什么?
        function userName() {
            console.log(userName);//这里输出什么?
        }
        userName();
    }
    t(&#39;toby&#39;);
</script>
Copier après la connexion

函数里面套函数,这次竟然又和前面不一样了...这次我不说答案了,直接先套公式走一波

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);
};
Copier après la connexion

分析阶段:

● 创建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(&#39;toby&#39;);
</script>
Copier après la connexion

好吧,我保证这个是最后一道...这个输出结果是什么呢?我们只要坚定公式没问题,就一定能得出结果,那么再套公式走一波

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() {console.log(userName);}},代码继续往下执行,接着就执行到了userName()

userName()的分析和执行阶段

分析阶段:

● 创建AO对象,userName.AO = {}

● 分析参数: 无,略过

● 分析var声明: 无,略过

● 分析函数声明: 无,略过

执行阶段: 按照例子4我们知道userName.AO是个空对象,所以会往上调用t.AO.userName,所以输出为:function () {console.log(userName);}


总结

JavaScript作用域会先在自己的AO上找,找不到就到父函数的AO上找,再找不到再找上一层的AO,直到找到window.这样就形成一条链,这条AO链就是JavaScript中的作用域链.

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal