让所有函数只接受由对象包装的参数原语是最有效的吗?

Cod*_*ice -2 javascript pass-by-reference pass-by-value typescript

在 JavaScript(或 TypeScript)中,对象是通过引用传递的,这与在函数中复制的原语不同。因此,是不是这样:

sum(one: number, two: number): number {
    return one + two;
}
Run Code Online (Sandbox Code Playgroud)

总是比这效率低?

sum(input: { one: number, two: number}): number {
    return input.one + input.two;
}
Run Code Online (Sandbox Code Playgroud)

在第一个函数中,'one' 和 'two' 被复制。在第二个函数中,'one' 和 'two' 只是对封装在对象中的原始 'one' 和 'two' 的引用,因此不会进行复制,这样可以节省计算量吗?

当然,如果我需要操纵 'one' 和 'two' 的值并且不希望更改持续存在,我会使用第二个函数。

因此,对于 JavaScript 开发人员来说,将他们的函数参数原语封装在一个对象中(假设他们不希望操作持续存在)不应该始终是建议的最佳实践吗?

T.J*_*der 6

因此,应该是这样的:

sum(one: number, two: number): number {
    return one + two;
}
Run Code Online (Sandbox Code Playgroud)

总是比这效率低:

sum(input: { one: number, two: number}): number {
    return input.one + input.two;
}
Run Code Online (Sandbox Code Playgroud)

那不遵循。

传递给函数的是其参数的。在计算机科学的上下文中,有几种不同的方法来解释“值”,所以我将使用真正非常实用的方法:运行时进入变量、堆栈等的位。

将值传递给函数非常有效。您将它们压入堆栈,函数将它们从堆栈中弹出。所以

sum(1, 2);
Run Code Online (Sandbox Code Playgroud)

做这个:

  • 1入堆栈。
  • 2入堆栈。
  • 调用函数,其中
    • 从堆栈中弹出值
    • 将它们加在一起
    • 将返回值压入堆栈
    • 返回

(甩开一些细节!)

在您的第二个示例中,要调用sum,您必须创建一个对象

sum({one: 1, two: 2});
Run Code Online (Sandbox Code Playgroud)

所以它这样做:

  • 为对象分配内存。
  • 创建一个属性,用插槽来记住它的名称"one"和值;将值1放入值槽中。
  • 创建第二个属性,用插槽来记住它的名称"two"和值;将值2放入值槽中。
  • 将该对象的引用(一个值,粗略地说,它在内存中的位置)压入堆栈。
  • 调用函数,它:
    • 从堆栈中弹出对象引用。
    • "one"在对象中查找属性并将其值放在局部变量中(有趣的是,它可能会在堆栈中)。
    • "two"在对象中查找属性并将其值放在局部变量中。
    • 将它们加在一起
    • 将结果压入堆栈
    • 返回

因此,您节省了一次 push/pop,但代价是分配一个对象并在其上填充两个属性,然后稍后查找这些值;所有这些都比堆栈操作更昂贵。

现在,在 JavaScript 中,我们创建了很多发布对象,因此引擎非常擅长。如果您有一个函数,最适合将对象传递给它,那么一定要这样做。(例如:如果函数需要三个以上的信息来完成它的工作,让它们传递具有命名属性的对象而不是让它们记住参数的顺序通常是更好的开发体验,尽管当然IDE 有帮助)。