JavaScript 函数传参机制:为什么是“按共享传递”而非按引用?

听雨眠
听雨眠
发布时间:2026-10-14| 5人浏览过
原创

许多开发者认为 JavaScript 中对象是按引用传递,原始值是传值,但这种理解并不完全准确。本文将详细拆解 JavaScript 的求值策略,揭示其实际采用的"按共享传递"(Call by sharing)机制,解释为何修改对象属性会影响外部变量,但给参数重新赋值却不会改变外部引用。

什么是求值策略?

在计算机科学中,求值策略(Evaluation strategy)决定了编程语言如何计算表达式中的参数并将其传递给函数。常见的分类包括:
- 严格模式:参数在函数调用前立即计算。
- 非严格模式:延迟计算(如惰性求值)。

在 ECMAScript(JavaScript 的核心标准)中,参数采用的是严格的传参策略,即传入的参数在进入函数体之前就已经被计算完毕。

三种核心传参策略对比

1. 按值传递 (Call by Value)

这是最直观的策略。当函数接收参数时,会创建一个参数值的完整副本。函数内部对参数的任何修改都不会影响外部的原始值。

// 伪代码演示
bar = 10
procedure foo(barArg):
    barArg = 20;
end

foo(bar)
print(bar) // 输出: 10 (外部不受影响)

这种方式在处理简单数值类型时效率很高,但对于大型结构体,频繁的内存拷贝会导致性能问题。

2. 按引用传递 (Call by Reference)

在这种策略下,函数接收到的是对象的直接地址引用。参数成为外部变量的别名。无论修改属性还是重新赋值,都会直接影响外部变量。

// 伪代码演示
bar = { x: 10, y: 20 }
procedure foo(barArg):
    barArg.x = 100 // 修改属性
    barArg = { z: 1 } // 重新赋值
end

foo(bar)
print(bar) // 输出: { z: 1 } (外部彻底改变)

这种策略能高效处理大对象,但因为赋予了函数极高的控制权,容易引发意外副作用。

3. 按共享传递 (Call by Sharing) - JavaScript 的真实机制

大多数现代语言(Java、Python、Ruby、JavaScript)实际上使用的策略被称为“按共享传递”,也称为“按对象传递”。这一概念由 Barbara Liskov 于 1974 年提出。

核心规则:
函数接收的是对象引用的副本(Copy of the reference),而非对象本身的副本,也不是原始引用的别名。

  • 修改属性(Mutation):因为副本和原始引用指向堆内存中的同一个对象,所以函数内修改对象属性会反映到外部。
  • 重新赋值(Reassignment):函数内的参数只是一个局部变量名。给它赋新值只是让它指向了另一个地址,这不会影响外部的引用。

让我们通过 JavaScript 的具体行为来验证这一点:

复制代码代码如下:
var obj = { name: 'Initial' };

function modify(arg) {
    // 修改属性:影响外部
    arg.name = 'Modified';
    
    // 重新赋值:不影响外部
    arg = { name: 'New Object' };
}

modify(obj);
console.log(obj.name); // 输出: "Modified"

从内存角度看:
1. obj 绑定到内存地址 A。
2. 调用函数时,arg 也被赋予指向地址 A 的权限(它是副本,但指向相同目的地)。
3. arg.name = 'Modified' 操作的是地址 A 的内容,所以 obj 看到的是变化。
4. arg = ... 让局部变量 arg 转向新的地址 B,但这切断了它与地址 A 的联系,旧的对象(以及外部的 obj)依然稳稳地待在地址 A。

常见的术语误区

“JavaScript 对象是按引用传递的吗?”

这是一个广为流传的错误说法。如果你执行以下代码:

var a = {x: 1};
var b = a; // 此时 a 和 b 共享同一对象
b.x = 2;
console.log(a.x); // 2

b = {y: 3}; // b 换了一个对象
console.log(a.x); // 2 (a 没变!如果是按引用传递,这里逻辑会更复杂或预期不同,但实际上是因为 b 不再是引用而是新绑定)

Brendan Eich(JS 发明者)明确指出:JavaScript 传递的是引用的副本。如果按严格的学术定义,这属于“按共享传递”。但在日常开发交流中,为了简化,人们有时仍笼统地称之为“按值传递”——只不过这里的“值”是一个特殊的“指针值”。

结论

掌握这一概念对于编写健壮的前端代码至关重要。当你试图在函数内部通过重新赋值来重置一个对象时,请记住:你必须返回新对象并重新赋值给外部变量,仅仅改变形参是无效的。

以上就是 JavaScript 函数参数传值机制的详细内容,更多关于 JavaScript 求值策略的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。