javascript oop coffeescript getter-setter ecmascript-5

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