CoffeeScript: Getter / Setter en Inicializadores de objetos
ECMAScript nos permite definir getters o setters de la siguiente manera:
[text/javascript]
var object = {
property: 7,
get getable() { return this.property + 1; },
set setable(x) { this.property = x / 2; }
};
Puedo trabajar si estoy usando una clase :
[texto/coffeescript]
"use strict"
Function::trigger = (prop, getter, setter) ->
Object.defineProperty @::,
get: getter
set: setter
class Class
property: ''
@trigger 'getable', ->
'x'
member: 0
Pero qué pasa si quiero definir trigger en el objeto directamente - sin usando defineProperty
/ -ies
. Quiero hacer algo como (es no funciona de esa manera):
[texto / x-pseudo-coffeescript]
object =
property: 'xhr'
get getable: 'x'
Es trabajando en JavaScript sin ningún problema y no quiero que mis scripts retrocedan cuando estoy usando CoffeeScript. ¿No hay una manera de hacer esto tan cómodo como en JavaScript/ECMAScript? Gracias.
6 answers
No, no por ahora : (
Del CoffeeScript FAQ :
P: ¿Agregará la característica X donde la característica X depende de una plataforma?
A: No, las características específicas de la implementación no están permitidas como política. Todo lo que escriba en CoffeeScript debe ser compatible y ejecutable en cualquier implementación actual de JavaScript (en la práctica, esto significa que el denominador común más bajo es IE6). Por lo tanto, no se implementarán características como las siguientes: getters & armadores, cedan.
Algunos problemas de GitHub sobre la sintaxis getter & setter: #64, #451, #1165 (hay una buena discusión en el último).
Personalmente creo que tener sintaxis literal de getter & setter sería una buena característica de opt-in para CoffeeScript ahora que defineProperty
es parte del estándar ECMAScript. La necesidad de getters y setters en JavaScript puede ser cuestionable, pero no está obligado a usarlos solo porque existan.
De todos modos, como se ha dado cuenta, no es tan difícil implementar una función de envoltura conveniente que llama Object.defineProperty
para declaraciones de clase. Yo personalmente usaría el enfoque sugerido en aquí :
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
O, tal vez crear dos métodos diferentes:
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 ' '
Para objetos simples puede usar Object.defineProperty
(o Object.defineProperties
;) ) sobre el objeto en sí como Jason propuso . Tal vez envolver eso en una pequeña función:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:29:54
Aquí hay otro enfoque para definir propiedades con getters y setters en CoffeeScript que mantiene una sintaxis relativamente limpia sin agregar nada al prototipo de función global (lo que prefiero no hacer):
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
Funciona bien con muchas propiedades. Por ejemplo, aquí hay una clase de rectángulo que se define en términos de (x, y, width, height), pero proporciona accesores para una representación alternativa (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
Aquí está el JavaScript correspondiente código. ¡Que lo disfrutes!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-19 19:48:57
Puede usar Object.defineProperty también en objetos JSON rectos.
obj = {}
Object.defineProperty obj, 'foo',
get: ->
return 'bar'
La notación get/set no funciona por varias razones en CoffeeScript. El mayor es que el compilador no ha sido construido para tener en cuenta la notación get/set.
Tenga en cuenta que get/set no es compatible con todos los navegadores (específicamente, IE). También tenga en cuenta que los nuevos estándares ECMA (ECMAScript5) menciona Object.defineProperty como la forma de definir propiedades con getters / setters.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-31 18:08:52
Al igual que @curran, prefiero no modificar el prototipo Function
.
Aquí está lo que hice en uno de mis proyectos :
Defina en algún lugar una función de utilidad que para una clase dada devuelve 2 funciones que le permiten agregar fácilmente getters y setters en el prototipo de la clase:
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 representa getter y setter.
Luego, compila e importa las dos funciones configuradas para su clase :
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-29 08:15:37
Un enfoque alternativo:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-21 09:14:53
Gracias a los otros que han ido antes. Muy general y simplemente:
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"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-16 21:57:08