Maison  >  Article  >  interface Web  >  Une brève discussion sur la portée et la fermeture des variables JavaScript

Une brève discussion sur la portée et la fermeture des variables JavaScript

青灯夜游
青灯夜游avant
2019-11-25 14:47:202054parcourir

Concepts liés aux fermetures : la portée des variables et la durée de vie des variables. L'article suivant vous présentera la portée et la fermeture des variables en JavaScript. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.

Une brève discussion sur la portée et la fermeture des variables JavaScript

1. La portée de la variable

1. plage valide de la variable, étroitement liée à l'emplacement de la définition de la variable, la portée décrit les variables d'un point de vue spatial et peut également être comprise comme la visibilité des variables. Une variable est visible dans une certaine portée, c'est-à-dire qu'elle est disponible. [Recommandations de cours associées : Tutoriel vidéo JavaScript]

2. Selon différentes portées, les variables peuvent être divisées en variables globales et variables locales.

● Variables globales : variables déclarées dans l'environnement global

● Variables locales : variables déclarées dans la fonction

● Lorsque la fonction est exécutée, une fermeture est créée L'exécution Dans le contexte de la fonction, les variables déclarées à l'intérieur de la fonction ne peuvent être utilisées qu'à l'intérieur de la fonction et ne sont pas accessibles de l'extérieur, tandis que les variables globales peuvent être utilisées n'importe où

3. Utilisez le mot-clé var dans la fonction pour afficher le Les variables de déclaration sont des variables locales ; au lieu d'utiliser le mot-clé var, les variables déclarées par affectation directe sont des variables globales

var m=8;
function f1(){
    var a1=10;
    console.log(m);  //8
}
function f2(){
    var a2=20;
    console.log(m);  //8
}
f1();
f2();

4 S'appuyer sur la portée des variables pour implémenter les fonctionnalités d'encapsulation

(1) Utilisez ES6 Le. à condition que let
(2) crée la portée via des fonctions :

var myObject=(function(){
    var _name="yian";  //私有变量
    return {
        getName:function(){  //公有方法
            return _name;
        }
    }
})();
console.log(myObject._name);  //undefined
console.log(myObject.getName());  //yian

2. Cycle de vie des variables

1 Pour Pour global. variables, leur cycle de vie est permanent à moins que la variable globale ne soit activement détruite ;

2 Pour les variables locales déclarées avec le mot-clé var dans une fonction, lorsque la fonction se termine, ces variables locales perdent leur valeur. et ils seront détruits à la fin de l'appel de fonction

3. Imitez la portée au niveau du bloc

(1) Utilisez des fonctions anonymes comme portée au niveau du bloc : une déclaration de fonction est entourée d'une paire de parenthèses, indiquant qu'il s'agit en fait d'une expression de fonction, et une autre paire de parenthèses qui la suit appelle immédiatement la fonction.

(function(){
    //这里是块级作用域
})();

Toutes les variables définies dans la fonction anonyme seront détruites à la fin de l'exécution

(2) Définissez d'abord une fonction puis appelez-la. La façon de définir une fonction consiste à créer une fonction anonyme et à affecter la fonction anonyme à une variable. Pour appeler une fonction, il faut ajouter une paire de parenthèses après le nom de la fonction.

var someFunction=function(){
    //这里是块级作用域
};
someFunction();

Problème classique :

var nodes=document.getElementsByTagName("div");
for(var i= 0,len=nodes.length;i<len;i++){
    nodes[i].onclick=function(){
        console.log(i);  //无论点击哪个div,最后弹出的结果都是5
    }
}

Explication : L'événement onclick du nœud div est déclenché de manière asynchrone Lorsque l'événement est déclenché, le for. loop C'est terminé il y a longtemps. A ce moment, j'ai déjà 5

Solution :

Méthode 1 : Utiliser let dans ES6

Méthode 2 : Dans la fermeture À l'aide de 1) Variables encapsulées : Les fermetures peuvent encapsuler certaines variables qui n'ont pas besoin d'être exposées globalement en tant que « variables privées ». Les variables privées incluent les paramètres de fonction, les variables locales et d'autres fonctions définies dans la fonction.

Exemple : La fonction mult reçoit des paramètres de type numéro et renvoie le produit de ces paramètres,

Code initial :

var nodes=document.getElementsByTagName("div");
for(var i= 0,len=nodes.length;i<len;i++){
    (function(x){
        nodes[i].onclick=function(){
            console.log(x);
        }
    })(i);
}

Après utilisation de la fermeture :

var cache={ };
var mult=function(){
    var args=Array.prototype.join.call(arguments,",");
    if(cache[args]){
        return cache[args];
    }
    var a=1;
    for(var i=0,len=arguments.length;i<len;i++){
        a=a*arguments[i];
    }
    return cache[args]=a;
};
console.log(mult(1,2,3));  //6
console.log(mult(3,4,5));  //60

Supplément : in détermine que l'attribut appartient à l'objet

var mult=(function(){
    var cache={ };  //加入缓存机制,避免相同参数的计算
    var calculate=function(){
        var a=1;
        for(var i= 0,len=arguments.length;i<len;i++){
            a=a*arguments[i];
        }
        return a;
    };
    return function(){
        var args=Array.prototype.join.call(arguments,",");
        if(args in cache){
            return cache[args];
        }
        return cache[args]=calculate.apply(null,arguments);
    }
})();

(2) Prolonger la durée de vie des variables locales

Exemple : lors de la déclaration de données à l'aide d'un rapport, environ 30 % des données seront perdu. La raison est que dans le rapport lorsque la variable locale img, lorsque l'appel de la fonction de rapport se termine, la variable locale img est immédiatement détruite

Code initial :

var mycar = {make: "Honda", model: "Accord", year: 1998};
if ( "make" in mycar ){  //属性名必须是字符串形式,因为make不是一个变量
    document.write(&#39;true&#39;);  // 显示true
}
else{
    document.write(&#39;false&#39;);
}

Après avoir utilisé la fermeture (encapsuler le img avec fermeture) :

var report=function(src){
    var image=new Image();
    image.src=src;
};

5. Fermeture et conception orientée objet

Méthode d'écriture de fermeture :

var report=(function(){
    var imgs=[ ];
    return function(){
        var image=new Image();
        imgs.push(image);
        image.src=src;
    }
})();

Méthode d'écriture orientée objet 1 :

var extent=function(){
    var value=0;
    return {
        call:function(){
            value++;
            console.log(value);
        }
    }
}
var extent=extent();
extent.call();  //1
extent.call();  //2

Deuxième méthode d'écriture orientée objet :

var extend={
    value:0,
    call:function(){
        this.value++;
        console.log(this.value);
    }
};
extend.call();  //1
extend.call();  //2

6. Fermetures et gestion de la mémoire

● Les variables locales doivent être déréférencées à la sortie de la fonction, mais si les variables locales sont enfermées dans l'environnement formé. par la fermeture, alors les variables locales resteront en vie, c'est-à-dire qu'elles resteront en mémoire.

● Il est plus facile de former une référence circulaire lors de l'utilisation de fermetures. Si certains nœuds DOM sont stockés dans la chaîne de portée de la fermeture, cela peut provoquer une fuite de mémoire.

● Résolvez le problème de fuite de mémoire provoqué par les références circulaires : définissez les variables dans les références circulaires sur null. (Définir une variable sur null coupe le lien entre la variable et les valeurs auxquelles elle faisait précédemment référence. Lors de la prochaine exécution du garbage collector, ces valeurs seront supprimées et la mémoire qu'elles occupent sera récupérée)

7. Caractéristiques :

● Fonction imbriquée

● Les paramètres et variables externes peuvent être référencés à l'intérieur de la fonction

● Les paramètres et variables ne seront pas recyclés par la fonction ; mécanisme de collecte des déchets.

8.Avantages : Éviter la pollution des variables globales

9、缺点:会常驻内存,增加内存的使用量,使用不当会造成内存泄漏;闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存

10、创建闭包

写法一:

function a() {  
	var b=123;  
	function c(){
    	console.log(b+=1);
    }  
    return c;
}
var d=a();
d();

方式二:

function f1(){
    var num=10;  //函数执行完毕,变量仍然存在
    var f2=function(){
        num++;
        console.log(num);  //11
    };
    return f2;
}
var res=f1();
res();

● 解释:执行f1()后,f1()闭包内部的变量会存在,而闭包内部函数的内部变量不会存在,使得JavaScript的垃圾回收机制不会收回f1()占用的资源,因为f1()中内部函数的执行需要依赖f1()中的变量。

方式三:

function foo(x) {
    var tmp = 3;
    return function f2(y) {
        alert(x + y + (++tmp));  //17
    };
}
var bar = foo(3);  //bar现在是一个闭包
bar(10);

练习题:

function f1(){
   var a=1;
   t=function(){
       a++;
   }
   return function(){
       console.log(a);
   }
}
var b=f1();  //返回值为一个匿名函数
b();  //1
t();
b();  //2

声明变量,若变量名称相同,就近原则:

var name="g";
function out(){
    var name="loc";
    function foo(){
        console.log(name);
    }
    foo();
}
out();  //name=loc

补充知识点:

1、JS中有哪些垃圾回收机制?

(1)引用计数:跟踪记录每个值被使用的次数。

● 当声明一个变量并将一个引用类型赋值给该变量时,该值的引用次数加1;

● 若该变量的值变为另一个,则该值引用次数减1;

● 若该值引用次数为0时,说明变量没有在使用,此值无法访问;

● 因此,可以将它占用的空间回收,垃圾回收机制会在运行时清理引用次数为0 的值所占用的空间。

● 在低版的IE中会发生内存泄漏,很多时候就是因为它采用引用计数得到方式进行垃圾回收(如果两个对象之间形成了循环引用,那么这两个对象都无法被回收)。

(2)标记清除:最常见的垃圾回收方式

● 当变量进入执行环境时,垃圾回收器将其标为“进入环境”,离开时标记为“离开环境”;

● 垃圾回收机制在运行时给存储在内存中的所有变量加上标记;

● 去掉环境中的变量及被环境中变量所引用的变量(闭包)的标记;

● 完成这些后仍存在的标记就是要删除的变量。

2、哪些操作会造成内存泄漏?

● 内存泄漏:指不再拥有或需要任何对象(数据)之后,它们仍然存在于内存中。

● 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为0(没有其他对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象占用的内存立即被回收。

● 如果setTimeout的第一个参数使用字符串而非函数,会造成内存泄漏。

● 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)等会造成内存泄漏。

本文来自 js教程 栏目,欢迎学习!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer