javascript - CoffeeScript: Getter/Setter en inicializadores de objetos
oop getter-setter (6)
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 Function global (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 Rectangle que se define en términos de (x, y, ancho, alto), pero proporciona accesos 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 código JavaScript correspondiente . ¡Disfrutar!
ECMAScript nos permite definir getters o setters de la siguiente manera:
[texto / javascript]
var object = {
property: 7,
get getable() { return this.property + 1; },
set setable(x) { this.property = x / 2; }
};
Puedo solucionar el problema si estoy usando una clase :
[text / coffeescript]
"use strict"
Function::trigger = (prop, getter, setter) ->
Object.defineProperty @::,
get: getter
set: setter
class Class
property: ''''
@trigger ''getable'', ->
''x''
member: 0
Pero, ¿qué defineProperty
si quiero definir el disparador en el objeto directamente , sin usar defineProperty
/ - ies
. Quiero hacer algo como ( no funciona de esa manera):
[text / x-pseudo-coffeescript]
object =
property: ''xhr''
get getable: ''x''
Está funcionando en JavaScript sin ningún problema y no quiero que mis scripts retrocedan cuando uso CoffeeScript. ¿No hay una manera de hacer esto tan cómoda como en JavaScript / ECMAScript? Gracias.
Como @curran, prefiero no modificar el prototipo de Function
. Aquí es lo que hice en uno de mis proyectos:
Defina en alguna parte una función de utilidad que para una clase determinada devuelva 2 funciones que le permitan 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 significa g etter y s etter.
Luego, crea 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
Gracias a los otros que han ido antes. Muy en 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"
No, no por ahora :(
De las preguntas frecuentes de CoffeeScript :
P: ¿Agregará la característica X donde la característica X depende de una plataforma?
R: 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 de JavaScript actual (en la práctica, esto significa que el denominador común más bajo es IE6). Por lo tanto, las características tales como las siguientes no se implementarán: getters & setters, yield.
Algunos problemas de GitHub sobre la sintaxis getter & setter: #64 , #451 , #1165 (hay una buena discusión en el último).
Personalmente creo que tener la sintaxis literal getter & setter sería una buena característica de defineProperty
para CoffeeScript ahora que defineProperty
es parte del estándar ECMAScript . La necesidad de getters & setters en JavaScript puede ser cuestionable, pero no está obligado a usarlas solo porque existan.
De todos modos, como Object.defineProperty
notado, no es tan difícil implementar una función de contenedor conveniente que llame a Object.defineProperty
para las declaraciones de clase. Yo personalmente usaría el enfoque sugerido 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
O bien, 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
(u Object.defineProperties
;)) en 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
También puede usar Object.defineProperty en objetos JSON rectos.
obj = {}
Object.defineProperty obj, ''foo'',
get: ->
return ''bar''
La notación get / set no funciona por varios motivos en CoffeeScript. Lo más importante es que el compilador no se ha diseñado para dar cuenta de 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 las nuevas normas ECMA (ECMAScript5) mencionan Object.defineProperty como la forma de definir propiedades con getters / setters.
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