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
却没有?是因为 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
Patrick Roberts 刚刚指出 'previous' 案例 4 是不可变的,我之前没有注意到这一点....但让我感兴趣的是通过翻转 [=23= 的顺序] 和 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 中,您是 提升 的"victim"。该代码不会按照编写的顺序执行。在 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 中为变量赋值?我认为这可能是一个典型的面试问题......但我无法清楚地解释它是如何工作的......
案例一
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
却没有?是因为 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
Patrick Roberts 刚刚指出 'previous' 案例 4 是不可变的,我之前没有注意到这一点....但让我感兴趣的是通过翻转 [=23= 的顺序] 和 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 中,您是 提升 的"victim"。该代码不会按照编写的顺序执行。在 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
属性的引用。