如果所有 JavaScript 类型都是对象,那么为什么要按值传递数字?

If all JavaScript types are objects, then why are numbers be passed by value?

在有关闭包的文章中,您经常会看到在循环内部创建闭包,使用自调用函数将迭代器变量传递给返回的函数表达式,以便在迭代器变量的值周围创建闭包调用自调用函数的时间,而不是循环完成后的值。这是一个例子:

var func = [];

for (var i = 0; i < 3; i++)
{
    func.push((function(j){ return function(){ console.log(j); }; })(i));
}

// Logs 
// 0
// 1
// 2 
// to the console
for (var i = 0; i < func.length; i++)
{
    func[i]();
}

根据我的简单实验,此技术适用于数字和字符串。但是,相同的技术不适用于普通 JavaScript 对象。如果将对象传递给自调用函数并在函数表达式中引用,则对封闭对象的更改在函数表达式中可见,因为传递给自调用函数的值是对对象的引用而不是对象的副本对象,就像数字和字符串一样。

我能理解为什么这种技术不适用于存储对象的变量,但我不明白为什么这种技术适用于数字和字符串,它们的原型链以 Object 结尾。

这是否意味着字符串和数字只是解释器以不同方式处理的对象的特例,或者我是否存在根本性的误解?

首先,"all JavaScript types are objects"是不正确的。原始字符串、数字和布尔值不是对象。

其次,JavaScript 中的所有内容 都是按值传递的。了解 "pass-by-value" 的含义很重要。这意味着当一个函数被调用时,像这样:

var someVariable = something;
someFunction(someVariable); // <--- this is the function call

然后该语言所做的是复制 someVariable 的值并将该副本传递给函数。 "pass-by-reference" 语言会做的是将对该变量的引用传递给函数。因为在按值传递的世界中,变量值的副本被传递给函数,所以函数绝对没有办法修改 someVariable 的值。在 "pass-by-reference" 语言中,确实如此。

在某种程度上,C++ 允许您使用任一参数传递方案。 JavaScript 没有。

在 JavaScript 中变量具有对象引用作为值的事实有时并不意味着该语言是按引用传递的。我知道这似乎是一个愚蠢的学究式区分,但重要的是要理解 "pass-by-value" 和 "pass-by-reference" 是用于描述语言语义的精确术语。如果它们没有确切的含义,那么它们就没有用。


还有一件事:JavaScript 当原始值用作对象时,将字符串、数字和布尔原始值隐式包装在相应字符串、数字和布尔类型的包装器中。这就是当你做一些常见的事情时会发生的事情:

var five = "hello".length

. 运算符的左侧操作数必须是一个对象,因此这里没有特殊情况:原始字符串值隐式提升为 String 实例。 (运行时在幕后真正做了什么,好吧,我们不知道也不应该关心。从概念上讲,创建、使用和丢弃临时包装器对象。)

在 javascript 中有 6 种基本类型:string、number、boolean、null、undefined、symbol - ECMAScript 2015 中的新类型。但是对于这些有 Object 包装器 类原语。除了 nullundefined 之外的所有 6 个都有包装器 类。 Reference 根据 javascript 设计,这些基本类型按值传递而不是按引用传递。