Javascript CoffeeScript:对象初始值设定项中的 Getter/Setter
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11587231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CoffeeScript: Getter/Setter in Object Initializers
提问by fridojet
ECMAScript allows us to define getters or setters as following:
ECMAScript 允许我们定义 getter 或 setter 如下:
[text/javascript]
[文本/javascript]
var object = {
property: 7,
get getable() { return this.property + 1; },
set setable(x) { this.property = x / 2; }
};
I can work around if I'm using a class:
如果我正在使用一个类,我可以解决:
[text/coffeescript]
[文字/咖啡稿]
"use strict"
Function::trigger = (prop, getter, setter) ->
Object.defineProperty @::,
get: getter
set: setter
class Class
property: ''
@trigger 'getable', ->
'x'
member: 0
But what if I want to define trigger on the object directly- withoutusing defineProperty
/ -ies
. I want to do something like (it's not workingthat way):
但是如果我想直接在对象上定义触发器怎么办-不使用defineProperty
/ -ies
。我想做一些类似的事情(它不是那样工作的):
[text/x-pseudo-coffeescript]
[文本/x-伪咖啡脚本]
object =
property: 'xhr'
get getable: 'x'
It's working in JavaScript without any problems and I don't want my scripts to regress when I'm using CoffeeScript. Isn't there a way to do this as comfortable as in JavaScript/ECMAScript? Thanks.
它在 JavaScript 中运行没有任何问题,我不希望我的脚本在使用 CoffeeScript 时退化。难道没有一种方法可以像在 JavaScript/ECMAScript 中那样轻松地做到这一点吗?谢谢。
回答by epidemian
No, not for now :(
不,暂时不:(
From the CoffeeScript FAQ:
Q: Will you add feature X where feature X depends on a platform?
A: No, implementation-specific features are not allowed as a policy. Everything that you write in CoffeeScript should be supported and runnable on any current JavaScript implementation (in practice, this means the lowest common denominator is IE6). Thus, features such as the following will not be implemented: getters & setters, yield.
问:您会在功能 X 取决于平台的情况下添加功能 X 吗?
答:不可以,不允许将特定于实现的功能作为策略。您在 CoffeeScript 中编写的所有内容都应该在任何当前的 JavaScript 实现上都得到支持和运行(实际上,这意味着最小的公分母是 IE6)。因此,将不会实现以下功能:getter & setter、yield。
Some GitHub issues about getter & setter syntax: #64, #451, #1165(there is some nice discussion in the last one).
关于 getter 和 setter 语法的一些 GitHub 问题:#64、#451、#1165(最后一个有一些很好的讨论)。
I personally think that having getter & setter literal syntax would be a nice opt-in feature for CoffeeScript now that defineProperty
is part of the ECMAScript standard. The need for getters & setters in JavaScript can be questionable, but you're not forced to use them just because they exist.
我个人认为拥有 getter 和 setter 文字语法将是 CoffeeScript 的一个不错的选择加入功能,现在它defineProperty
是ECMAScript 标准的一部分。JavaScript 中对 getter 和 setter 的需求可能是有问题的,但您不会仅仅因为它们存在就被迫使用它们。
Anyway, as you noticed, it's not that hard to implement a convenient wrapper function that calls Object.defineProperty
for class declarations. I personally would use the approach suggested in here:
无论如何,正如您所注意到的,实现一个方便的调用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
Or, maybe create two different methods:
或者,也许创建两种不同的方法:
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 ' '
For plain objects you can just use Object.defineProperty
(or Object.defineProperties
;) ) on the object itself as Jason proposed. Maybe wrap that in a little function:
对于普通对象,您可以像Jason 建议的那样在对象本身上使用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
回答by curran
Here's another approach for defining properties with getters and setters in CoffeeScript that maintains a relatively clean syntax without adding anything to the global Function prototype (which I'd rather not do):
这是在 CoffeeScript 中使用 getter 和 setter 定义属性的另一种方法,它保持相对干净的语法,而无需向全局函数原型添加任何内容(我宁愿不这样做):
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
It works well with many properties. For example, here's a Rectangle class that is defined in terms of (x, y, width, height), but provides accessors for an alternative representation (x1, y1, x2, y2):
它适用于许多属性。例如,这里有一个 Rectangle 类,它是根据 (x, y, width, height) 定义的,但提供了用于替代表示 (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
Here's the corresponding JavaScript code. Enjoy!
这是相应的 JavaScript 代码。享受!
回答by Jason L.
You can use Object.defineProperty on straight JSON objects as well.
您也可以在直接的 JSON 对象上使用 Object.defineProperty。
obj = {}
Object.defineProperty obj, 'foo',
get: ->
return 'bar'
The get/set notation does not work for various reasons in CoffeeScript. The biggest being that the compiler has not been built to account for get/set notation.
由于各种原因, get/set 符号在 CoffeeScript 中不起作用。最大的问题是编译器尚未构建以考虑 get/set 表示法。
Note that get/set is not supported by all browsers (specifically, IE). Also note that the new ECMA standards (ECMAScript5) mentions Object.defineProperty as the way to define properties with getters/setters.
请注意,并非所有浏览器(特别是 IE)都支持 get/set。另请注意,新的 ECMA 标准 (ECMAScript5) 提到 Object.defineProperty 作为使用 getter/setter 定义属性的方式。
回答by Micka?l Gauvin
Like @curran, I prefer not to modify Function
prototype.
Here it is what I did in one of my projects?:
像@curran 一样,我不喜欢修改Function
原型。这是我在我的一个项目中所做的?:
Define somewhere an utility function which for a given class returns 2 functions allowing you to easily add getters and setters on the prototype of the class:
在某处定义一个实用函数,它为给定的类返回 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
gsstands for getter and setter.
GS代表摹埃特和小号埃特。
Then, you build and import the two functions configured for your class :
然后,您构建并导入为您的类配置的两个函数:
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
回答by M K
An alternative approach:
另一种方法:
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
回答by kwerle
Thanks to the others that have gone before. Very generally and simply:
感谢之前去过的其他人。非常普遍和简单:
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"