关于javascript闭包的一点疑问

闭包存储局部变量的机理是什么?它如何存储的?比如如下一个闭包

 function test(){
     var num = 10;
     return function(){
        num++;
        return num;
    };
 };
 var n = test();
 alert(n());    //返回11
 alert(n());    //返回12,实现了累加
 alert(n());    //继续累加

第二次alert(n())通过闭包实现了累加,但是这个局部变量num是如何存储在内存里的,以至于可以持续调用?机理是什么?局部变量不是当函数调用完后就销毁了吗

7个回答

test函数的内部函数被赋予n这个全局变量,因为n内部含有test函数的局部变量num,所以test函数的num局部变量不会被释放。执行一次n,num就会在原来的基础上加1

yishuixs
yishuixs 回复danielinbiti: 结合所有指导,前前后后思考了半小时终于明白了,谢谢!感觉还是你说的最透彻
接近 5 年之前 回复
danielinbiti
danielinbiti 回复yishuixs:是这样吗?function test(){ var num = 10; num++; return num; } 那是局部变量,没有引用的话,内部函数执行完就释放了。这里讲的是一个函数使用另一个函数域内的变量,如果是自己域内,这个函数执行完就释放了。
接近 5 年之前 回复
yishuixs
yishuixs 还是不明白,如果把test函数的内部匿名函数换掉,变成num++; return num;,无论alert(n)多少次都无法显示累加,照您的说法,局部变量num始终都在n里面,就应该实现累加,但是无法实现
接近 5 年之前 回复

只要变量被其他地方引用到,是不是被释放的,你返回了匿名函数,函数引用到num变量,只有n存储的匿名函数句柄被销毁才会释放

yishuixs
yishuixs 谢谢,我最终明白啦!
接近 5 年之前 回复

num是属于test的,不是属于匿名函数的,它会被解释器传给匿名函数,但是它的生命周期是和test一样的。

alert(test()());
这样每次都是11了。

yishuixs
yishuixs 回复caozhy: 是啊,嘿嘿,我是个初学者,问问题比较简单,多谢您的耐心帮助了!
接近 5 年之前 回复
caozhy
每个人都有一个梦才不会孤单的说话就有天堂 回复yishuixs: 没事。你是不是之前问过js原型的那位?
接近 5 年之前 回复
yishuixs
yishuixs 谢谢,您的这个alert(test()())从另一方面验证了闭包局部变量存在在内存中,非常感谢,可是只能采纳一个人的意见,不好意思啊
接近 5 年之前 回复

你可以理解num为n的一个成员了,n存在,所以num就一直存在,没有被释放

oyljerry
oyljerry 回复yishuixs: 你可以对非采纳的答案,而有帮助的点赞。就是那个小手。
接近 5 年之前 回复
yishuixs
yishuixs 谢谢,言简意赅,的确是这么个意思,可惜只能采纳一个大神的意见了
接近 5 年之前 回复

javascript本身就是一门编译解释语言,而且是在浏览器上运行,属于二次解释语言,不能直接翻译成
图片说明
本身就是先执行一个函数,返回结果,然后被上层函数再次返回结果到外面。
其实一开始执行的函数就是缺省函数,因为浏览器不必再分配一个方法名给它了,就是一块解释文本,告诉浏览器直接按缺省函数规定干好活就可以了。

给你一个简单纯js代码,这个是基本的函数调用,也是最基础的语法了。
function DeleteRouteTable(divId, riF, nameF, msgF){
this.riField = riF;
this.nameField = nameF;
this.msgField = msgF;

    var div = document.getElementById(divId);

    this.table = document.createElement("TABLE");
    div.appendChild(this.table);
    this.table.width = "100%";
    this.table.cellSpacing = 0;
    this.table.border = 1;

    this.tbody = document.createElement("TBODY");
    this.table.appendChild(this.tbody);

    this.arrayRI = new Array();
}

DeleteRouteTable.prototype.setValue = function(array){
    while(this.table.rows.length>0){
        this.table.deleteRow(0);
    }

    for(var i=0;i<array.length;i++){
        var item = array[i];
        this.arrayRI.push(item[this.riField]);

        var tr = document.createElement("TR");
        this.tbody.appendChild(tr);

        var tdRi = this.createTD(item[this.riField], 100, 2, "black");
        tr.appendChild(tdRi);
        var tdName = this.createTD(item[this.nameField], 100, 2, "black");
        tr.appendChild(tdName);
        var tdMsg = this.createTD(item[this.msgField], -1, 2, "red");
        tr.appendChild(tdMsg);
    }
};

DeleteRouteTable.prototype.createTD = function(value, width, fontSize, fontColor){
    var td = document.createElement("TD");
    if(width!=-1){
        td.width = width;
    }       

    var font = document.createElement("FONT");
    td.appendChild(font);

    font.size = fontSize;
    font.color = fontColor;
    font.innerText = value;

    return td;
};
yishuixs
yishuixs 谢谢啦!
接近 5 年之前 回复

闭包里引用了外部的变量,那这个变量就会成为闭包函数作用域的一部分,闭包不回收变量也就不会被回收,因此闭包很多可能造成内存泄露。
你这个例子,如果把里面的闭包函数换成num++,根据常识也应该知道每次调用test函数时都是一次全新的调用,每次调用输出的都是一样的值。
因为num是test函数内部的一个局部变量,每次调用时都会被重新定义,重新赋值,使用完然后销毁。如果加上闭包函数,在里面调用num++,
上面已经说了,num没有被销毁,加一次是1,再加一次自然就变成了2,如此累加。

yishuixs
yishuixs 谢谢,你说的很明白,可惜只能采纳一个
接近 5 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问