为什么数组有时通过值传递而不是通过值传递? [英] Why does an array get passed by value some times and not others?

查看:62
本文介绍了为什么数组有时通过值传递而不是通过值传递?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释JavaScript中的这种奇怪行为吗?我以为我了解按引用传递和按值传递的工作方式,但是JavaScript在处理方式上似乎有所不同。两个简单的例子:

Can anyone explain to me this strange behavior in JavaScript? I thought I understood how pass-by-reference and pass-by-value worked, but JavaScript seems to alternate in how it handles this. Two simple examples:

var arr = [1, 2, 3];
function reassign(array) { 
  array = [1, 1, 1]; 
}
reassign(arr);
console.log(arr) // [1, 2, 3]

var arr2 = [1, 2, 3];
function withSplice(array) { 
  array.splice(1, 1); 
}
withSplice(arr2);
console.log(arr2) // [1, 3]

我的想法在哪里处理失败了吗?我觉得重新分配功能正在接收数组的副本,因此重新分配对原始数组没有任何作用,但是 withSplice方法似乎可以接收实际的数组。是什么赋予了?

Where is my thought process failing with this? I feel like the 'reassign' function is receiving a copy of the array, so the reassignment does nothing to the original, but then the 'withSplice' method seems to receive the actual array. What gives? Thanks in advance!

推荐答案


为什么数组有时通过值而不是其他值传递?

Why does an array get passed by value some times and not others?

不是。在两种情况下,对数组的引用(按值)传递到函数中。在第一个代码段中,然后替换 array 变量中的引用以及对新数组的引用; array 变量与您的 arr 变量无关,后者始终引用旧数组。在第二个代码段中,修改原始数组的 state ,该数组都同时包含 array arr 是指。

It doesn't. A reference to the array is passed (by value) into the function in both cases. In your first snippet, you then replace the reference in your array variable with a reference to a new array; that array variable has nothing to do with your arr variable, which keeps referring to the old array. In your second snippet, you modify the state of the original array that both array and arr are referring to.

(有关术语按值传递和按引用传递的更多信息,其含义如下。)

让我们退后一秒,然后我们来看一下您的摘录。

Let's step back for a second, and then we'll look at your snippets.

在JavaScript中(与许多语言一样),变量仅包含原始值,例如(例如)数字15。一种原始值是 reference 数组或其他类型的对象,该对象存在于变量中的其他位置。这些引用是我们从来没有直接看到过的值,它们告诉JavaScript引擎在内存中其他地方可以找到数组/对象。

In JavaScript (as in many languages), variables contain only primitive values, like (say) the number 15. One kind of primitive value is a reference to an array or other kind of object, which exists elsewhere in memory from the variable. These references are values we never see directly that tell the JavaScript engine where to find the array/object elsewhere in memory.

所以说我们有这段代码:

So say we have this code:

var n = 15;
var a = [1, 2, 3];

以下是我们在内存中获得的一些ASCII艺术:

Here's some ASCII-art for what we get in memory:


+−−−−−+
|  n  |
+−−−−−+
| 15  |
+−−−−−+

+−−−−−−−−−−−−−−+
|      a       |     +−−−+
+−−−−−−−−−−−−−−+     | 1 |
| (ref #123)   |−−−−>| 2 |
+−−−−−−−−−−−−−−+     | 3 |
                     +−−−+

n 包含值15; a 包含一个对象引用,该对象指向内存中其他位置的数组。

n contains the value 15; a contains an object reference that points to the array, elsewhere in memory.

当您将变量的值传递给函数(或将其分配给另一个变量等)时,将在其中创建原始值的副本。对于对象引用,复制的值是对象引用;然后,引用的两个副本都引用同一对象。因此,如果我们这样做:

When you pass a variable's value into a function (or assign it to another variable, etc.), a copy of the primitive value in it is made. The value that's copied in the case of object references is the object reference; both copies of the reference then refer to the same object. So if we do this:

var m = n;
var b = a;

我们得到:


+−−−−−+
|  n  |
+−−−−−+
| 15  |
+−−−−−+

+−−−−−+
|  m  |
+−−−−−+
| 15  |
+−−−−−+

+−−−−−−−−−−−−−−+
|      a       |
+−−−−−−−−−−−−−−+
| (ref #123)   |−−+
+−−−−−−−−−−−−−−+  |  +−−−+
                  |  | 1 |
                  +−>| 2 |
+−−−−−−−−−−−−−−+  |  | 3 |
|      b       |  |  +−−−+
+−−−−−−−−−−−−−−+  |
| (ref #123)   |−−+
+−−−−−−−−−−−−−−+

在这两种情况下,变量的值都被复制到新变量中。

In both cases, the value of the variable was copied to a new variable.

那么您的摘要中发生了什么?

So what's happening in your snippets, then?

在第一个代码段中,您为 array 变量(参数)提供了 new 值,该值是对新数组,与原始数组分开。由于 array 变量与 arr 变量没有关系,因此 arr 仍然引用原始数组。

In the first snippet, you're giving the array variable (argument) a new value, a reference to a new array, separate from the original array. Since the array variable has no connection to the arr variable, arr still refers to the original array.

在第二个片段中,您正在更改原始数组的 state ,而不是 array 变量的值。由于 array arr 都引用相同的数组,因此无论您使用哪个引用副本,都可以看到修改后的状态

In the second snippet, you're changing the state of the original array, not the array variable's value. Since both array and arr refer to that same array, you see that modified state regardless of which copy of the reference you use to look at it.

更多ASCII艺术:

在您的第一个代码段中,您首先从内存中开始:

In your first snippet, you start out with this in memory:


+−−−−−−−−−−−−+
|    arr     |     +−−−+
+−−−−−−−−−−−−+     | 1 |
| (ref #123) |−−−−>| 2 |
+−−−−−−−−−−−−+     | 3 |
                   +−−−+

然后,当您输入重新分配函数之前,在 array = [1,1,1]; 行中,您具有:

Then when you enter your reassign function before the array = [1, 1, 1]; line, you have:


+−−−−−−−−−−−−+
|    arr     |
+−−−−−−−−−−−−+
| (ref #123) |−−+
+−−−−−−−−−−−−+  |  +−−−+
                |  | 1 |
                +−>| 2 |
+−−−−−−−−−−−−+  |  | 3 |
|    array   |  |  +−−−+
+−−−−−−−−−−−−+  |
| (ref #123) |−−+
+−−−−−−−−−−−−+



变量包含对该数组引用的副本。

Each variable contains a copy of the reference to the array.

然后在之后 array = [1,1,1 ]; 行中的 reassign 函数,但是在返回之前,您已经:

Then after the array = [1, 1, 1]; line in your reassign function but before it returns you have:


+−−−−−−−−−−−−+
|    arr     |     +−−−+
+−−−−−−−−−−−−+     | 1 |
| (ref #123) |−−−−>| 2 |
+−−−−−−−−−−−−+     | 3 |
                   +−−−+

+−−−−−−−−−−−−+
|    array   |     +−−−+
+−−−−−−−−−−−−+     | 1 |
| (ref #456) |−−−−>| 1 |
+−−−−−−−−−−−−+     | 1 |
                   +−−−+

如您所见,现在变量引用了 different

As you can see, now the variables have references to different arrays.

然后您的函数返回,并且 array 变量消失,最终创建的数组是垃圾-

Then your function returns and the array variable goes away, and eventually the array you created is garbage-collected.

在您的第二个片段中,您从同一件事开始,何时您进入 withSplice 函数之前,调用 splice 之前,您有相同的想法您以前做过:

In your second snippet, you start out with the same thing, and when you go into your withSplice function before the call to splice, you have the same thing you did earlier:


+−−−−−−−−−−−−+
|    arr     |
+−−−−−−−−−−−−+
| (ref #123) |−−+
+−−−−−−−−−−−−+  |  +−−−+
                |  | 1 |
                +−>| 2 |
+−−−−−−−−−−−−+  |  | 3 |
|    array   |  |  +−−−+
+−−−−−−−−−−−−+  |
| (ref #123) |−−+
+−−−−−−−−−−−−+

然后您执行您的 splice ,更改数组的状态,您就会得到:

Then you execute your splice, changing the state of the array, and you have this:


+−−−−−−−−−−−−+
|    arr     |
+−−−−−−−−−−−−+
| (ref #123) |−−+
+−−−−−−−−−−−−+  |
                |  +−−−+
                +−>| 1 |
+−−−−−−−−−−−−+  |  | 3 |
|    array   |  |  +−−−+
+−−−−−−−−−−−−+  |
| (ref #123) |−−+
+−−−−−−−−−−−−+

两个变量所指向的数组的 state splice 更改。

The state of the array both variables point to was changed by splice.

这些术语在计算机科学中具有非常特殊的含义:它们指的是将变量传递给函数时会发生什么:传递值表示传递了变量的 value ;函数完全不了解变量,只知道值。引用传递是指对变量的引用;然后,该函数可以访问并修改变量的值,以便调用代码可以看到更改。因此,如果我有一个变量,其中包含 15 并将该(通过引用)传递给一个函数,该函数可以将变量的值更改为 20 并让更改不仅显示在函数中,还显示在函数返回时调用它的代码中。与上面的讨论完全不同,引用一词的用法也很丰富,但产生了很多误解。 :-)

These terms have a very specific meaning in computer science: They refer to what happens when you pass a variable into a function: Pass-by-value means that the variable's value is passed; the function has no knowledge at all of the variable, just the value. Pass-by-reference means a reference to the variable is passed; the function could then reach up and modify the variable's value such that the calling code would see the change. So if I had a variable with 15 in it, and passed that by reference into a function, the function could change the variable's value to 20 and have that change show up not just within the function, but also in the code that called it when the function returned. It's a completely different usage of the word "reference" from our discussion above, but a rich source of misunderstanding. :-)

JavaScript纯粹是传递值。与C ++或C#不同,它根本没有任何传递引用功能。

JavaScript is purely pass-by-value. Unlike, say, C++ or C#, it doesn't have any pass-by-reference features at all.

这篇关于为什么数组有时通过值传递而不是通过值传递?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆