JS之闭包

  闭包是很多语言都具备的特性,在js中,闭包主要涉及到js的几个其他的特性:

  1)作用域链

  2)垃圾(内存)回收机制

  3)函数嵌套...等等.

  首先理解一下作用域链的含义,简单来说,作用域链就是函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引。

而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止。

当函数中需要查询一个变量的值的时候,js解释器会去作用域链去查找,从最前面的本地变量中先找,如果没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则不再继续。

如果找到最后也没找到需要的变量,则解释器返回undefined。

  然后再来看看js的内存回收机制。

一般来说,一个函数在执行开始的时候,会给其中定义的变量划分内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了。

对应的内存空间也就被回收了。下次再执行此函数的时候,所有的变量又回到最初的状态,重新赋值使用。但是

如果这个函数内部又嵌套了另一个函数,而这个函数是有可能在外部被调用到的。并且这个内部函数又使用了外部函数的某些变量的话

  这种内存回收机制就会出现问题。

如果在外部函数返回后,又直接调用了内部函数,那么内部函数就无法读取到他所需要的外部函数中变量的值了。

所以js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一起保存起来。

也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包。

而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收。也就是说,有了闭包,嵌套的函数结构才可以运作,这也是符合我们的预期的。

/**
 * Created by XBY on 2015/5/16. *模块化代码
 */
var a = (function(){
    var x = 1; //x是局部的变量
    function bb(){  //私有的方法
        x++;
        alert(x);
    }
    function cc(){  //私有的方法
        x = x + 2;
        alert(x);
    }
    return {
        b : bb,
        c : cc
    }
})();

a.b(); //2
a.c(); //4

闭包的好处:

    1.希望一个变量长期驻扎在内存中;    2.避免全局变量的污染;    3.私有成员的存在闭包的用法:    1.模块化代码;    2.在循环中直接找到对应元素的索引。

没有利用闭包时:
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>闭包</title>
    <script src="bibao.js"></script>
</head>
<body>
    <ul>
        <li>我是零</li>
        <li>我是一</li>
        <li>我是二</li>
    </ul>
</body>
</html>
window.onload = function(){
    var aLi = document.getElementsByTagName("li");
    for(var i = 0; i < aLi.length;i++){
        aLi[i].onclick = function() {
            alert(i);  //3 3 3
        };
    }
}

利用了闭包时:

window.onload = function(){
    var aLi = document.getElementsByTagName("li");
    for(var i = 0; i < aLi.length;i++){

        (function(i){
            aLi[i].onclick = function() {
                alert(i); //0 1 2
            };

        })(i)
    }
}

或者(另一种方式):

window.onload = function(){
    var aLi = document.getElementsByTagName("li");
    for(var i = 0; i < aLi.length;i++){

            aLi[i].onclick = (function(i){
                return function(){
                    alert(i); // 0 1 2
                }
            })(i);

    }
}

使用闭包时需要注意的问题:

  IE会出现内存泄露:

window.onload = function(){
    var oDiv = document.getElementById("div");
    oDiv.onclick = function () {
        alert(oDiv.id);
    }
}

元素内外部相互引用,就会出现。

解决办法1:

window.onload = function(){
    var oDiv = document.getElementById("div");
    oDiv.onclick = function () {
        alert(oDiv.id);
    }
    window.onunload = function () {
        oDiv.onclick = null;
    }
}

解决办法2:

window.onload = function(){
    var oDiv = document.getElementById("div");
    var id  = oDiv.id;
    oDiv.onclick = function () {
        alert(oDiv.id);
    }
    oDiv = null;
}
 

  

时间: 2024-11-05 14:25:57

JS之闭包的相关文章

关于js中闭包的理解

1.以前很不理解js中闭包的概念及使用,下面来看一下 function foo() { var a = 123; var b = 456; return function () { return a; } } var fn = foo(); 上面的代码只能访问 a和b,但是不能修改,这是js中闭包的技术之一 function foo() { var a = 123; var b = 456; return { get_a: function () { return a; }, set_a: fu

JS基础——闭包

有关JS中闭包的理解和使用. 一.简介 子函数可以使用父函数中的局部变量,这种行为就叫做闭包.通常指,有权访问另一个函数作用域中的变量的函数.创建时,通常在一个函数中创建另一个函数,通过另一个函数访问这个函数的局部变量. function box() { var user = 'Lee'; return function () { //通过匿名函数返回 box()局部变量 return user; }; } alert(box()()); 这里通过一个匿名函数来访问父函数中的user变量,并且返

js:深入闭包(作用域)

/** * 闭包的作用域 */ fn1(); //fn1 能够执行,不会报错,对于通过function func_name()这种写法来定义的函数,永远都会被最先初始化. function fn1(){ console.log("fn1"); } fn2(); //报错:fn2 is not a function /** *使用如下方式定义函数,不会被先执行,如果在定义之前调用,报错. *这种函数的定义方式是先在内存中创建一块区域,之后通过一个fn2的变量指向这块区域, *这块区域的函

JS高级——闭包

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascrip

js:深入闭包(作用域:下)

函数功能:该函数将一个字符串转为字形下标的数组.此函数可用来确定一种字体里是否存在某个字形 控制台下代码: #include "stdafx.h" #include <windows.h> #include"stdio.h" void main() { char ch[] = {'0'}; WORD chnl[20] = {0}; HDC hdc; hdc = GetWindowDC(0); int n = GetGlyphIndicesA(hdc,ch

[Js]JavaScript闭包和范围的快速测试

1. if (!("a" in window)) { var a = 1; } alert(a); [分析]代码含义:如果window不包含属性a,就声明一个变量a并赋值为1 ①Js引擎会先扫描所有的变量声明 ②所有的全局变量都是window的属性 ③变量声明和赋值一起用时,Js引擎会自动将它分成两部分:变量声明提前,变量赋值没有(不将赋值提前是因为他有可能影响代码执行出不可预期的结果) 所以代码执行顺序等价于 var a; if(!("a" in window))

js的闭包概念

一.变量的作用域要懂得闭包,起首必须懂得Javascript特别的变量作用域.变量的作用域无非就是两种:全局变量和局部变量.Javascript说话的特别之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999另一方面,在函数外部天然无法读取函数内的局部变量.Js代码 function f1(){ var n=999; } alert(n); // error这里有一个处所须要重视,函数内部声明变量

对js中闭包,作用域,原型的理解

前几天,和朋友聊天,聊到一些js的基础的时候,有一种‘好像知道,好像又不不知道怎么讲的感觉’...于是捡起书,自己理一理,欢迎拍砖. 闭包 理解闭包首先要理解,js垃圾回收机制,也就是当一个函数被执行完后,其作用域会被收回,如果形成了闭包,执行完后其作用域就不会被收回. 如果某个函数被他的父函数之外的一个变量引用,就会形成闭包 闭包的作用,就是保存自己私有的变量,通过提供的接口(方法)给外部使用,但外部不能直接访问该变量. 例子(使用闭包): var test=(function(){ var

从面试题谈谈js的闭包,原型

最近群里有小伙伴分享了两道面试题,这里我谈谈自己的理解,废话不多说,上第一题: var n = 10; var obj = { n:20, fn:(function(){ this.n += 2; n *= 3; return function(){ this.n *= 2; n += 1; console.log(n) } })(n) } var fn = obj.fn; fn(); obj.fn() console.log(n,obj.n) 这个题目中,定义的obj对象的fn属性是个自执行的