Шаблон дизайна javascript для параметров со значениями по умолчанию?
// 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;
}
}
Вышеизложенное кажется ужасно подробным. Какой лучший способ обрабатывать параметры аргументов с параметрами по умолчанию?
Ответы
Ответ 1
Теперь, когда я думаю об этом, я вроде как:
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
}
Ответ 2
Это использует jQuery.extend, но может быть заменено слиянием объектов из выбранной вами библиотеки или Object.assign в 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
Изменить: теперь также в underscore
или 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
В Javascript ES6 вы можете использовать Object.assign:
function Module(options = {}){
let defaults = {
color: 'red',
};
let actual = Object.assign({}, defaults, options);
console.info( actual.color );
}
Ответ 3
В ES6/ES2015 есть несколько новых способов. Используя Object.assign
:
options = Object.assign({}, defaults, options);
Использование деструктурирующего задания:
const { a = 1, b = 2 } = options;
Вы также можете использовать параметры функции деструктурирования:
const ƒ = ({a = 1, b = 2, c = 3} = {}) => {
console.log({ a, b, c });
};
Нет зависимостей!
Ответ 4
Чтобы получить параметры по умолчанию без дополнительных зависимостей, я использую следующий шаблон:
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.
};
Хотя немного подробный, мне легко читать, добавлять/удалять параметры и добавлять значения по умолчанию. Когда есть несколько вариантов, немного более компактная версия:
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.
};
Ответ 5
И более компактная версия jQuery:
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"}
Ответ 6
Если вам нужно сделать это во многих последовательных функциях, способ стандартизации процесса и его ускорения:
function setOpts (standard, user) {
if (typeof user === 'object' {
for (var key in user) {
standard[key] = user[key];
}
}
}
Затем вы можете просто определить свои функции просто так:
var example = function (options) {
var opts = {
a: 1,
b: 2,
c:3
};
setOpts(opts, options);
}
Таким образом вы определяете только один объект опций внутри функции, который содержит значения по умолчанию.
Если вы хотите поставить дополнительную проверку избежать наследования прототипов, первой функцией может быть:
function setOpts (standard, user) {
if (typeof user === 'object') {
Object.keys(user).forEach(function (key) {
standard[key] = user[key];
});
}
}
Последний случай не поддерживается для: IE < 9, Chrome < 5, Firefox < 4, Safari < 5
(вы можете проверить таблицу совместимости здесь)
Наконец ECMAScript 6 предложит нам лучший способ: параметры по умолчанию.
Это займет несколько месяцев, хотя до этого широко поддерживается в браузерах.
Ответ 7
Хотя Object.assign - довольно простой способ объединить параметры со значениями по умолчанию, у него есть некоторые недостатки:
-
если вы хотите установить условные параметры с тройным оператором - он перезапишет значения по умолчанию даже для значений undefined
:
const options = {
logging: isProduction ? 'none' : undefined
};
const defaults = {
logging: 'verbose'
}
Object.assign({}, defaults, options); // {logging: undefined} !
-
если вы указали неверное имя параметра - вы не будете предупреждены:
const options = {
loging: 'none' // typo
};
const defaults = {
logging: 'verbose'
}
Object.assign({}, defaults, options); // {logging: 'verbose', loging: 'none'} !
Чтобы охватить эти случаи, я создал маленький flat-options пакет.
Он не перезаписывает значения по умолчанию для значений undefined
:
const options = {
logging: isProduction ? 'none' : undefined
};
const defaults = {
logging: 'verbose'
}
flatOptions(options, defaults); // {logging: 'verbose'}
и предупреждает о неправильных именах опций:
const options = {
loging: 'none' // typo
};
const defaults = {
logging: 'verbose'
}
flatOptions(options, defaults); // throws "Unknown option: loging."
Надеюсь, это поможет!
Ответ 8
Если у вас есть доступ к ES6 с предложением этапа 4 (например, с Babel), вы можете выполнить это с помощью распределения и деструктурирования.
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"
});
Ответ 9
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;
}
Ответ 10
Я думаю, что вы ищете что-то вроде этого (извините за поздний ответ):
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: извинения, захватили это из какого-то старого кода... Вы должны убедиться, что используете метод hasOwnProperty(), чтобы убедиться, что вы не перебираете все на функции .prototype
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty