返回

重新理解连续赋值,你的对象能力了解了吗?

前端



没错,重新理解连续赋值,说白了就是连续赋值。

a = {n: 1};
a.x = 100;
console.log(a.x); // 100

a = {n: 2};
console.log(a.x); // undefined

实际上,上边的语句中,var x 只是声明一个 x,然后用 y = 100 的结果值去初始化 x。原因是:a 被重新赋值为 {n:2} 后,a 的引用变成了全新的,而 js 遵循从左向右的执行原则,a.x 拿到的是老的 a 的属性引用,console 输出 undefined 也是情理之中的。

而你可能觉得,如果改成这样就没事了吧:

var a = {n: 1};
a.x = 100;
console.log(a.x); // 100

a = {n: 2, x: 100};
console.log(a.x); // 100

不不不,这样理解还是错了!

第一段代码会打印出 undefined,第二段代码会打印出 100。这是因为,变量 a 是一个引用数据类型,而对于引用数据类型来说,赋值就意味着重新指向了另一块内存地址,即之前指向的内存地址的数据无法再通过 a 访问到了。

具体到第二段代码中,即使 a 重新指向了另一块内存地址,但在新地址中依然有一个 x 的属性,且值为 100,所以 console 打印出的结果依然是 100


在哪里可能会发生连续赋值?

  1. 函数参数:如果向函数传递引用类型的数据,那么函数中的变量其实和函数外的是同一个,只要在函数中改变了该变量,那么函数外的值也会发生改变。

  2. 函数内部:内部函数中的变量可以访问外部函数中的变量,所以如果内部函数中改变了外部函数中的变量,那么外部函数中的值也会发生改变。

  3. 闭包:闭包中的变量可以访问外层函数中的变量,所以如果闭包中的变量改变了外层函数中的变量,那么外层函数中的值也会发生改变。


// 全局变量
var a = {n: 1};

// 函数内部
function func() {
  a.n = 2;
}

func();
console.log(a.n); // 2

// 闭包
function outerFunc() {
  var a = {n: 1};

  function innerFunc() {
    a.n = 2;
  }

  return innerFunc;
}

var inner = outerFunc();
inner();
console.log(a.n); // 2

所以说,连续赋值其实是一个挺危险的操作,因为很容易导致我们意料之外的错误。因此,在使用连续赋值的时候,一定要慎重,最好能明确知道自己想要做什么。


另外,在 js 中,letconst 都是用来声明变量的,但它们和 var 有着本质的区别。letconst 声明的变量都是块级作用域,而 var 声明的变量是全局作用域或函数作用域。这意味着,letconst 声明的变量只能在声明它们的块级作用域内使用,而 var 声明的变量可以在整个函数或全局范围内使用。

所以,如果我们想避免连续赋值带来的问题,那么就可以使用 letconst 来声明变量,这样就可以确保变量不会被意外重新赋值。


最后,希望大家能够对连续赋值有一个更深刻的理解,这样在以后的编程中才能避免一些不必要的错误。