Javascript:为什么在某些情况下对象的值会发生变化,而其他情况下在将其传递给函数后不会发生变化?

Javascript: Why some cases the value of an object are mutated but others are not after passing it to a function?

我这里有四个案例,执行结果如评论中所示。我不太明白的是,在某些情况下,值可以发生变化,但有些则不能。有谁能提供一个答案,即不变性和可变性如何在 javascript 中为变量赋值?我认为这可能是一个典型的面试问题......但我无法清楚地解释它是如何工作的......

案例一

const x = { a: 1, b: 2 };
function fn1(_x) {
    _x.a = 0;
}
fn1(x);
console.log(x);
// { a: 0, b: 2 }          mutated

案例二

const y = { a: 1, b: 2 };
function fn2(_y) {
    _y = 0;
}
fn2(y.a);
console.log(y);
// { a: 1, b: 2 }          not mutated

我从这个示例代码中得到的是,如果对象的 属性 的值没有在函数中明确赋值,则无法更改。


案例三

const z1 = { a: 1, b: 2 };
function fn3({ a }) {
    a = 0;
    a.c = 0;
}
fn3(z1);
console.log(z1);
// { a: 1, b: 2 }          not mutated

案例4

const z2 = { a: {}, b: 2 };
function fn3({ a }) {
    a = 0;
    a.c = 0;
}
fn3(z2);
console.log(z2);
// { a: {}, b: 2 }         not mutated

我对案例 4 的预期是 // { a: {}, b: 2 }。为什么 z2 的值发生了变异,而 z1 却没有?是因为 StringNumber 是不可变的吗?


并且根据这些实验,我是否可以假设只有在函数中将其显式分配给对象的 属性 时该值才会更改?我还将假设 Array 的行为与 Object.

中的行为相同

谢谢!


更新:

案例5

const z2 = { a: {}, b: 2 };
function fn4({ a }) {
    a.c = 0;
    a = 0;
}
fn3(z2);
console.log(z2);
// { a: { c: 0 }, b: 2 }        mutated

Patrick Roberts 刚刚指出 'previous' 案例 4 是不可变的,我之前没有注意到这一点....但让我感兴趣的是通过翻转 [=23= 的顺序] 和 a = 0;,即案例 5 中的 fn4,输出发生了变化...但那是我存货的地方...很抱歉之前案例 4 中的错误输出。

案例 1 中,您正在传递对对象的引用并改变其属性之一,而在案例 2 中,您重新将一个值传递给函数并用它做一些事情。 _yfn2(_y) 范围内的一个变量,它不存在于它之外,调用 fn2(y.a) 与调用 fn2(1) 是一回事,所以,它不是在 y.

上更改任何内容

案例3案例4都使用了新的对象解构语法,这些代码是等价的:

function fn3({ a }) {
    a = 0;
    a.c = 0;
}

function fn3(x) {
    var a = x.a;
    a = 0;
    a.c = 0;
}

因此,在情况 3 中调用 fn3 是按值传递,就像在情况 2 中一样。

情况 4 不改变对象。

更新 案例 5

const z2 = { a: {}, b: 2 };
function fn4({ a }) {
    a.c = 0;
    a = 0;
}
fn4(z2);
console.log(z2);

在情况 5 中,您是 提升 的"victim"。该代码不会按照编写的顺序执行。在 JS 中声明任何变量等同于在封闭范围的顶部声明它。该范围将是 var 的封闭函数和 letconst 的大括号。前面的代码等同于:

const z2 = { a: {}, b: 2 };
function fn4(x) {
   var a = 0;
   x.a.c = 0;
}
fn4(z2);
console.log(z2);

原因是当你声明 a = 0 时它被提升到函数的顶部,而你从参数中得到的 a 是不同的 a,即传递给函数的对象对 a 属性的引用。