CoffeeScript私有类实例变量

CoffeeScript Private Class Instance Variables

本文关键字:实例 变量 CoffeeScript      更新时间:2023-09-26

我有以下CoffeeScript代码:

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

它编译成以下JavaScript代码:

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;
})();

当前CCD_ 1在CCD_ 2的所有实例之间共享。有没有办法让secret成为CoffeeScript中的私有实例变量?

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

CoffeeScript:

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;
})();

CoffeeScript中没有私有成员的概念,因为JavaScript中没有。有一些局部变量,您可以在自己的解决方案中很好地利用这些变量,但尽管您的解决方案确实对constructor函数之外的任何东西隐藏了secret变量,但它也引入了在类Person的每次实例化中重新声明inc方法的开销。

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

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

现在问问自己:让所有成员都公开是什么伤害?

考虑到所说的一切,最终的解决方案将是:

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

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

参考这个线程,您只能通过封闭的getter函数

使其工作

以下是一个在大多数情况下都能满足要求的技巧:

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)必须是跨实例的唯一密钥。

试试

您实际上是在通过声明成员私有来隐藏实现细节。通过使用继承,您可以隐藏实现细节,通过声明一个"抽象"类(据我所知,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

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

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

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()

它们需要在构造的范围内才能工作。这是一个非常私人的地方。

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

你可以这样做。。。

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!

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