JavaScript对象没有被销毁?

JavaScript对象没有被销毁?,javascript,jquery,html,garbage-collection,Javascript,Jquery,Html,Garbage Collection,谈到JavaScript,我是个新手,但最近我遇到了一个问题,我可以用一个小例子来重现这个问题: function TimerTest(panelId) { this.PanelID = panelId; } TimerTest.prototype.Start = function() { var self = this; $(document.getElementById(this.PanelID)).everyTime("1s", "Test", function

谈到JavaScript,我是个新手,但最近我遇到了一个问题,我可以用一个小例子来重现这个问题:

function TimerTest(panelId)
{
    this.PanelID = panelId;
}

TimerTest.prototype.Start = function()
{
    var self = this;

    $(document.getElementById(this.PanelID)).everyTime("1s", "Test", function(){
        self.Print();
    });
}

TimerTest.prototype.Print = function()
{
    $("#debug").append("<div>triggered...</div>");
}

function Remove()
{
    $("#main").empty();
    $("#main").html("I'm done!");
}

$(document).ready(function(){
    var timer = new TimerTest("timerpanel");
    timer.Start();
});
函数TimerTest(panelId)
{
this.PanelID=PanelID;
}
TimerTest.prototype.Start=函数()
{
var self=这个;
$(document.getElementById(this.PanelID))。每次(“1s”,“Test”,function(){
self.Print();
});
}
TimerTest.prototype.Print=函数()
{
$(“#调试”).append(“触发…”);
}
函数删除()
{
$(“#main”).empty();
$(“#main”).html(“我完成了!”);
}
$(文档).ready(函数(){
var定时器=新定时器测试(“定时器面板”);
timer.Start();
});

调用Remove()后,对象似乎仍然存在并打印“已触发…”:(

我使用HTML5的历史记录功能通过AJAX加载内容。我基本上体验到的是,我有一个带有标记的嵌入式谷歌地图和一个计时器,每隔一段时间更新这些标记。当导航离开该页面时,我仍然可以看到FireBug AJAX调用来更新标记。这对我来说意味着对象没有被破坏尽管它的面板已从DOM中删除,但JQuery在empty()上的文档称它删除了所有DOM元素及其数据


我有点困惑。我知道我可以在导航离开之前调用对象上的“stopTime()”,但这不是我的问题。示例中的计时器就在那里,因此我可以看到TimerTest对象仍然存在(即我的Google地图仍然存在!)

只有在不存在对对象的引用时,垃圾收集器才会回收对象

jQuery的
empty()
方法将从DOM中删除该元素,并将删除jQuery存储的关于通过该方法添加的元素的所有数据以及事件处理程序。

Chrome试图运行你的小提琴时,抱怨jQuery.offput.ca,称其为“已知分发恶意软件”的站点。如果我去该jQuery插件的演示,我会得到同样的警告。因此,我无法使用实际的代码。在您更新时,我可以使用您的实际代码,因此请参阅此答案的最后部分,以获得使用原始代码的答案。不过,我将保留非计时器插件答案

元素可能保留在内存中,也可能不保留在内存中,这完全取决于计时器插件的工作方式。不过,重要的是,无论元素是否在内存中,都不会停止计时器。您需要代码来完成此操作

我从未使用过该计时器插件,但它可能有一些方法告诉计时器停止,可能是通过调用您已将计时器附加到的元素的jQuery包装器。因此,在
Remove
函数中,您需要一种方法来识别带有计时器的元素,以便可以停止它们

下面是一个在没有计时器插件的情况下执行此操作的示例,以演示这些概念。下面是我如何执行此操作的:

  • 当我创建
    setInterval
    计时器时,我记得名为
    data timer handle
    的属性上的计时器句柄。您可能需要,也可能不需要,但您需要在元素上放置某种标记,以便告诉计时器插件停止

  • Remove
    中,在清除
    #main
    之前,我使用
    数据计时器句柄
    属性找到它的所有子项,并清除间隔计时器

  • |

    HTML:

    (我还使用jQuery来查找元素,而不是
    document.getElementById
    。您需要在函数表达式的末尾加上分号。)

    并更改
    Remove
    以停止该类所有元素上的计时器:

    function Remove()
    {
        var main = $("#main");
        main.find(".hastimer").stopTime();
        main.html("I'm done!");
    }
    
    (在调用
    html
    之前,无需调用
    empty
    html
    调用
    empty


    Kill it with fire!=D'if(TimerTest)delete TimerTest;'这就是当今所谓的暴力编程…=DYour JSFIDLE包含恶意软件,Google Chrome如是说。我认为“delete”实际上并没有删除任何内容,只是将变量设置为“null”?恶意软件?我很抱歉,但这只是上面的代码。也许它报告它为恶意软件是因为重复的计时器事件?@benqus:但这不会起作用。a)
    delete
    用于属性,b)timeout函数仍然包含对itI的引用,但我不会删除“#main”,只删除它的内容(“timerpanel”)。我知道“this.Panel”包含对面板的引用,但我也尝试过使用“this.PanelID”,然后在Start()中使用它,但它产生了相同的结果:(这是更新后的示例…我的第一个怀疑当然是我仍然持有这个.Panel的引用,但将其更改为仅持有ID似乎也不起作用。我已经将我的JSFIDLE更新为插件脚本的另一个URL(googlecode),所以希望Chrome不再抱怨:)不过,我对您的代码有一个问题:它确实停止了计时器,但我如何知道它实际上破坏了TimerTest对象?计时器只是我告诉您的一种方式。好吧,计时器本身没有对TimerTest对象的引用,那么为什么该对象仍然存在?您可以通过修改Print()打印“this.PanelID”来判断…@AlexK.:如果你“已经”更新了你的提琴,请更新你的问题以供参考,这样人们就不会浪费时间在旧的提琴上/因为旧的提琴而气馁。@AlexK.:我已经更新了答案以解决上面的问题(见结尾,休息下)@AlexK.:当您接受答案时,我更新了您更新的小提琴,以展示如何使用原始代码解决此问题。很高兴这有帮助!@AlexK.:是的,因为您已将对它的引用分配给全局变量
    timer
    。如果您将
    脚本
    元素中的代码更改为
    new TimerTest().Start();function TimerTest(panelId)
    {
        this.PanelID = panelId;
    }
    
    TimerTest.prototype.Start = function()
    {
        var self = this;
    
        // Start the timer
        var handle = setInterval(function() {
            self.Print();
        }, 1000);
    
        // Remember the handle on a data-timer-handle property
        // on the element.
        $(document.getElementById(this.PanelID)).attr("data-timer-handle", handle);
    }
    
    TimerTest.prototype.Print = function()
    {
        $("#debug").append("<div>triggered...</div>");
    }
    
    function Remove()
    {
        var main = $("#main");
        // Find any elements with timers on them, stop them
        main.find("[data-timer-handle]").each(function() {
            clearInterval($(this).attr("data-timer-handle"));
        });
        main.html("I'm done!");
    }
    
    $(document).ready(function(){
        var timer = new TimerTest("timerpanel");
        timer.Start();
        $("#removeButton").click(function() {
            Remove();
        });
    });
    
    TimerTest.prototype.Start = function()
    {
        var self = this;
    
        $("#" + this.PanelID)
            .addClass("hastimer")
            .everyTime("1s", "Test", function(){
                self.Print();
        });
    };
    
    function Remove()
    {
        var main = $("#main");
        main.find(".hastimer").stopTime();
        main.html("I'm done!");
    }