||

Vue开发中为什么需要对箭头函数保持警惕

对 Vue 原理和 JS 基础不够了解的话,有时会遇到看似比较怪异的问题,比如在 Vue 的 watch 或者 methods 中使用箭头函数,被报 this.xxx is undefined 的。遇到的同学可能通过修改箭头函数为 function 匿名函数或者具名函数就解决了,但其中的原理是什么,本文就来介绍一下。

Vue 中的 watch

Vue 中的实例,比如以组件实例为例,在定义时我们往往需要定义一些对象,比如 propsmethodsdatawatch、computed ,尤其是 methods、watch 和 computed 之类的对象,其字段组成都是函数,一般我们直接使用具名函数来定义,比如 watch 中:

watch: {
  counter(newval) {
    // do something
  }
}

这里的 counter 就是具名的,还有一些情况,我们会使用 key value 的形式来定义,例如:

watch: {
  counter(newval) {
    // do something
  },
  'person.name': function(newval) {
    // do something
  }
}

在这个代码中,person.name 是通过 key value 的形式定义的,其中 value 是一个 function 匿名函数。

往往问题就出在这里,对于不知道箭头函数和普通 function 函数区别的同学,可能这里为了简单会写成箭头函数的形式,而如果箭头函数里使用 this 访问了当前 Vue 实例,就可能会报 this.xxx is undefined 的错误。

同样的问题也可以扩展到 methodscomputed 中的定义。

Vue 中对 this 代理

Vue 中除了对数据 data 的代理外,也存在对当前 Vue 实例的一些访问代理,具体表现为在 methods 、watch 和 computed 中使用 this.xxx 可以直接访问 data 、props 和 methods 中的定义,而无需 this.data.xxx 或者 this.methods.xxx。

注意到这点的同学可能对其中的原理有所猜想,比如将 methods、data、watch、props 和 computed 中的数据挂载一份到当前的 Vue 实例中,但这并非是通过编译挂载实现的,因为我们如果枚举 this ,其实是拿不到上述属性中的对象值的。

其实这里面 Vue 依然使用了代理的思维,在 2.x 中为 Object.defineProperty ,在 3.x 中为 Proxy ,但其实现的目的是一样的,就是将对 this.xxx 的访问重定向到 this.data.xxx 或者 this.methods.xxx 上。

function redirectProxy(instance, target) {
  Object.keys(target).forEach(k => {
    Object.defineProperty(instance, k, {
      get() { return target[k] },
      set(val) { target[k] = val }
    });
  });
}

通过调用上面的方法,可以将 instance.xxx 的访问定向到 target.xxx 上,比如:

redirectProxy(this, this.data);

执行后,我们访问 this.counter 的时候时候实际上访问的是 this.data.counter 。

这跟箭头函数有什么关系?

箭头函数

箭头函数最大的特定,就是它没有自己的 this ,因为它本质上是一种匿名函数,在语义上它的作用域就在其代码块内,由于这个特性,箭头函数没有办法作为构造函数使用。

由于箭头函数没有 this ,所以也就无法改变其 this ,也就是通过 bind 、call、apply 去改变一个箭头函数的 this 指向时,最终都不会成功。

而在 Vue 中,由于需要在 this 中访问到 data 和 methods 中的值,就需要对函数的 this 指向最定义,vue 中使用 call 方法来完成这一步,但由于箭头函数的特点,这个指向其实是失败的,this 最终都指向了一个空对象,这也就导致 this.xxx 永远都是 undefined 。

总结

在 Vue 中并不是不能使用箭头函数,而是由于 Vue 中对一些函数初始化的原因,这些函数需要被 call 重新指定 this ,而箭头函数将得不到真正的 this,这是导致错误的根本原因。

真实开发中,必须做到知其然,也要知其所以然。

类似文章