我这里有四个案例,执行结果如注释中所示。我真正不明白的是,在某些情况下,值可以改变,但有些则不能。有谁能提供一个答案,即不变性和可变性如何在 javascript 中为变量赋值?我认为这可能是一个典型的面试问题...但我无法清楚地解释它是如何运作的...
案例1
const x = { a: 1, b: 2 };
function fn1(_x) {
_x.a = 0;
}
fn1(x);
console.log(x);
// { a: 0, b: 2 } mutated
案例2
const y = { a: 1, b: 2 };
function fn2(_y) {
_y = 0;
}
fn2(y.a);
console.log(y);
// { a: 1, b: 2 } not mutated
我从这个示例代码中得到的是,如果没有在函数中显式赋值,则对象属性的值无法更改。
<小时/>案例3
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
的值却没有变化?这是因为 String
和 Number
是不可变的?
根据这些实验,我是否可以假设只有当我将其显式分配给函数中对象的属性时,该值才会更改?我还将假设 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
帕特里克·罗伯茨刚刚指出“先前的”情况 4 是不可变的,我之前没有注意到这一点......但令我感兴趣的是,通过翻转 a.c = 0;< 的顺序
和 a = 0;
,即案例 5 中的 fn4
,输出发生变化...但这就是我存放的位置...对于之前的错误感到抱歉案例 4 中的输出。
最佳答案
在情况 1 中,您将传递对对象的引用并更改其属性之一,而在情况 2 中,您将向函数传递一个值,并改变其属性之一。用它做某事。 _y
是 fn2(_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 中,您是吊装的“受害者”。。该代码不会按照编写的顺序执行。在 JS 中声明任何变量都相当于在封闭范围的顶部声明它。该作用域将是 var
的封闭函数以及 let
和 const
的大括号。前面的代码相当于:
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
属性的引用。
关于Javascript:为什么在某些情况下对象的值会发生变化,而其他情况下将其传递给函数后不会发生变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48532636/