Home >Web Front-end >JS Tutorial >A brief discussion on the scope and closure of JavaScript variables

A brief discussion on the scope and closure of JavaScript variables

青灯夜游
青灯夜游forward
2019-11-25 14:47:202112browse

Concepts related to closures: the scope of variables and the lifetime of variables. The following article will introduce to you the scope and closure of variables in JavaScript. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

A brief discussion on the scope and closure of JavaScript variables

1. The scope of the variable

1. The scope of the variable refers to the valid range of the variable , closely related to the location of variable definition, scope describes variables from a spatial perspective, and can also be understood as the visibility of variables. A variable is visible within a certain scope, that is, it is available. [Related course recommendations: JavaScript Video Tutorial]

2. According to different scopes, variables can be divided into global variables and local variables.

● Global variables: variables declared in the global environment

● Local variables: variables declared in the function

● When the function is executed, a closure is created The execution context of the function, the variables declared inside the function can only be used inside the function, and cannot be accessed from the outside, while global variables can be used anywhere

3. Use the var keyword in the function to display the declared Variables are local variables; instead of using the var keyword, variables declared by direct assignment are global variables

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

4. Rely on variable scope to implement encapsulation features

(1) Use ES6 The provided let
(2) creates the scope through the function:

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

2. The life cycle of the variable

1. For For global variables, their life cycle is permanent unless the global variable is actively destroyed;

2. For local variables declared with the var keyword within a function, when the function exits, these local variables That is, they lose their value and they will be destroyed as the function call ends

3. Imitation of block-level scope

(1) Used as an anonymous function in block-level scope: A function declaration is enclosed in a pair of parentheses, indicating that it is actually a function expression, and another pair of parentheses following it immediately calls the function.

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

Any variables defined in the anonymous function will be destroyed at the end of execution

(2) First define a function and then call it. The way to define a function is to create an anonymous function and assign the anonymous function to a variable; and to call a function is to add a pair of parentheses after the function name.

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

Classic question:

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

Explanation: The onclick event of the div node is triggered asynchronously. When the event is triggered, the for loop It has ended a long time ago. At this time i is already 5

Solution:

Method 1: Use let in ES6

Method 2: In the closure With the help of 1) Encapsulated variables: Closures can encapsulate some variables that do not need to be exposed globally as "private variables". Private variables include function parameters, local variables and other functions defined within the function.

Example: mult function receives number type parameters and returns the product of these parameters,

Initial code:

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);
}

After using closure:

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

Supplement: in determines that the attribute belongs to the object

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) Extend the life of local variables

Example: When using report data to report, about 30% of the data will be lost. The reason is that in the report when img When the report function call ends, the img local variable is destroyed immediately

Initial code:

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;);
}

After using the closure (encapsulate the img variable with a closure):

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

5. Closure and object-oriented design

Closure writing method:

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

Object-oriented writing method one:

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

Object-oriented writing method two:

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

6. Closures and memory management

● Local variables should be dereferenced when the function exits, but if the local variables are enclosed in the environment formed by the closure, then the local variables will remain survive, that is, it will remain in memory.

● It is easier to form a circular reference when using closures. If some DOM nodes are stored in the scope chain of the closure, this may cause a memory leak.

● Solve the memory leak problem caused by circular references: Set the variables in the circular references to null. (Setting a variable to null cuts the connection between the variable and the values ​​it previously referenced. When the garbage collector runs next time, these values ​​will be deleted and the memory they occupy will be reclaimed)

7, Features:

● Function nested function;

● External parameters and variables can be referenced inside the function;

● Parameters and variables will not be recycled by the garbage collection mechanism.

8. Advantages: Avoid pollution of global variables

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教程 栏目,欢迎学习!

The above is the detailed content of A brief discussion on the scope and closure of JavaScript variables. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete