Javascript CoffeeScript:对象初始值设定项中的 Getter/Setter

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11587231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:25:47  来源:igfitidea点击:

CoffeeScript: Getter/Setter in Object Initializers

javascriptoopcoffeescriptgetter-setterecmascript-5

提问by fridojet

ECMAScript allows us to define getters or setters as following:

ECMAScript 允许我们定义 getter 或 setter 如下:

[text/javascript]

[文本/javascript]

var object = {
  property: 7,
  get getable() { return this.property + 1; },
  set setable(x) { this.property = x / 2; }
};

I can work around if I'm using a class:

如果我正在使用一个类,我可以解决:

[text/coffeescript]

[文字/咖啡稿]

"use strict"

Function::trigger = (prop, getter, setter) ->
      Object.defineProperty @::,
              get: getter
              set: setter               

class Class
      property: ''

      @trigger 'getable', ->
               'x'

      member: 0

But what if I want to define trigger on the object directly- withoutusing defineProperty/ -ies. I want to do something like (it's not workingthat way):

但是如果我想直接对象上定义触发器怎么办-使用defineProperty/ -ies。我想做一些类似的事情(它不是那样工作的):

[text/x-pseudo-coffeescript]

[文本/x-伪咖啡脚本]

object =
  property: 'xhr'
  get getable: 'x'

It's working in JavaScript without any problems and I don't want my scripts to regress when I'm using CoffeeScript. Isn't there a way to do this as comfortable as in JavaScript/ECMAScript? Thanks.

它在 JavaScript 中运行没有任何问题,我不希望我的脚本在使用 CoffeeScript 时退化。难道没有一种方法可以像在 JavaScript/ECMAScript 中那样轻松做到这一点吗?谢谢。

回答by epidemian

No, not for now :(

不,暂时不:(

From the CoffeeScript FAQ:

来自CoffeeScript 常见问题解答

Q: Will you add feature X where feature X depends on a platform?

A: No, implementation-specific features are not allowed as a policy. Everything that you write in CoffeeScript should be supported and runnable on any current JavaScript implementation (in practice, this means the lowest common denominator is IE6). Thus, features such as the following will not be implemented: getters & setters, yield.

问:您会在功能 X 取决于平台的情况下添加功能 X 吗?

答:不可以,不允许将特定于实现的功能作为策略。您在 CoffeeScript 中编写的所有内容都应该在任何当前的 JavaScript 实现上都得到支持和运行(实际上,这意味着最小的公分母是 IE6)。因此,将不会实现以下功能:getter & setter、yield。

Some GitHub issues about getter & setter syntax: #64, #451, #1165(there is some nice discussion in the last one).

关于 getter 和 setter 语法的一些 GitHub 问题:#64#451#1165(最后一个有一些很好的讨论)。

I personally think that having getter & setter literal syntax would be a nice opt-in feature for CoffeeScript now that definePropertyis part of the ECMAScript standard. The need for getters & setters in JavaScript can be questionable, but you're not forced to use them just because they exist.

我个人认为拥有 getter 和 setter 文字语法将是 CoffeeScript 的一个不错的选择加入功能,现在它definePropertyECMAScript 标准的一部分。JavaScript 中对 getter 和 setter 的需求可能是有问题的,但您不会仅仅因为它们存在就被迫使用它们。



Anyway, as you noticed, it's not that hard to implement a convenient wrapper function that calls Object.definePropertyfor class declarations. I personally would use the approach suggested in here:

无论如何,正如您所注意到的,实现一个方便的调用Object.defineProperty类声明的包装函数并不难。我个人会使用这里建议的方法:

Function::property = (prop, desc) ->
  Object.defineProperty @prototype, prop, desc

class Person
  constructor: (@firstName, @lastName) ->
  @property 'fullName',
    get: -> "#{@firstName} #{@lastName}"
    set: (name) -> [@firstName, @lastName] = name.split ' '

p = new Person 'Robert', 'Paulson'
console.log p.fullName # Robert Paulson
p.fullName = 'Space Monkey'
console.log p.lastName # Monkey

Or, maybe create two different methods:

或者,也许创建两种不同的方法:

Function::getter = (prop, get) ->
  Object.defineProperty @prototype, prop, {get, configurable: yes}

Function::setter = (prop, set) ->
  Object.defineProperty @prototype, prop, {set, configurable: yes}

class Person
  constructor: (@firstName, @lastName) ->
  @getter 'fullName', -> "#{@firstName} #{@lastName}"
  @setter 'fullName', (name) -> [@firstName, @lastName] = name.split ' '

For plain objects you can just use Object.defineProperty(or Object.defineProperties;) ) on the object itself as Jason proposed. Maybe wrap that in a little function:

对于普通对象,您可以像Jason 建议的那样在对象本身上使用Object.defineProperty(或Object.defineProperties;)) 。也许将其包装在一个小函数中:

objectWithProperties = (obj) ->
  if obj.properties
    Object.defineProperties obj, obj.properties
    delete obj.properties
  obj

rectangle = objectWithProperties
  width: 4
  height: 3
  properties:
    area:
      get: -> @width * @height

console.log rectangle.area # 12
rectangle.width = 5
console.log rectangle.area # 15

回答by curran

Here's another approach for defining properties with getters and setters in CoffeeScript that maintains a relatively clean syntax without adding anything to the global Function prototype (which I'd rather not do):

这是在 CoffeeScript 中使用 getter 和 setter 定义属性的另一种方法,它保持相对干净的语法,而无需向全局函数原型添加任何内容(我宁愿不这样做):

class Person
  constructor: (@firstName, @lastName) ->
  Object.defineProperties @prototype,
    fullName:
      get: -> "#{@firstName} #{@lastName}"
      set: (name) -> [@firstName, @lastName] = name.split ' '

p = new Person 'Robert', 'Paulson'
console.log p.fullName # Robert Paulson
p.fullName = 'Space Monkey'
console.log p.lastName # Monkey

It works well with many properties. For example, here's a Rectangle class that is defined in terms of (x, y, width, height), but provides accessors for an alternative representation (x1, y1, x2, y2):

它适用于许多属性。例如,这里有一个 Rectangle 类,它是根据 (x, y, width, height) 定义的,但提供了用于替代表示 (x1, y1, x2, y2) 的访问器:

class Rectangle                                     
  constructor: (@x, @y, @w, @h) ->
  Object.defineProperties @prototype,
    x1:
      get: -> @x
      set: (@x) ->
    x2:
      get: -> @x + @w
      set: (x2) -> @w = x2 - @x
    y1:
      get: -> @y
      set: (@y) ->
    y2:
      get: -> @y + @h
      set: (y2) -> @w = y2 - @y

r = new Rectangle 5, 6, 10, 11
console.log r.x2 # 15

Here's the corresponding JavaScript code. Enjoy!

这是相应的 JavaScript 代码。享受!

回答by Jason L.

You can use Object.defineProperty on straight JSON objects as well.

您也可以在直接的 JSON 对象上使用 Object.defineProperty。

obj = {}
Object.defineProperty obj, 'foo',
    get: ->
        return 'bar'

The get/set notation does not work for various reasons in CoffeeScript. The biggest being that the compiler has not been built to account for get/set notation.

由于各种原因, get/set 符号在 CoffeeScript 中不起作用。最大的问题是编译器尚未构建以考虑 get/set 表示法。

Note that get/set is not supported by all browsers (specifically, IE). Also note that the new ECMA standards (ECMAScript5) mentions Object.defineProperty as the way to define properties with getters/setters.

请注意,并非所有浏览器(特别是 IE)都支持 get/set。另请注意,新的 ECMA 标准 (ECMAScript5) 提到 Object.defineProperty 作为使用 getter/setter 定义属性的方式。

回答by Micka?l Gauvin

Like @curran, I prefer not to modify Functionprototype. Here it is what I did in one of my projects?:

像@curran 一样,我不喜欢修改Function原型。这是我在我的一个项目中所做的?:

Define somewhere an utility function which for a given class returns 2 functions allowing you to easily add getters and setters on the prototype of the class:

在某处定义一个实用函数,它为给定的类返回 2 个函数,允许您轻松地在类的原型上添加 getter 和 setter:

gs = (obj) ->
  getter: (propName, getterFunction) ->
    Object.defineProperty obj.prototype, propName, 
      get: getterFunction
      configurable: true
      enumerable: true
  setter: (propName, setterFunction) ->
    Object.defineProperty obj.prototype, propName, 
      set: setterFunction
      configurable: true
      enumerable: true

gsstands for getter and setter.

GS代表埃特和小号埃特。

Then, you build and import the two functions configured for your class :

然后,您构建并导入为您的类配置的两个函数:

class Dog
  { getter, setter } = gs @

  constructor: (name, age) -> 
    @_name = name
    @_age = age

  getter 'name', -> @_name
  setter 'name', (name) -> 
    @_name = name
    return

  getter 'age', -> @_age
  setter 'age', (age) -> 
    @_age = age
    return

回答by M K

An alternative approach:

另一种方法:

get = (self, name, getter) ->
  Object.defineProperty self, name, {get: getter}

set = (self, name, setter) ->
  Object.defineProperty self, name, {set: setter}

prop = (self, name, {get, set}) ->
  Object.defineProperty self, name, {get: get, set: set}

class Demo 
  constructor: (val1, val2, val3) ->
    # getter only
    get @, 'val1', -> val1
    # setter only
    set @, 'val2', (val) -> val2 = val
    # getter and setter
    prop @, 'val3', 
      get: -> val3
      set: (val) -> val3 = val

回答by kwerle

Thanks to the others that have gone before. Very generally and simply:

感谢之前去过的其他人。非常普遍和简单:

attribute = (self, name, getterSetterHash) ->
  Object.defineProperty self, name, getterSetterHash

class MyClass
  constructor: () ->
    attribute @, 'foo',
      get: -> @_foo ||= 'Foo' # Set the default value
      set: (who) -> @_foo = "Foo #{who}"

    attribute @, 'bar',
      get: -> @_bar ||= 'Bar'

    attribute @, 'baz',
      set: (who) -> @_baz = who


myClass = new MyClass()
alert(myClass.foo) # alerts "Foo"
myClass.foo = 'me' # uses the foo setter
alert(myClass.foo) # alerts "Foo me"