Javascript CoffeeScript私有类实例变量

Javascript CoffeeScript私有类实例变量,javascript,coffeescript,Javascript,Coffeescript,我有以下咖啡脚本代码: class Person secret = 0 constructor: (@name, @age, @alive) -> inc: -> secret++ var Person; Person = (function() { var secret; secret = 0; function Person(name, age, alive) { this.name = name; t

我有以下咖啡脚本代码:

class Person
  secret = 0
  constructor: (@name, @age, @alive) ->
  inc: -> secret++
var Person;
Person = (function() {   
    var secret;
    secret = 0;

    function Person(name, age, alive) {
        this.name = name;
        this.age = age;
        this.alive = alive;
    }
    Person.prototype.inc = function() {
        return secret++;
    };
    return Person;
})();
它编译为以下JavaScript代码:

class Person
  secret = 0
  constructor: (@name, @age, @alive) ->
  inc: -> secret++
var Person;
Person = (function() {   
    var secret;
    secret = 0;

    function Person(name, age, alive) {
        this.name = name;
        this.age = age;
        this.alive = alive;
    }
    Person.prototype.inc = function() {
        return secret++;
    };
    return Person;
})();

当前,
secret
Person
的所有实例之间共享。有没有办法在CoffeeScript中使
secret
成为私有实例变量?

我想出了一个解决方案。我不确定这是否是最好的解决方案,所以我仍然对其他人持开放态度

咖啡脚本:

class Person
  constructor: (@name, @age, @alive) ->
    secret = 0
    @inc = -> secret++;
JavaScript:

var Person;
Person = (function() {
    function Person(name, age, alive) {
        var secret;
        this.name = name;
        this.age = age;
        this.alive = alive;
        secret = 0;
        this.inc = function() {
            return secret++;
        };
    }
    return Person;
})();

请参阅,您只能通过closured getter函数使其工作

CoffeeScript中没有私有成员的概念,因为JavaScript中没有私有成员的概念。有一些局部变量,您可以很好地利用它们,但是,虽然您的解决方案确实对
构造函数
函数之外的任何对象隐藏了
secret
变量,但它还引入了在类
Person
的每个实例化上重新声明
inc
方法的开销

JavaScript社区中常见的一个错误是试图在其上投射其他语言的不存在的特性,模仿私有成员的尝试显然就是一个例子。它没有这样的概念,深入思考,您会得出结论,对于一个极其松散的动态环境来说,JavaScript是不自然的

因此,不要将时间和应用程序的性能浪费在实现不存在的构造上。只需专注于解决你的问题,而不是缺乏语言特征的问题

现在扪心自问:让所有成员公开有什么害处

考虑到所说的一切,最终的解决办法是:

class Person
  constructor: (@name, @age, @alive) ->
    @secret = 0
  inc: -> @secret++

虽然不会真正隐藏它们,但惯例是在“private”成员前面加下划线。这里的想法是,使用它的人应该假设这些成员是实现细节,建议不要使用它们。

这里有一个技巧,可以在大多数情况下满足需求:

msg = "Result-----------\n"

class Dog

  #public variable
  dogName: null

  #private variables
  _private = []

  constructor: (@dogName, surname) ->
    _private[@dogName] = {surname: surname}

  #public method (note the => instead of ->)
  walk: =>
    msg += "#{@dogName} is walking\n"
    sayHello(@dogName, _private[@dogName].surname)

  #private method
  sayHello = (dog, surname) ->
    msg += "Hi! says #{dog}. Call me #{surname}\n"

window.ralph = new Dog("Ralph", "Ralphie")
window.peter = new Dog("Peter", "Pitty")
window.rex = new Dog("Rex", "Roxie")
rex.walk()
peter.walk()
ralph.walk()

alert msg
但您必须记住:_private随着每个新实例(它是一个共享数组)而增长,并且您的密钥(在本例中为@dogName)必须是唯一的accross实例


您实际上是在通过声明成员私有来隐藏实现细节。通过使用继承,您可以隐藏实现细节,方法是声明一个“抽象”类(据我所知,它实际上不存在于CoffeeScript中)并用您自己的实现对其进行扩展。像这样:

  class bottle
        drink: ->
        empty: ->

  class bottle_impl extends bottle
        drink: -> 
             if count > 0
                 alert "drinking for the " + _count + " time."
       empty: -> @_count = 0
       _count: 4

现在,每个返回瓶子的函数实际上都应该返回一个瓶子impl(同时在注释中对用户隐藏该事实)。不幸的是,当你伸出一个瓶子时,你不会伸出一个可能不是你想要的瓶子。

hmmmmm不完全正确。如果你想要私人会员,你不能真正获得私人会员,但如果你真的想要,你可以拥有私人会员

class person 
  constructor:->
    name='my secret name'
    @getName=->
      name
    null


boy= new person()


alert boy.name  #it's now private spits out undefined
alert boy.getName()
它们必须在构造的范围内,这样才能工作。 这是你能得到的最接近隐私的地方

问题私人memebers将减慢应用程序的速度。 它需要在每次实例化时运行,而不能仅从原型中获取。
玩得开心

你可以这样做

class person
  secret = 
    name : "my secret name"
  constructor:->
    x = 123
  getName: ->
    secret.name

user = new person()

console.log user.name # undefined
console.log user.getName() # "my secret name"

它确实是私有的。缺点是您必须使用变量
secret
或您选择的任何引用私有变量的方法。

尽管Javascript没有可见性概念,但您可以使用作用域来模拟它

class Test
  privateVariable = null

  privateFunction = (obj)->
    privateVariable = obj
  constructor: (a) ->
    privateVariable = a

  publicFunction: ->
    return privateVariable

  setPrivateVariable: (obj) ->
    privateFunction(obj)

test = new Test("Test")
console.log(test.privateVariable)   # undefined
console.log(test.publicFunction())  # Test
test.setPrivateVariable("Changed!") #
console.log(test.publicFunction())  # Changed!

这是一个很有争议的话题。我个人喜欢隐藏一些属性和方法,以使类的契约更清晰。

通常使用命名约定来表示“私有”变量。与Python类似,这通常由
\u var
表示,即在本例中为
\u secret
。@AaronDufour您建议的是模仿私有成员功能的另一种尝试。我的观点是,JavaScript开发人员必须将他的思想从这样一个概念中解放出来,因为最终所有类似这样的解决方案都会成为一个过度复杂的解决方案,没有任何实际用途;它只是让我们更清楚地知道该类的用途。调用变量
secret
可能就足够了,但下划线前缀是一种更通用的解决方案。如果该类暴露于第三方,这尤其有用。@NikitaVolkov原则上你是对的;我曾经做过很多“反谷物”的事情;它让你*更好地理解语言,*对软件没有什么好处,*知道时间可以花得更好。-除此之外,JS在闭包方面非常棒,下面是KPthunder的解决方案,在这个方向上:闭包中的变量可以是私有的,也可以是特定于实例的。javascript绝对有私有变量的概念。它们通常是用闭包实现的,但不将函数中的变量赋值给
this
在默认情况下使其私有。仅仅因为js隐含了变量的隐私(即没有
public
/
private
关键字),并不意味着它不支持或鼓励它