我知道Stack上有很多关于JS Scope的问题......但我遇到了一个我无法解决的特定问题。我有一个看起来像这样的Javascript模块(虽然大大简化了):
module.exports = {
$company: $('#id_company'),
$companyCtrl: null,
$jobType: $('#id_job_type'),
$jobTypeCtrl: null,
init: function() {
var _this = this;
this.$companyCtrl = this.$company.selectize({
onChange: function(value) {
_this.companyChanged(value);
}
})[0].selectize;
},
companyChanged: function() {
// Company changed has been fired and does a few things
// before it calls this:
this.updateJobType();
},
updateJobType: function() {
var _this = this;
$.ajax({
url:'/ajax-url',
data: {
'id': this.companyID
}
})
.done(function(data) {
// If our job type selectize() instance hasn't been setup,
// then create it now
if (_this.$jobTypeCtrl === null) {
// ------------
// PROBLEM BLOCK
_this.$jobTypeCtrl = _this.$jobType.selectize({
onChange: function(value) {
if (_this.currentModel !== 'wire_add') {
_this.jobTypeChanged(value);
}
}
})[0].selectize;
// ------------
}
// Reload and re-enable input
_this.$jobTypeCtrl.reloadFromOriginalInput();
_this.$jobTypeCtrl.enable();
});
},
}
现在,这是我不明白的,如果我移动那个"问题块"在Ajax调用之外,并将其重新放入init(),它工作正常。但是,据我所知,在它的当前位置中,范围(_this = this)是完全相同的因为它会在init函数中出现。
更具体地说,我遇到的问题是" onChange"当代码在Ajax处理程序中时,处理程序永远不会触发,但插件实例仍然是创建的,否则应该。但是,如果我将它移动到init(),onChange处理程序将触发而不对代码进行任何其他更改
任何帮助让我绕过这个的人都会非常感激。谢谢!
答案 0 :(得分:1)
我有一个类似的问题,你开始用对象追逐你自己的尾巴。
使用模块的强大之处在于它们有自己的上下文。因此,一旦编译,该文件就知道内部存在哪些变量和函数;这消除了跟踪this
从功能到功能的反弹的需要,一旦你涉及异步回调,这就变成了一场噩梦。
我建议在顶部和函数中使用vars重写模块,这样就可以更轻松地调用任何函数,而无需从此处,那里和任何地方传递正确的_this/self
上下文。
这是一个未经测试的重写:
module.exports = {
var $company = $('#id_company'),
$companyCtrl = null,
$jobType = $('#id_job_type'),
$jobTypeCtrl = null;
function init() {
$companyCtrl = $company.selectize({
onChange: function(value) {
companyChanged(value); // <== invoke any function and treat them as black-box code
}
})[0].selectize;
}
function companyChanged() {
// Company changed has been fired and does a few things
// before it calls this:
updateJobType();
}
function updateJobType() {
$.ajax({
url:'/ajax-url',
data: {
'id': companyID
}
})
.done(function(data) {
// If our job type selectize() instance hasn't been setup,
// then create it now
if ($jobTypeCtrl === null) {
// ------------
// PROBLEM BLOCK
$jobTypeCtrl = $jobType.selectize({
onChange: function(value) {
if (currentModel !== 'wire_add') {
jobTypeChanged(value);
}
}
})[0].selectize;
// ------------
}
// Reload and re-enable input
$jobTypeCtrl.reloadFromOriginalInput();
$jobTypeCtrl.enable();
});
}
}