为何Vue data中带私有字段的类实例调用方法触发私有字段赋值报错
问题原因
这是正常现象。
Vue的响应式系统会对data函数返回的所有属性做响应式转换:Vue 3 会将对象包装为 Proxy 代理,Vue 2 会通过Object.defineProperty重写属性的读写逻辑。你将Foo类的实例声明在data中时,后续通过this.foo拿到的不是原始的类实例,而是经过响应式处理的代理对象。
而JavaScript的私有类字段有严格的访问限制:仅能在类内部访问,且只能作用于类的原始实例,代理对象、继承实例等非原始实例都无法读写私有字段。你调用this.foo.init(2)时,init方法内部的this指向的是响应式代理,不是原始Foo实例,因此触发了私有字段的访问报错。你在mounted中定义局部变量存储实例时,用到的是原始实例没有被代理,所以可以正常运行。
解决方案
方案1:不将类实例放入data
直接将类实例挂载到组件实例上,不要在data中声明,就不会被Vue做响应式处理:
<template> <div class="hello"> <div>{{bar}}</div> </div> </template> <script> import Foo from '../api/foo.js'; export default { created() { // 直接挂载到this,不进入响应式处理流程 this.foo = new Foo() }, data(){ return { bar: '', } }, mounted() { this.foo.init(2); this.bar = this.foo.getBar(); }, } </script>
方案2:用markRaw标记实例跳过响应式处理(Vue 3适用)
如果需要将实例放在data中,可以用Vue提供的markRaw方法标记实例,告知Vue不需要对其做响应式转换:
<template> <div class="hello"> <div>{{bar}}</div> </div> </template> <script> import { markRaw } from 'vue' import Foo from '../api/foo.js'; export default { data(){ return { // markRaw标记后不会被转为响应式代理 foo: markRaw(new Foo()), bar: '', } }, mounted() { this.foo.init(2); this.bar = this.foo.getBar(); }, } </script>
内容的提问来源于stack exchange,提问作者Raphaël
相关产品推荐
相关产品推荐

