admin管理员组文章数量:1134247
// opt_options is optional
function foo(a, b, opt_options) {
// opt_c, opt_d, and opt_e are read from 'opt_options', only c and d have defaults
var opt_c = 'default_for_c';
var opt_d = 'default_for_d';
var opt_e; // e has no default
if (opt_options) {
opt_c = opt_options.c || opt_c;
opt_d = opt_options.d || opt_d;
opt_e = opt_options.e;
}
}
The above seems awfully verbose. What's a better way to handle argument options with default parameters?
// opt_options is optional
function foo(a, b, opt_options) {
// opt_c, opt_d, and opt_e are read from 'opt_options', only c and d have defaults
var opt_c = 'default_for_c';
var opt_d = 'default_for_d';
var opt_e; // e has no default
if (opt_options) {
opt_c = opt_options.c || opt_c;
opt_d = opt_options.d || opt_d;
opt_e = opt_options.e;
}
}
The above seems awfully verbose. What's a better way to handle argument options with default parameters?
Share Improve this question edited Sep 7, 2022 at 9:41 Martijn Vissers 7821 gold badge5 silver badges30 bronze badges asked Mar 7, 2012 at 13:31 ripper234ripper234 230k280 gold badges642 silver badges913 bronze badges 4 |15 Answers
Reset to default 92This uses jQuery.extend but could be interchanged with an object merger from your library of choice or Object.assign in ES6.
function Module(options){
var defaults = {
color: 'red'
};
var actual = $.extend({}, defaults, options || {});
console.info( actual.color );
}
var a = new Module();
// Red
var b = new Module( { color: 'blue' } );
// Blue
Edit: Now also in underscore
or lodash
!
function Module(options){
var actual = _.defaults(options || {}, {
color: 'red'
});
console.info( actual.color );
}
var a = new Module();
// Red
var b = new Module( { color: 'blue' } );
// Blue
In Javascript ES6 you can use Object.assign:
function Module(options = {}){
let defaults = {
color: 'red'
};
let actual = Object.assign({}, defaults, options);
console.info( actual.color );
}
Using the ES2018 spread syntax for object properties:
const defaults = { a: 1, b: 2 };
const ƒ = (given = {}) => {
const options = { ...defaults, ...given };
console.log(options);
};
Using ES6/ES2015 features, several more options are available.
Using destructuring assignment:
const { a = 1, b = 2 } = options;
You can also use destructuring function parameters:
const ƒ = ({a = 1, b = 2, c = 3} = {}) => {
console.log({ a, b, c });
};
Using Object.assign
:
options = Object.assign({}, defaults, options);
No dependencies!
To get default options without additional dependencies, I use the following pattern:
var my_function = function (arg1, arg2, options) {
options = options || {};
options.opt_a = options.hasOwnProperty('opt_a') ? options.opt_a : 'default_opt_a';
options.opt_b = options.hasOwnProperty('opt_b') ? options.opt_b : 'default_opt_b';
options.opt_c = options.hasOwnProperty('opt_c') ? options.opt_c : 'default_opt_b';
// perform operation using options.opt_a, options.opt_b, etc.
};
Although a bit verbose, I find it easy to read, add/remove options and add defaults. When there are LOTS of options, a slightly more compact version is:
var my_function = function (arg1, arg2, options) {
var default_options = {
opt_a: 'default_opt_a',
opt_b: 'default_opt_b',
opt_c: 'default_opt_c'};
options = options || {};
for (var opt in default_options)
if (default_options.hasOwnProperty(opt) && !options.hasOwnProperty(opt))
options[opt] = default_options[opt];
// perform operation using options.opt_a, options.opt_b, etc.
};
And the more compact jQuery version:
function func(opts) {
opts = $.extend({
a: 1,
b: 2
}, opts);
console.log(opts);
}
func(); // Object {a: 1, b: 2}
func({b: 'new'}); // Object {a: 1, b: "new"}
Using ES6 Spread Operator without using external libraries
function Example(opts) {
let defaults = { foo: 1, bar: 2 }
opts = { ...defaults, ...(opts || {}) }
console.log(opts);
}
Example({ bar: 3, baz: 4 })
// { foo: 1, bar: 3, baz: 4 }
If you need to do this in many consecutive functions, a way to standardize the process and speed it up is:
function setOpts (standard, user) {
if (typeof user === 'object' {
for (var key in user) {
standard[key] = user[key];
}
}
}
Then you can just define your functions simply like this:
var example = function (options) {
var opts = {
a: 1,
b: 2,
c:3
};
setOpts(opts, options);
}
This way you only define one options object inside the function, which contains the default values.
If you want to put an extra check to avoid prototype inheritance, the first function can be:
function setOpts (standard, user) {
if (typeof user === 'object') {
Object.keys(user).forEach(function (key) {
standard[key] = user[key];
});
}
}
The latter case is not supported for: IE < 9, Chrome < 5, Firefox < 4, Safari < 5
(you can check the compatibility table here)
Finally ECMAScript 6 will bring us the best way to do this: default parameters.
It will take a few months though before this is widely supported across browsers.
If you have access to ES6 with a stage 4 proposal (such as with Babel) you can accomplish this with spread and destructuring assignment.
const defaultPrintOptions = {
fontName: "times",
fontStyle: "normal",
fontSize: 10,
align: "left"
};
// Setting the null default isn't necessary but
// makes it clear that the parameter is optional.
// Could use {} but would create a new object
// each time the function is called.
function print(text, options = null) {
let {
fontName,
fontStyle,
fontSize,
align
} = {
...defaultPrintOptions,
...options
};
console.log(text, fontName, fontStyle, fontSize, align);
}
print("All defaults:");
print("Override some:", {
fontStyle: "italic",
align: "center"
});
print("Override all:", {
fontName: "courier",
fontStyle: "italic",
fontSize: 24,
align: "right"
});
This also works (but may create more objects):
function myFunction({
text = "",
line = 0,
truncate = 100
} = {}) {
console.log(text, line, truncate);
}
(latter example from David Walsh - @wprl's answer also mentions this)
Here is a simple and clean approach, hopefully, this helps someone:
function example(url, {title = false, check = false, wait = false} = {}){
console.log('url: ', URL);
console.log('title: ', title);
console.log('check: ', check);
console.log('wait: ', wait);
}
example('https://example.com', {wait: 20})
Here is the output of the code above:
url: https://example.com
title: false
check: false
wait: 20
var mergeOptions = function mergeOptions(userOptions) {
// Default options
var options = {
height: "100px",
width: "100px" ,
color: "blue"
}
if (userOptions) {
Object.keys(userOptions).forEach(function (key) {
options[key] = userOptions[key]
})
}
return options;
}
After seeing all solutions, I prefer the way as following:
function example(firstArgument, optional = {}) {
const {
a = 123, // default value
b,
} = optional;
console.log(firstArgument, a, b);
}
And this way support multiple syntax to call:
example(); // undefined 123 undefined
example("test"); // test 123 undefined
example("test", { a: 456 }); // test 456 undefined
example("test", { b: 456 }); // test 123 456
example("test", { a: 456, b: 123 }); // test 456 123
Although Object.assign is pretty straight way to merge options with defaults it has some disadvantages:
if you want to set conditional options with ternary operator - it will overwrite defaults even for
undefined
values:const options = { logging: isProduction ? 'none' : undefined }; const defaults = { logging: 'verbose' } Object.assign({}, defaults, options); // {logging: undefined} !
if you provide incorrect option name - you will not be warned:
const options = { loging: 'none' // typo }; const defaults = { logging: 'verbose' } Object.assign({}, defaults, options); // {logging: 'verbose', loging: 'none'} !
To cover these cases I've created tiny flat-options package.
It does not overwrite defaults for undefined
values:
const options = {
logging: isProduction ? 'none' : undefined
};
const defaults = {
logging: 'verbose'
}
flatOptions(options, defaults); // {logging: 'verbose'}
and warns for incorrect option names:
const options = {
loging: 'none' // typo
};
const defaults = {
logging: 'verbose'
}
flatOptions(options, defaults); // throws "Unknown option: loging."
Hope this helps!
There is a new javascript syntax for easily setting defaults, logical assignment operators:
// Super crazy this:
staticConfig.defaultPropsForFoo =
staticConfig.defaultPropsForFoo || {
myDefault: 'props'
}
// turns into:
staticConfig.defaultPropsForFoo ||= { myDefault: 'props' }
Also works with nullish operator if you prefer stricter boolean semantics:
staticConfig.defaultPropsForFoo ??= { myDefault: 'props' }
(Arguably we should always use ??=
version but it's also pretty new)
Also, I use default params all the time, but this syntax works inside of any destructuring assignment:
const {
defaultPropsForFoo = { myDefault: 'props' },
...restConfig
} = staticConfig
This is a very old question, and the answers aren't updated as per modern destructuring. If using Typescript or Babel:
function test({ a = 2, b = 2 } = {}) {
console.log(a + b)
}
test() // 4
test({ a: 3 }) // 5
Using =
provides the default arguments for the properties, and the last =
makes sure an empty object is set with the default property values if no argument is passed in.
I think you're looking for something like this (sorry for the late reply):
function foo(a, b, options) {
this.defaults = {
x: 48,
y: 72,
z: 35
};
for (var i in this.defaults) {
if (options[i] != "undefined") { this.defaults[i] = options[i]; }
}
// more code...
}
edit: apologies, grabbed this from some old code... You should make sure to use the hasOwnProperty() method to make sure you don't iterate over everything on function.prototype
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
Now that I think about it, I kind of like this:
function foo(a, b, opt_options) {
// Force opt_options to be an object
opt_options = opt_options || {};
// opt_c, opt_d, and opt_e are read from 'opt_options', only c and d have defaults
var opt_c = 'default_for_c' || opt_options.c;
var opt_d = 'default_for_d' || opt_options.d;
var opt_e = opt_options.e; // e has no default
}
本文标签: A javascript design pattern for options with default valuesStack Overflow
版权声明:本文标题:A javascript design pattern for options with default values? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736802539a1953549.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
extend
and don't keep local variables for the options? – ripper234 Commented Mar 7, 2012 at 13:40