43

ECMAScript を使用すると、次のようにゲッターまたはセッターを定義できます。

[テキスト/javascript]

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

クラスを使用している場合は回避できます。

[テキスト/コーヒースクリプト]

"use strict"

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

class Class
      property: ''

      @trigger 'getable', ->
               'x'

      member: 0

しかし、 / -を使用せずに、オブジェクトにトリガーを直接定義したい場合はどうでしょう。私は次のようなことをしたいです(そのようには機能しません):definePropertyies

[text/x-pseudo-coffeescript]

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

JavaScript で問題なく動作しており、CoffeeScript を使用しているときにスクリプトのパフォーマンスが低下することは望ましくありません。JavaScript /ECMAScriptと同じくらい快適にこれを行う方法はありませんか? ありがとう。

4

6 に答える 6

78

いいえ、今のところではありません:(

CoffeeScript FAQから:

Q: プラットフォームに依存する機能 X を追加する予定はありますか?

A: いいえ、実装固有の機能はポリシーとして許可されていません。CoffeeScript で記述したものはすべて、現在の JavaScript 実装でサポートされ、実行可能である必要があります (実際には、これは最小公分母が IE6 であることを意味します)。したがって、ゲッターとセッター、yield などの機能は実装されません。

ゲッターとセッターの構文に関するいくつかの GitHub の問題: #64#451#1165 (最後のものでいくつかの良い議論があります)。

defineProperty個人的には、getter と setter のリテラル構文を持つことは、ECMAScript 標準の一部となった CoffeeScript の優れたオプトイン機能になると思います。JavaScript での getter と setter の必要性は疑わしい場合がありますが、それらが存在するという理由だけでそれらを使用する必要はありません。


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

または、2 つの異なるメソッドを作成することもできます。

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 ' '

単純なオブジェクトの場合、ジェイソンが提案し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
于 2012-07-21T14:09:10.960 に答える
33

これは、CoffeeScriptでゲッターとセッターを使用してプロパティを定義するための別のアプローチです。グローバル関数プロトタイプに何も追加せずに比較的クリーンな構文を維持します(これは私がしたくない):

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

多くのプロパティでうまく機能します。たとえば、(x、y、width、height)で定義されているが、代替表現(x1、y1、x2、y2)のアクセサーを提供するRectangleクラスは次のとおりです。

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

対応するJavaScriptコードは次のとおりです。楽しみ!

于 2013-03-19T19:48:57.847 に答える
8

Object.defineProperty は、そのままの JSON オブジェクトでも使用できます。

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

get/set 表記は、CoffeeScript ではさまざまな理由で機能しません。最大の問題は、コンパイラが get/set 表記を考慮して構築されていないことです。

get/set はすべてのブラウザー (特に IE) でサポートされているわけではないことに注意してください。また、新しい ECMA 標準 (ECMAScript5) では、getter/setter を使用してプロパティを定義する方法として Object.defineProperty が言及されていることに注意してください。

于 2012-07-20T21:42:08.983 に答える
5

@curran のように、私はFunctionプロトタイプを変更したくありません。これが私のプロジェクトの1つで行ったことです。

特定のクラスに対して 2 つの関数を返すユーティリティ関数をどこかに定義して、クラスのプロトタイプにゲッターとセッターを簡単に追加できるようにします。

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

gsは、ゲッターとセッター略です。

次に、クラス用に構成された 2 つの関数をビルドしてインポートします。

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
于 2015-03-10T20:24:35.730 に答える
1

別のアプローチ:

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
于 2016-11-21T09:01:29.063 に答える