【问题标题】:Private variable definition inside JavaScript objectJavaScript 对象内的私有变量定义
【发布时间】:2014-05-01 21:49:54
【问题描述】:

我正在学习使用原型属性在 JavaScript 上定义“类类”函数。 当我像这样定义 People 类时,一切都很好:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;

    this.fullName = function(){
        console.log(full_name);
        return this;
    };

    // private
    var self = this;
    var full_name = function(){
        return self.firstName + ' ' + self.lastName;
    }();
};

var person = new People('John', 'Smith');
person.fullName();  // => "John Smith"

但是,当我将 fullName 方法移到初始定义之外时,如下所示:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;

    // private
    var self = this;
    var full_name = function(){
        return self.firstName + ' ' + self.lastName;
    }();
};

People.prototype.fullName = function(){
    console.log(full_name);
    return this;
};

var person = new People('John', 'Smith');
person.fullName();  // => "ReferenceError: full_name is not defined"

我遇到了一个错误。我不明白为什么...??

【问题讨论】:

  • 没有类或私有,它是函数和范围,但一些聪明人决定称它为“类”和“私有/公共”(可能是 Crockford,让我们责怪他)。
  • 不清楚你想要什么。如果您希望“full_name”是一个作为原型属性可见的函数,那么它没有理由成为“私有”。
  • @adeneo 你是对的......这就是为什么我称它为“类”lol
  • @Bergi 解释得很好,但这不是我在这里问的。

标签: javascript jquery class constructor prototype


【解决方案1】:

这里:

var full_name = function(){
    return self.firstName + ' ' + self.lastName;
}();

您将变量“full_name”设置为调用该匿名函数的结果。但是,它只是在该构造函数的上下文中声明的变量,所以这并不重要;构造函数之外的任何东西都不能访问它。

因此,在该原型函数中,您会收到一个错误,因为“full_name”实际上没有定义。如果你想要原型上的全名函数,只需在此处声明即可:

People.prototype.fullName = function() {
  return this.firstName + " " + this.lastName;
};

如果您想要一个只能由构造函数中的代码访问的“私有”函数,那么您可以这样做:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;

    // private
    var self = this;
    function fullName(){
        return self.firstName + ' ' + self.lastName;
    }

    this.addressMe = function(msg) {
        return fullName() + ": " + msg;
    };
};

那么你可以这样做:

var bob = new People("Bob", "Scum");
alert( bob.addressMe("stand and deliver") ); // "Bob Scum: stand and deliver"

【讨论】:

  • 您对私有共享成员使用了错误的模式。您使用的模式是针对私有实例特定的(每个实例都是唯一的)。由于 full_name 是一个函数并且可以共享,因此您不必放弃原型来实现它。
  • @HMR 我同意;我可能不会编写这样的代码。原始问题的意图不是很清楚。
【解决方案2】:

Pointy 对私有 shared 成员使用了错误的模式,该模式适用于私有 instance specific 成员,并且每个实例都有自己的 addressMe 函数。

私有共享成员的模式可以将原型包装在 IIFE 中:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;
};

(function(){
  // private shared member
  var full_name = function(){
      return this.firstName + ' ' + this.lastName;
  };
  //privileged member that has access to private shared
  //  fullName is a closure and full_name is available
  //  in the colosure scope created for this function
  People.prototype.fullName = function(){
    //calling private member, make sure you set
    //  the invoking object (this) by using
    //  Function.prototype.call
    console.log(full_name.call(this));
    return this;
  };
}());

var person = new People('John', 'Smith');
person.fullName();

您不能将此模式用于特定于实例的私有成员,但函数 full_name 不是特定于实例的。

可以在here 找到受保护的模式以及有关原型和构造函数的更多信息。

【讨论】:

  • 谢谢你的回答,但更多的是你在它末尾附加的链接。那里有很好的解释!!!你也分享你自己的博客吗?
  • @Lior 谢谢,没有博客。认为 JavaScript 原型是编程中最容易被误解的东西之一,并在自己试图弄清楚它时写了它。 SO 非常适合,因为我希望 cmets 能指出错误或提出改进建议。
猜你喜欢
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
  • 2021-07-08
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
相关资源
最近更新 更多