admin管理员组文章数量:1424445
Is it possible to "deep extend" objects when using destructuring to set default properties of an object passed into a function?
Example:
function foo({
foo = 'foo',
bar = 'bar',
baz = {
propA: 'propA',
propB: 'propB'
}
} = {}) {
console.log(foo);
console.log(bar);
console.log(baz);
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
Is it possible to "deep extend" objects when using destructuring to set default properties of an object passed into a function?
Example:
function foo({
foo = 'foo',
bar = 'bar',
baz = {
propA: 'propA',
propB: 'propB'
}
} = {}) {
console.log(foo);
console.log(bar);
console.log(baz);
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
This outputs: (baz is overwrote)
changed
bar
{
"propA": "changed"
}
Is there syntax which will extend the baz
object, to give output:
changed
bar
{
"propA": "changed",
"propB": "propB"
}
Share
Improve this question
asked Dec 5, 2016 at 11:42
FergalFergal
2,4744 gold badges36 silver badges49 bronze badges
4 Answers
Reset to default 6There is no native-way to do what you ask, but you can write your own function decorator
, of course it is a verbose approach...
Note: In order to perform a deep merge you should use some of the existing solution developed by the munity, both Object.assign
and Object Spread Operator
perform a shallow copy of the source, even, writing your own deepmerge function could be error-prone. I suggest you to use lodash#merge
that is monly accepted as one of the solid solutions to the problem.
var {
// https://lodash./docs/#merge
merge
} = require('lodash');
function defaultsArgDecorator(defaults, target) {
return function(args) {
return target(
merge(Object.create(defaults), args)
)
}
}
function _foo(args) { console.log({args}); }
var foo = defaultsArgDecorator({
foo: 'foo',
bar: 'bar',
baz: {
propA: 'propA',
propB: 'propB'
}
}, _foo);
foo({bar: "ciao bello", baz: {propA: "HELLO"}})
Since parameters destructuring allow you to use previous parameters in the defaults of other parameters, you can create a property that doesn't exit on the original parameters, for example __baz
, and set its defaults using baz
.
In the method you'll use __baz
instead of baz
.
Note: this is a hack, and if the object contains a property by the name of
__baz
it will override the default, with unexpected results. However, you can name the default property with something likedontUse__baz
, which has a very low chance of being used.
Default properties using Object#assign
:
function foo({
foo = 'foo',
bar = 'bar',
baz,
__baz = Object.assign({
"propA": "changed",
"propB": "propB"
}, baz)
} = {}) {
console.log(foo);
console.log(bar);
console.log(__baz);
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
Default properties using object spread (requires babel plugin - see link):
function foo({
foo = 'foo',
bar = 'bar',
baz,
__baz = {
"propA": "changed",
"propB": "propB",
...baz
}
} = {}) {
console.log(foo);
console.log(bar);
console.log(__baz);
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
You can also do nested destructuring. You destructure baz, but also destructure propA
and propB
.
If you need your object whole and don't want to 'rebuild' it, this isn't for you, but it does acplish one objective of setting default values for unspecified properties nested in an object.
I've left baz
as a separate descructured value in addition to it's properties as an example of a sometimes handy pattern, but you would most likely want to remove it since it suffers from the same problem of losing default properties.
function foo({
foo = 'foo',
bar = 'bar',
baz, // likely extraneous and confusing, here for example
baz: { propA = 'propA', propB = 'propB' }
} = {}) {
console.log(foo);
console.log(bar);
console.log(propA, propB);
console.log(baz);
console.log(Object.assign(baz, {propA, propB}));
}
foo({
foo: 'changed',
baz: {
propA: 'changed'
}
});
Yep, totally possible!
Solution 1:
function foo({
foo = 'foo',
bar = 'bar',
baz: {
propA = 'propA',
propB = 'propB'
} = {}
}) {
console.log(foo)
console.log(bar)
console.log({propA, propB}) // Because `bar` is renamed to `{propA, propB}`. Hence, no local variable named `baz`
}
Solution 2 (Workaround):
function foo({
foo = 'foo',
bar = 'bar',
baz = {}
}) {
// ...
const baz2 = Object.assign({}, {propA: 'propA', propB: 'propB'} = {})
console.log(baz2) // Yeah, not really a solution
}
You can even do this:
const func = ([{foo, bar: {a, b: BB, c: CC = 'c'} = {}} = {}], ...{0: rest0 = 0, 1: rest1 = '1'}) => { /* do stuffs */ }
The code above is a plicated example, I'll use simpler examples to explain:
Example 1:
const f1 = ({x: varx}) => console.log(varx)
When you call f1(obj)
, obj.x
will be assigned to varx
in f1
's scope
Example 2:
const f2 = ({xy: {x, y}}) => console.log({x, y})
Similar to f1
but with {x, y}
in place of varx
, obj.xy
will be assigned to {x, y}
, so x = obj.xy.x
and y = obj.xy.y
Example 3: Now let add create default parameters
const f3 = ({xy: {x, y} = {}}) => { /* do stuffs */ }
Now, you still have to pass obj
as an object but you no longer have to provide obj.xy
. If obj.xy
is undefined
, x
and y
are undefined
s
Example 4: Now, let x
and y
have default values
const f4 = ({xy: {x = 'XXX', y = 'YYY'} = {}}) => { /* do stuffs */ }
If obj.xy
you passed is undefined
, {x, y}
will be set to {x: undefined, y: undefined}
, but since x
and y
also have default values, x
will be 'XXX'
and y
will be 'YYY'
Example 4: "THE ULTIMATE LIFE FORM"
const f5 = ({xy: {x = 'XXX', y = 'YYY'} = {}} = {}) => { /* do stuffs */ }
Guess I don't have to explain this anymore :D
本文标签: javascriptDestructuring objects as function parameters deep extendStack Overflow
版权声明:本文标题:javascript - Destructuring objects as function parameters deep extend - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745421388a2657914.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论