【问题标题】:Why using push or any array method modifies the original array but assigning it to something else doesn't?为什么使用 push 或任何数组方法会修改原始数组,但将其分配给其他东西却不会?
【发布时间】:2019-10-30 10:38:14
【问题描述】:

我不明白为什么将数组分配给新值不会影响新数组。 我知道“推”会修改原始数组,也可以拼接,而过滤器或切片不会,这不是我的问题。我的问题是为什么分配不。 我查看了旧问题的答案,说它是通过引用传递的,但是如果它是通过引用传递的,那么更改它的值也应该会影响引用。

const modify = (someArray) => {
    // modified my array
    someArray.push(1)
    // modified my original array
    someArray[0] = 'A'

    // didn't modify my array and I want to know why.
    someArray = ['whatever']
}
let myArray = ['a', 'b']
modify(myArray)
console.log(myArray) //  ["A", "b", 1]

【问题讨论】:

  • 我的两个对象(数组)引用内存中的同一个对象,这意味着每当我们修改其中一个对象时,另一个对象也将被修改。这并不意味着我们何时将其中一个重新分配到一个新值,第二个将改变。
  • 所以我们不能重新分配?
  • someArraymyArray 是两个不同的变量,它们引用内存中的同一个对象。当您修改时,someArray myArray 也会被修改。但是当你重新分配它someArray = ['whatever']。然后它不会引用变量myArray
  • 变量是值的容器。有些值可以直接修改(对象是可变的),有些则不能(字符串是不可变的)。分配给变量总是用新值“交换”现有值。注意someArray[0] = 'A'变量赋值。它读取变量,“提取”它包含的值并改变该值(更改数组的第一个元素)。

标签: javascript arrays ecmascript-6


【解决方案1】:

在 Javascript(以及 Java 或 C#)中,默认情况下,所有内容都由 value 传递!

重要的是要知道,价值是什么。这行let myArray = ['a', 'b'] 在内存中创建新数组并将对它的引用放入myArray。现在,myArray 的值是对['a', 'b'] 所在内存的引用。

当您将它传递给modify 函数时,值(即引用)从myArray复制someArray。这意味着someArray 可以访问同一数组的同一内存段,因此更改该数组内的值,但您不能从someArray 更改myArray 的值(即对该数组的引用)。

【讨论】:

  • 我不觉得第一句话对初学者很有用,因为他们不知道“按值”对于像数组这样的对象意味着什么。数组的“价值”是什么?整个对象是否以某种方式通过?副本通过了吗?是否传递了指向对象的指针?所以,你是答案中的主要句子并没有真正解释任何事情,让人感到困惑。描述中最好使用初学者清楚理解的术语。稍后,您会尝试解释哪个更好。
【解决方案2】:

正如我多次向初学者描述的那样,我发现最好将 Javascript 中的对象视为作为指针传递和分配(就像指针在 C/C++ 中的工作方式一样)。所以,当你这样做时:

let a = [1,2,3];
let b = a;

您现在有两个变量,每个变量都有一个指向同一个[1,2,3] 数组的指针。我发现最好考虑数组本身存在,现在您有两个变量,每个变量都指向该数组。当您分配b = a 时,它不会复制数据,它只是将b 指向a 指向的相同数据。

如果您使用a.push(4)a[0] = 9 之类的赋值来修改该数组,则ab 指向的唯一一个数组已被修改。因此,无论您是从 a 还是从 b 访问该数组,您都会看到变化,因为两个变量都指向同一个物理数组对象。

但是,如果您像这样将其他数组重新分配给b

b = [9,8,7];

您刚刚获取了一个新数组并将指向它的指针放在b 中。另一个变量a 仍然指向相同的原始数组。它没有以任何方式改变。

当您像在 modify() 函数中那样将数组作为参数传递时,函数中的函数参数就像上面示例中的 b 变量一样。它只是指向同一个数组的另一个变量。如果您修改数组本身,那么两个变量将指向同一个修改后的数组。但是,如果您将参数变量重新分配为现在指向某个其他数组,则只有该变量会受到影响。

【讨论】:

  • “通过指针传递和分配” 听起来很危险地类似于“通过引用并分配”,这是错误的。此外,对象是引用类型值这一事实似乎与变量的工作方式无关*
  • @FelixKling - 对于知道指针在 C/C++ 中如何工作的任何人,描述与 Javascript 中发生的完全匹配。我用这个模型一遍又一遍地解释它,正是因为在我的答案中没有使用“参考”这个词,这经常让人们感到困惑。在 C/C++ 中,如果 ab 都有一个指向同一个数组的指针,那么通过其中一个对数组内存的任何修改都会修改另一个指向的内容。但是,如果您为b 分配不同的内容,它根本不会影响a 指向的内容。这就是 JS 的工作原理。
  • 是的,我明白了。也许是“by”这个词让我感到困扰。 idk :)
  • @FelixKling - 好的,我从答案中删除了“by”。
【解决方案3】:

['a', 'b'] 是一个数组。 myArray 是一个引用该数组的变量。 someArraymodify 函数的局部变量,它将获取 myArray 的值(即 reference 到您的数组;所以 myArraysomeArray 都引用同一个数组)。如您所述,someArray.push(1)someArray[0] = 'A' 都修改了someArray 引用的数组。 someArray = ["whatever"] 会将someArrayreference 更改为新数组['whatever'],但myArray 仍然引用旧数组。在函数结束时,someArray 变量消失(而['whatever'] 被遗忘,因为不再有任何引用它)。

在 JavaScript 中无法更改传递给函数的变量的引用(例如 C++ 可以);你只能操纵接收到的参考点。

【讨论】:

    猜你喜欢
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 2016-06-25
    • 2016-01-20
    • 2012-11-12
    • 2012-09-30
    相关资源
    最近更新 更多