如何在Ember模型的函数中访问模型实例?解决调用报错问题
解决Ember模型方法中this.set报错的问题
嘿,作为从Ruby转过来的开发者,我太懂这种“按直觉写却报错”的憋屈了!咱们先搞清楚问题出在哪,再给你搞定它。
首先看你的代码,本身定义turnOn方法的写法其实没问题——Ember模型实例的方法里确实可以用this.set来修改属性。那为啥会报Cannot read property 'set'的错误呢?核心原因是JavaScript里的this上下文和Ruby不一样:
在Ruby里,方法绑定在实例上,不管怎么传递方法,它的上下文都是原实例;但在JS里,函数的this是动态决定的——如果你的turnOn方法不是直接通过模型实例调用(比如把它当成普通函数传递、或者在回调里调用时没绑定上下文),this就会变成undefined或者其他对象,自然找不到set方法。
常见的错误场景和解决办法
场景1:直接解构或单独调用方法
比如你写了这样的代码:const widget = this.store.findRecord('widget', 1); const turnOn = widget.turnOn; turnOn(); // 这里this就不是widget实例了!解决办法:直接通过实例调用方法,或者手动绑定上下文:
// 正确方式1:直接调用 widget.turnOn(); // 正确方式2:绑定this后再传递 const boundTurnOn = widget.turnOn.bind(widget); boundTurnOn();场景2:在action或异步回调中使用
比如在组件的action里调用时,不小心丢失了上下文:// 组件里的错误写法 actions: { activateWidget() { const widget = this.model; setTimeout(widget.turnOn, 1000); // 这里this会丢失 } }解决办法:用箭头函数包裹,或者绑定this:
// 正确写法1:箭头函数保留上下文 actions: { activateWidget() { const widget = this.model; setTimeout(() => widget.turnOn(), 1000); } } // 正确写法2:绑定this actions: { activateWidget() { const widget = this.model; setTimeout(widget.turnOn.bind(widget), 1000); } }
额外的Ember小技巧
如果你的Ember版本比较新(比如Ember Octane及以上),也可以用ES类的写法来定义模型,这样结合箭头函数的话,能更直观地保留上下文:
// 用ES类写法的widget.js import Model, { attr } from '@ember-data/model'; export default class WidgetModel extends Model { @attr('boolean') enabled; turnOn = () => { this.set('enabled', true); } }
这里把turnOn定义为实例的箭头函数属性,不管怎么传递,this都会始终指向模型实例,和Ruby里的方法行为更接近,适合咱们Ruby开发者的习惯~
内容的提问来源于stack exchange,提问作者Argus9
相关产品推荐
相关产品推荐

