Vue2中为何无法直接通过this访问data()内的属性?
报错现象
watcher触发addRegals()方法时控制台抛出错误:
[Vue warn]: Error in callback for watcher "regalsTotalNumber": "TypeError: this is undefined"
直接在方法内通过this.size、this.thetiles访问data()定义的属性会触发报错,只有先把属性赋值给方法内局部变量才能正常运行。
问题根因
这个报错和Vue对data属性的代理逻辑无关,也不是watcher本身的机制缺陷,本质是JavaScript函数的this绑定规则导致的组件实例上下文丢失:
- Vue组件内
methods定义的普通方法、watcher配置的普通函数回调,被Vue框架直接调用时,this会被自动绑定到当前组件实例,所以在方法最顶层作用域访问this.size、this.thetiles是完全正常的——这也是为什么你在方法第一行写var size = this.size不会触发报错。 - 从复现场景看,
addRegals方法内调用了画布/拖拽相关的第三方库API,这些API接收的回调如果是普通function声明的,回调被第三方库执行时,this不会指向Vue组件实例:ES6严格模式下这个值就是undefined,非严格模式可能指向window或者库自身的内部对象,你在这类深层回调里直接写this.size自然会触发报错。 - 你提前把
this.size赋值给方法内局部变量的写法,本质是利用了JavaScript的闭包特性:局部变量会被内部所有回调访问,完全不受回调内部this指向变化的影响,所以代码能正常运行。
修复方案
不需要逐一把用到的实例属性存为局部变量,选任意一种规范写法即可:
- 内部回调统一使用箭头函数
箭头函数没有自身的this上下文,会直接继承外层作用域(也就是addRegals方法层,this指向组件实例)的绑定,回调内可以直接用this访问实例属性:// 错误写法:普通函数回调丢失this renderTiles(function() { console.log(this.size) // 报错,this不是组件实例 }) // 正确写法:箭头函数继承外层this renderTiles(() => { console.log(this.size) // 正常访问 }) - 显式绑定回调的this指向
如果遇到极个别不兼容箭头函数的老库,可以用Function.prototype.bind强制把回调的this绑定到组件实例:renderTiles(function() { console.log(this.size) // 正常访问 }.bind(this)) - 顶层统一缓存实例引用
如果方法内嵌套层级多、逻辑复杂,可以在方法最开头一次性缓存组件实例到局部变量,后续逻辑统一用这个变量访问实例,不用单独缓存每个属性:addRegals() { const vm = this // 固定缓存当前组件实例 renderTiles(function() { console.log(vm.size, vm.thetiles) // 所有属性都能正常访问 }) }
常见同类踩坑
如果watcher本身直接用箭头函数定义,也会出现全局的this丢失,这类写法是错误的:
watch: { // 错误:箭头函数定义时的上下文不是组件实例 regalsTotalNumber: (newVal) => { console.log(this.size) // 直接报this undefined } }
watcher回调请始终用普通函数定义:
watch: { regalsTotalNumber(newVal) { console.log(this.size) // 正常访问 } }
内容的提问来源于stack exchange,提问作者mustafa00
相关产品推荐
相关产品推荐

