【问题标题】:JS Variable ScopeJS 变量范围
【发布时间】:2009-03-23 19:49:03
【问题描述】:

JS 中的变量范围让我很困惑。在下面的代码中,如果我使用setClient 公共方法设置clientID,然后我可以使用getClient 方法从track 方法内部访问该值。但是,我不能以这种方式(或任何其他私有成员)访问私有成员“版本”的值。我曾假设 var _this = this 会创建某种闭包,允许访问 Container 函数的范围。

现在我很困惑。我意识到这可能很简单,所以我想我会在这里问。到底哪里抓错了大棒?

function Container()
{
    // private members
    var version = '0.1';
    var CID = false;
    var _this = this;
    
    // public members
    this.getVersion = function() { return _this.version; }
    this.getClient = function() { return _this.CID; }
    this.setClient = function(CID) { _this.CID = CID; }
    
    // private methods
    this.getQS = function() { return _this.version; }
    
    // public methods
    this.track = function()
    {
        if (_this.CID)
        {
            var date = new Date();
            
            data = 
            {
                cid: _this.getClient(),
                sw: screen.width ? screen.width : false,
                sh: screen.height ? screen.height : false,
                d: date.getTime()
            }
            
            qs = '';
            
            for (p in data) { qs += p+'~'+data[p]+'-'; }
            
            var elHd = document.getElementsByTagName("head")[0];         
            var elScr = document.createElement('script');

            elScr.type = 'text/javascript';
            elScr.src = 'http://example.org/'+qs+
                            'version-'+_this.getVersion();
            
            elHd.appendChild(elScr);
        }
        else
        {
            alert('no client ID');
        }
    }
}

【问题讨论】:

    标签: javascript scope


    【解决方案1】:

    稍微清理一下你的 Container 构造函数。 version 和 CID 变量是私有的,并且在 Container 构造函数范围内,因此您不需要 this 范围引用,它根本不起作用。这。公共可访问的属性和方法需要引用,并且在您在构造函数之外定义原型时非常有用,如第二个代码块所示。

    function Container() {
      var version = "0.1", CID = false;
    
      this.getVersion = function()      { return version };
      this.getClient  = function()      { return CID     };
      this.setClient  = function(value) { CID = value    };
    
      this.track = function() {
        if (CID) {
          var qs = "", data = {
            cid: this.getClient(),
            sw: screen.width ? screen.width: false,
            sh: screen.height ? screen.height: false,
            d: (new Date).getTime()
          };
          for (var p in data) qs += p +"~"+ data[p] +"-";
          var js = document.createElement("script");
          js.type = "text/javascript";
          js.src = "http://example.org/"+ qs +"version-"+ this.getVersion();
          document.getElementsByTagName("head")[0].appendChild(js);
        } else {
          alert("No Client ID");
        }
      };
    };
    

    这个。当您在构造函数之后添加/覆盖原型时,引用变得至关重要。

    function Container2() { }
    Container2.prototype = {
      CID: null,
      version: "0.1",
      track: function() {
        alert(this.version);
      }
    }
    

    【讨论】:

    • 非常感谢。我显然是在错误的印象下工作,我需要创建某种闭包或反向引用。我认为这对我来说又回到了 o'reilly 书籍
    • 没问题,你需要花点时间才能理解它。正如另一篇文章所述,crockford.com/javascript/private.html 是一本很好的读物,有助于巩固其工作原理。
    【解决方案2】:

    我不确定我是否理解您在哪里感到困惑(或者为什么您会按照自己的方式做事,所以我可能会很困惑)。如果你这样做会发生什么:

    this.getVersion = function() { return version; }
    

    【讨论】:

      【解决方案3】:

      变量version不是Container类的成员字段。它是一个局部变量,仅在 Container 构造函数期间存在。您需要这样创建它(就像您使用方法一样):

      this.version = "0.1";
      

      您应该对 CID 字段执行相同的操作。更好的是,将它们添加到类的原型对象中。

      【讨论】:

        【解决方案4】:

        简单的答案是使用

        this.getVersion = function() { return version; }
        

        因为 JavaScript 函数是闭包,所以即使在函数返回后也可以访问上述函数中对局部变量 version 的引用。试图访问_this.version 是试图读取_this 对象的version 成员。由于您从未为_this 分配版本 成员,因此它将返回值undefined

        在 JavaScript 中,您将只能访问显式添加到您正在使用的对象、或添加到该对象的原型或原型的原型等的成员。

        有关在 JavaScript 中使用私有成员的更多信息,请参阅 Douglas Crockford 的一篇精彩文章:Private Members in JavaScript

        【讨论】:

          猜你喜欢
          • 2012-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多