Fer*_*gal 6 javascript ecmascript-6
在使用解构来设置传递给函数的对象的默认属性时,是否可以"深度扩展"对象?
例:
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'
}
});
Run Code Online (Sandbox Code Playgroud)
这输出:(巴兹被覆盖)
changed
bar
{
"propA": "changed"
}
Run Code Online (Sandbox Code Playgroud)
是否存在扩展baz
对象的语法,以提供输出:
changed
bar
{
"propA": "changed",
"propB": "propB"
}
Run Code Online (Sandbox Code Playgroud)
没有本地方法可以做你所要求的,但你可以自己编写function decorator
,当然这是一个冗长的方法......
注意:为了执行深度合并,您应该使用社区开发的一些现有解决方案,Object.assign
并Object Spread Operator
执行源的浅层副本,即使编写自己的deepmerge函数也可能容易出错.我建议你使用lodash#merge
这是常见的最佳解决方案.
var {
// https://lodash.com/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"}})
Run Code Online (Sandbox Code Playgroud)
由于参数解构允许您在其他参数的默认值中使用以前的参数,因此您可以创建一个不在原始参数上存在的属性,例如__baz
,并使用 设置其默认值baz
。在该方法中,您将使用__baz
而不是baz
.
注意:这是一个 hack,如果对象包含一个名称为属性的属性,
__baz
则会覆盖默认值,从而产生意外的结果。但是,您可以使用诸如 之类的名称来命名默认属性dontUse__baz
,但使用该属性的可能性非常低。
默认属性使用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'
}
});
Run Code Online (Sandbox Code Playgroud)
使用对象传播的默认属性(需要 babel 插件 -请参阅链接):
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'
}
});
Run Code Online (Sandbox Code Playgroud)
DMa*_*ter -3
是的,完全有可能!
解决方案一:
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`
}
Run Code Online (Sandbox Code Playgroud)
解决方案 2(解决方法):
function foo({
foo = 'foo',
bar = 'bar',
baz = {}
}) {
// ...
const baz2 = Object.assign({}, {propA: 'propA', propB: 'propB'} = {})
console.log(baz2) // Yeah, not really a solution
}
Run Code Online (Sandbox Code Playgroud)
你甚至可以这样做:
const func = ([{foo, bar: {a, b: BB, c: CC = 'c'} = {}} = {}], ...{0: rest0 = 0, 1: rest1 = '1'}) => { /* do stuffs */ }
Run Code Online (Sandbox Code Playgroud)
上面的代码是一个复杂的例子,我将用更简单的例子来解释:
示例1:
const f1 = ({x: varx}) => console.log(varx)
Run Code Online (Sandbox Code Playgroud)
当你调用时f1(obj)
,obj.x
将被分配到varx
inf1
的范围内
示例2:
const f2 = ({xy: {x, y}}) => console.log({x, y})
Run Code Online (Sandbox Code Playgroud)
与 类似,f1
但用{x, y}
代替varx
,obj.xy
将被分配给{x, y}
, sox = obj.xy.x
和y = obj.xy.y
示例 3:现在让 add 创建默认参数
const f3 = ({xy: {x, y} = {}}) => { /* do stuffs */ }
Run Code Online (Sandbox Code Playgroud)
现在,您仍然必须obj
作为对象传递,但不再需要提供obj.xy
. 如果obj.xy
是undefined
,x
并且y
是undefined
s
示例 4:现在,让x
和y
具有默认值
const f4 = ({xy: {x = 'XXX', y = 'YYY'} = {}}) => { /* do stuffs */ }
Run Code Online (Sandbox Code Playgroud)
如果obj.xy
您传递了 is undefined
,{x, y}
则将被设置为{x: undefined, y: undefined}
,但由于x
和y
也有默认值,因此x
will be'XXX'
和y
will be'YYY'
示例 4:“终极生命形式”
const f5 = ({xy: {x = 'XXX', y = 'YYY'} = {}} = {}) => { /* do stuffs */ }
Run Code Online (Sandbox Code Playgroud)
我想我不必再解释了:D