18

如果我有一个类,我将许多参数传递给:

class Foo

  constructor: (parameters) ->

  @bar = parameters.bar
  @moo = parameters.moo

该类是这样创建的:

foo = new Foo(bar: 2, moo: 8)

我的问题是在构造函数中检测传递的变量是否存在以及不设置默认值的最优雅方法是什么。我会在 javascript 中这样做的方式是:

this.bar = ( parameters.bar !== undefined ) ? parameters.bar : 10;

其中 10 是默认值。

谢谢你的帮助 :)

好的答案 - 只是为了总结最好的:

为了检测参数是否存在并在不存在时定义默认值,在 javascript 中是:

this.bar = ( parameters.bar !== undefined ) ? parameters.bar : 10;

在咖啡中是:

@bar = parameters.bar ? 10

如此优雅和紧凑!

4

5 回答 5

30

您可以使用存在运算符

class Foo
  constructor: (options = {}) ->
    @bar = options.bar ? 10
    @moo = options.moo ? 20

该构造函数编译为:

// Compiled JS.
function Foo(options) {
  var _ref, _ref1;
  if (options == null) {
    options = {};
  }
  this.bar = (_ref = options.bar) != null ? _ref : 10;
  this.moo = (_ref1 = options.moo) != null ? _ref1 : 20;
}

一个等效的替代方法是立即破坏选项对象(因此避免不必要的名称),然后设置默认值以防这些选项未传递:

class Foo
  constructor: ({@bar, @moo} = {}) ->
    @bar ?= 10
    @moo ?= 20

由于传递带有选项的对象是 JS 代码中的一种常见模式,因此一些库具有有用的实用函数可以帮助解决此问题。例如,下划线提供了_.defaults,我认为这会产生非常可读的代码:

class Foo
  constructor: ({@bar, @moo} = {}) ->
    _.defaults @, bar: 10, moo: 20

如果你不使用 Underscore,还有$.extend(谁不使用 jQuery?):

class Foo
  defaults = bar: 10, moo: 20
  constructor: (options = {}) ->
    {@bar, @moo} = $.extend {}, defaults, options

如果您相信将传递的唯一选项是有效选项,则另一种方法是直接extend使用对象(与其他选项相比,这导致 JS 非常少):Foo

class Foo
  defaults = bar: 10, moo: 20
  constructor: (options = {}) ->
    $.extend @, defaults, options

最后一种选择是在 中使用默认值,Foo.prototype并且仅当它们出现在 options 参数中时才将它们设置为自己的属性:

class Foo
  bar: 10
  moo: 20
  constructor: ({bar, moo} = {}) ->
    @bar = bar if bar?
    @moo = moo if moo?

这可以防止所有实例Foo具有自己的单独属性,而是在使用默认值时在实例之间共享相同的属性,这通常与方法相同。您也可以@bar = bar if @bar isnt bar仅在参数值与默认值不同时分配这些属性。

如您所见,有很多方法可以做到这一点。它们都不是完美的,它们都有其优点和缺点,因此请尝试选择更适合您的需求/口味/无论如何=D

于 2012-07-15T17:49:24.163 回答
3

您可以使用运算符执行此?=操作:

class Foo
  constructor: (parameters) ->
   @bar = parameters.bar
   @bar ?= 10
   @moo = parameters.moo
   @moo ?= 20

如果您不介意传入位置参数而不是哈希,您也可以使用默认参数值非常优雅地执行此操作:

class Foo
  constructor: (@bar = 10, @moo = 20) ->

f = new Foo
于 2012-07-15T16:15:16.307 回答
2

您可以定义一个默认对象并执行类似的操作..

 (parameters = {}) ->
   this[key] = parameters[key] ? defaults[key] for key, value of defaults

但你真的不必经历所有这些。制作默认值的最简单方法就是使用原型继承......

class Foo
  bar: 10
  moo: 10
  constructor: (parameters = {}) ->
    this[key] = value for own key, value of parameters

假设上述情况:

a = new Foo();
a.bar # => 10
b = new Foo(bar: 50)
b.bar # => 50

除了构造函数之外,您使用 : 定义的每个属性都将成为对象原型上的属性。

类定义转换为这个 JavaScript:

Foo = (function() {      
  Foo.prototype.bar = 10;      
  Foo.prototype.moo = 10;
  //etcetc
  return Foo;      
})();

玩它。希望有帮助。

于 2012-07-15T16:43:44.987 回答
1

还有一种更简单的方法:

class Foo
  constructor: (parameters = {}) ->
    {
      @bar = 10
      @moo = 20
    } = parameters
于 2015-09-06T20:38:34.243 回答
1

新版本的coffeescript有一个很好的方法来解决这个确切的问题

class MyObject
  constructor: ({string1='x', string2='y'} = {})

它也适用于常规功能

myFunction = ({string1='x', string2='y'} = {}) ->
  string1 + string2

console.log myFunction({string1:"a", string2:"b"}) 
# outputs: 'ab'

console.log myFunction() 
# outputs: 'xy'
于 2015-12-31T03:21:47.800 回答