函数调用的对象解构

Posted

技术标签:

【中文标题】函数调用的对象解构【英文标题】:Object destructuring for function calls 【发布时间】:2019-09-10 18:29:03 【问题描述】:

有没有办法就地解构 JS 对象,而不是将解构后的变量分配给作用域?

不要这样做:

const  a, b, c  = obj;
someFunction(a, b, c);

我想这样做:

someFunction(a, b, c from obj);

或功能等效的东西。

我想在有这两个规定的情况下这样做:

我不想将变量名放入封闭范围内。

我不想传递整个对象 obj,因此无法选择展开运算符。

我剩下的唯一选择是使用

someFunction(obj.a, obj.b, obj.c);

在这种情况下这很好,但当obj 是一个长标识符时会降低可读性。

这样的事情可能吗?我尝试在表达式中使用赋值作为解决方法,但我的 IDE 抱怨它找不到名称 abc

someFunction(a, b, c = obj);

【问题讨论】:

如果你的目标是 es6 环境,你可以使用解构参数来定义你的函数,例如 function f(a,b,c) /*...*/ 或者你不想这样,因为你不想传递整个对象 【参考方案1】:

一种选择是使用.map 提取您想要的每个属性的值,并将其传播到参数列表中:

someFunction(
  ...['a', 'b', 'c'].map(prop => obj[prop])
);

解构需要创建中间变量,不幸的是,这是你不想要的。

【讨论】:

不幸的是,中间体是必需的,因为在某些情况下(比如我的)它只是不必要的性能损失。至于你的提议,我喜欢它比 obj.property 更好地扩展,但它仍然很冗长:/ 足以让我确信如果没有代码审查失败,我就无法将它投入生产代码。 性能很少需要担心 - 代码可读性在 99% 的情况下更重要,如果您想保持代码 DRY 并希望能够将模式用于任意数量的属性,我很确定这是你能找到的最好的模式。如果由于过于冗长而导致代码审查失败,我认为这表明代码审查存在问题,而不是此处的代码存在问题 我同意你的所有陈述,尤其是最后一个(但遗憾的是,我的观点并没有胜过传统)。也许我应该试一试,看看会发生什么。【参考方案2】:

IIFE 应该可以工作:

((( a, b, c ) => someFunction(a, b, c))(obj);

【讨论】:

我喜欢这个工作,但我不喜欢每当我需要调用someFunction 时创建函数的性能损失。此外,与另一个答案类似,这看起来很不寻常,我认为它不会通过代码审查:/.【参考方案3】:

我会这样做:

function foo(  x, y  ) 
	console.log( x, y );


foo(  y: 1, x: 2  );	 // 2 1

至于 OP 的具体要求是不传递整个对象(或在全局范围内声明变量)。恕我直言,将对象解构为块范围变量是最好的方法。

const obj =  x: 1, y: 2 

function foo( x, y ) 
    console.log( x, y );


   let  x, y  = obj;
    foo( x, y );   // 1 2


console.log(x) // "ReferenceError: x is not defined

【讨论】:

您能解释一下这如何解决我的问题吗?我看不出有很强的关系。 您将对象作为参数传递,并将其作为函数参数进行破坏。我知道您说过您不想将整个对象作为参数传递,这仍然是我的建议。 对,但这意味着我必须是编写函数的人。非常适合我自己的代码,但在很多情况下我无法控制函数的参数,例如库,或为公司编码时的大部分成本。 @@AnthonyMonterrosa 如果这是一个大问题,我会使用这种风格作为你的库调用的包装函数,例如function wrapLib(x, y) return library.expensiveCall(x,y)。如果情况需要,可以缓存结果。或者,TC39 一直在寻找对 JS 的独特改进。【参考方案4】:

对象解构的函数调用参数未知

当您无法访问或更改函数声明,或者您不想这样做时,这是需要的。

const getParamNames = func => 
    const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
    const ARGUMENT_NAMES = /([^\s,]+)/g;
    let fnStr = func.toString().replace(STRIP_COMMENTS, '');
    let result = fnStr.slice(fnStr.indexOf('(')+1, 
    fnStr.indexOf(')')).match(ARGUMENT_NAMES);
    if (result === null) result = [];
    return result;


const callFunctionFromObject = (func, obj) => 
    let params = getParamNames2(func)
    return func(...params.map(prop => obj[prop]))

示例用法:

//Function declared somewhere:
var logFor*** = (a, b, c) => console.log(a, b, c)

//ex1
callFunctionFromObject(logFor***, a: 1);
1 undefined undefined
//ex2
callFunctionFromObject(logFor***, b: 1)
undefined 1 undefined
//ex3
callFunctionFromObject(logFor***, b: "hello", c:3, a:[1, 2, 3])
[1, 2, 3] "hello" 3

感谢@CertainPerformance。解决方案。 如果您有任何问题,请给我留言。谢谢。

【讨论】:

【参考方案5】:

当对象的属性顺序与函数的参数一致时,您可以使用:

someFunction(...Object.values(obj))

【讨论】:

以上是关于函数调用的对象解构的主要内容,如果未能解决你的问题,请参考以下文章

箭头函数 解构赋值 立即执行函数 (function() )()

解构函数调用

我必须手动解构所有对象吗

Kotlin常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )

Kotlin常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )

函数参数解构赋值