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

jer*_*son 5 javascript jquery closures

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

基本上,我包装了两个操纵CSContent对象内部DOM的方法.我创建对象的实例,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();
});
Run Code Online (Sandbox Code Playgroud)

Mar*_*pel 5

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

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


Fel*_*ing 2

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

$('#edit-cscontent-cs-content-twitter').change(content.toggleTweetTextarea);
Run Code Online (Sandbox Code Playgroud)

工作?

好吧,您不传递content事件处理程序,而是传递content.toggleTweetTextarea. content并且这个引用在不存在之后仍然存在。没有什么特别的。您刚刚将一个对象(函数)分配给另一个变量。只要至少存在一个对对象的引用,该对象就不会被垃圾收集。

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

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