If I have a class that I pass a number of parameters to:
class Foo
constructor: (parameters) ->
@bar = parameters.bar
@moo = parameters.moo
The class is created like so:
foo = new Foo(bar: 2, moo: 8)
My question is what is the most elegant way to detect in the constructor if the variables being passed exist, and if not to set a default. The way I would do it in javascript would be:
this.bar = ( parameters.bar !== undefined ) ? parameters.bar : 10;
where 10 is the default.
Thanks for your help :)
Good answers - Just to summerize the best:
Inorder to detect if a parameter exists and define a default if it doesn't, in javascript is:
this.bar = ( parameters.bar !== undefined ) ? parameters.bar : 10;
and in coffescript is:
@bar = parameters.bar ? 10
So elegant and compact!
You can use the existential operator:
class Foo
constructor: (options = {}) ->
@bar = options.bar ? 10
@moo = options.moo ? 20
That constructor compiles to:
// 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;
}
An equivalent alternative is to destruct the options object immediately (therefore avoiding an unnecessary name for it) and then setting the default values in case those options were not passed:
class Foo
constructor: ({@bar, @moo} = {}) ->
@bar ?= 10
@moo ?= 20
As passing an object with options is a common pattern in JS code, some libraries have useful utility functions that can help with this. Underscore, for example, provides _.defaults
, which i think results in quite readable code:
class Foo
constructor: ({@bar, @moo} = {}) ->
_.defaults @, bar: 10, moo: 20
If you are not using Underscore, there is also $.extend
(who doesn't use jQuery anyway?):
class Foo
defaults = bar: 10, moo: 20
constructor: (options = {}) ->
{@bar, @moo} = $.extend {}, defaults, options
An alternative is to extend
the Foo
object directly if you trust that the only options that will be passed are the valid ones (this results in quite minimal JS compared to the other ones):
class Foo
defaults = bar: 10, moo: 20
constructor: (options = {}) ->
$.extend @, defaults, options
And a final alternative is to have the default values in the Foo.prototype
and only set them as own properties if they come in the options parameter:
class Foo
bar: 10
moo: 20
constructor: ({bar, moo} = {}) ->
@bar = bar if bar?
@moo = moo if moo?
This prevents all the instances of Foo
from having separate properties of their own and instead shares the same properties between instances when they use the default values, the same that is usually done with methods. You can also do @bar = bar if @bar isnt bar
to assign those properties only when the parameter value differs from the default value.
As you can see, there are quite a lot of ways to do this. None of them is perfect, they all have their pros and cons, so try to choose the one that better suits your needs/taste/whatever =D
You could do this using the ?=
operator:
class Foo
constructor: (parameters) ->
@bar = parameters.bar
@bar ?= 10
@moo = parameters.moo
@moo ?= 20
If you didn't mind passing in positional arguments rather than a hash, you could also do this very elegantly using default parameter values:
class Foo
constructor: (@bar = 10, @moo = 20) ->
f = new Foo
You could define an object of defaults and do something like this..
(parameters = {}) ->
this[key] = parameters[key] ? defaults[key] for key, value of defaults
But you really don't have to go through all of that. The easiest way to make default values is just to use prototypal inheritance...
class Foo
bar: 10
moo: 10
constructor: (parameters = {}) ->
this[key] = value for own key, value of parameters
Assuming the above:
a = new Foo();
a.bar # => 10
b = new Foo(bar: 50)
b.bar # => 50
With the exception of the constructor every property you define with a : will become a property on the object's prototype.
The class definition translates to this JavaScript:
Foo = (function() {
Foo.prototype.bar = 10;
Foo.prototype.moo = 10;
//etcetc
return Foo;
})();
Play with it. Hope that helps.
class Foo
constructor: (parameters = {}) ->
{
@bar = 10
@moo = 20
} = parameters
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With