在类构造函数中解构参数列表 - Coffeescript

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;

在 CoffeeScript 中则是:

@bar = parameters.bar ? 10

如此优雅而简洁!


最简单的方法:https://dev59.com/1Ggu5IYBdhLWcg3wMkfF#32428070 - Inanc Gumus
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代码中,传递带有选项的对象是一种常见模式,因此一些库提供了有用的实用函数来帮助处理这个问题。例如,Underscore提供了_.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

另一种方法是直接扩展 Foo 对象,如果您相信传递的选项只会是有效的,则这种方法比其他方法产生的JS代码要少得多:

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

最后一种选择是将默认值存储在Foo.prototype中,只有当它们在选项参数中出现时才将它们设置为自己的属性:

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


有很多好的答案,但最优雅的是:@bar = options.bar ? 10 - Jamie Fearon
1
非常喜欢那里的$.extend @,defaults,options方法。 - Chris Nicola

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

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;      
})();

尝试使用它。希望这能有所帮助。


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'

1

有更简单的方法:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接