为什么这个Javascript对象在$(document).ready之后不会超出范围?

时间:2010-08-04 19:42:09

标签: javascript jquery closures

我有一些工作Javascript来操纵一些DOM元素。问题是,我不明白为什么它起作用,这从来都不是一件好事。我正在尝试更多地了解面向对象的javascript和javascript最佳实践,因此组织可能看起来有点奇怪。

基本上,我将两个操作DOM的方法包装在CSContent对象中。我在content中创建了该对象的实例$(document).ready,并将一些事件绑定到content中的函数。但是,我对在$(document).ready退出后如何仍然可以调用这些函数感到困惑。这是否意味着content已超出范围,其功能不可用?无论如何,这是代码:

function CSContent() {
    var tweetTextArea = document.getElementById('cscontent-tweet'),
        tweetTextElement = document.getElementById('edit-cscontent-cs-content-tweet'),
        charCountElement = document.getElementById('cscontent-tweet-charactercount');

    this.toggleTweetTextarea = function () {
      $(tweetTextArea).slideToggle();
    };

    this.updateTweetCharacterCount = function () {
        var numOfCharsLeft = 140 - tweetTextElement.value.length;
        if (numOfCharsLeft < 0) {
            $(charCountElement).addClass('cscontent-negative-chars-left');
        }
        else {
            $(charCountElement).removeClass('cscontent-negative-chars-left');
        }
        charCountElement.innerHTML = '' + numOfCharsLeft + ' characters left.';
    };
}



$(document).ready(function () {
    var content = new CSContent();
    //If the twitter box starts out unchecked, then hide the text area
    if ($('#edit-cscontent-cs-content-twitter:checked').val() === undefined) {
        $('#cscontent-tweet').hide();
    }

    $('#edit-cscontent-cs-content-twitter').change(content.toggleTweetTextarea);
    //Seems wasteful, but we bind to keyup and keypress to fix some weird miscounting behavior when deleting characters.
    $('#edit-cscontent-cs-content-tweet').keypress(content.updateTweetCharacterCount);
    $('#edit-cscontent-cs-content-tweet').keyup(content.updateTweetCharacterCount);
    content.updateTweetCharacterCount();
});

3 个答案:

答案 0 :(得分:5)

这个,m'lord,被称为闭包:局部变量content将在$(document).ready退出后保留在内存中。这也是内存泄漏的已知原因。

简而言之,您将此函数绑定到DOM元素的事件侦听器,然后JavaScript垃圾收集器知道它应保持本地变量不变。除非事件被触发,否则不能直接调用它(在函数外部)。如果你真的想在之后调用该函数(例如,使用element.click()模拟点击),你可以“手动”执行此操作。

答案 1 :(得分:2)

我假设你想知道为什么事件处理程序喜欢

$('#edit-cscontent-cs-content-twitter').change(content.toggleTweetTextarea);

工作?

嗯,您不会将content作为事件处理程序传递,而是content.toggleTweetTextarea中包含的函数。在content不再存在之后,此引用仍然存在。没什么特别的。您刚刚将一个对象(该函数)分配给另一个变量。只要存在至少一个对象的引用,该对象就不会被垃圾回收。

现在您可能会问为什么这些功能仍然可以访问例如tweetTextArea?这确实是一个封闭。通过new CSContent()创建函数时,此函数的激活上下文将添加到内部函数CSContent.toggleTweetTextareaCSContent.updateTweetCharacterCount的范围链中。因此,即使您不再引用content,此函数的范围仍包含在其他函数的范围链中。

content完成后,您将无法再访问ready()中包含的对象,这确实超出了范围。

答案 2 :(得分:1)

今天我的大脑已经关闭了,但在这种情况下你不应该使用闭包吗?

$('#edit-cscontent-cs-content-twitter').change( 
    function(){ 
        content.toggleTweetTextarea(); 
    } 
);