ECMAScript允许我们定义getter或setter如下:
[文本/ JavaScript的]
var object = {
property: 7,
get getable() { return this.property + 1; },
set setable(x) { this.property = x / 2; }
};
如果我使用类:
,我可以解决[文本/ CoffeeScript的]
"use strict"
Function::trigger = (prop, getter, setter) ->
Object.defineProperty @::,
get: getter
set: setter
class Class
property: ''
@trigger 'getable', ->
'x'
member: 0
但是如果我想直接在对象上定义触发器 - 而不使用 defineProperty
/ - ies
。我想做一些事情(这是无法正常工作):
[文本/ X-伪的CoffeeScript]
object =
property: 'xhr'
get getable: 'x'
它在JavaScript中运行没有任何问题,我不想让我的脚本在使用CoffeeScript时回归。有没有办法像JavaScript一样舒服 / ECMAScript?感谢。
答案 0 :(得分:74)
不,不是现在:(
问:您是否会在功能X依赖于平台的位置添加功能X?
答:不可以,特定于实现的功能不允许作为策略。您在CoffeeScript中编写的所有内容都应该在任何当前的JavaScript实现上得到支持和运行(实际上,这意味着最低的共同点是IE6)。因此,以下功能将不会实现:getters&二传手,收益率。
关于getter& amp;的一些GitHub问题setter语法:#64,#451,#1165(在最后一个中有一些很好的讨论)。
我个人认为有吸气剂和吸气剂现在,defineProperty
是part of the ECMAScript standard,因此setter文字语法对于CoffeeScript来说是一个不错的选择加入功能。对吸气剂和吸气剂的需求JavaScript中的setter可能有问题,但你不会因为它们的存在而被迫使用它们。
无论如何,正如您所注意到的,实现一个方便的包装函数并不难以为类声明调用Object.defineProperty
。我个人会使用here中建议的方法:
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
或者,也许可以创建两种不同的方法:
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
;))对象本身用作Jason proposed。也许把它包装成一个小函数:
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
答案 1 :(得分:29)
这是另一种在CoffeeScript中使用getter和setter定义属性的方法,它保持相对干净的语法,而不向全局Function原型添加任何内容(我不愿意这样做):
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)定义的Rectangle类,但为替代表示(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
答案 2 :(得分:7)
您也可以在直接JSON对象上使用Object.defineProperty。
obj = {}
Object.defineProperty obj, 'foo',
get: ->
return 'bar'
在CoffeeScript中,get / set表示法因各种原因不起作用。最大的问题是编译器尚未构建以考虑获取/设置表示法。
请注意,并非所有浏览器(特别是IE)都支持get / set。另请注意,新的ECMA标准(ECMAScript5)提到了Object.defineProperty作为使用getter / setter定义属性的方法。
答案 3 :(得分:4)
与@curran一样,我不想修改Function
原型。
这是我在其中一个项目中所做的:
定义一个实用程序函数,它为给定的类返回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
gs 代表 g etter和 s etter。
然后,构建并导入为您的类配置的两个函数:
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
答案 4 :(得分: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
答案 5 :(得分:1)
感谢之前的其他人。一般而且简单:
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"