【问题标题】:Understanding Complex Scope in Javascript Modules and Plugins了解 Javascript 模块和插件中的复杂范围
【发布时间】:2015-08-27 18:13:12
【问题描述】:

我知道 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) 与它的 完全相同在初始化函数中。

更具体地说,我遇到的问题是,当代码位于 Ajax 处理程序内部时,“onChange”处理程序永远不会触发,但插件实例仍然被创建并正常运行。但是,如果我将其移至 init(),onChange 处理程序将触发而无需对代码进行任何其他更改

如果能帮助我解决这个问题,我们将不胜感激。谢谢!

【问题讨论】:

    标签: javascript jquery scope


    【解决方案1】:

    我遇到了类似的问题,您开始使用物体追逐自己的尾巴。

    使用模块的强大之处在于它们有自己的上下文。所以一旦编译,文件就知道里面有什么 vars 和 funcs;这消除了跟踪 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();
        });
      }
    }
    

    【讨论】:

    • 还想补充一点,在调用具有不同上下文的函数时,使用 bindcall 和/或 apply 比使用 hacky var 缓存 this 更容易self_thisthat
    • 我唯一的问题是,“module.exports”应该更像这样,对吧:module.exports = init; ?
    • 几乎是:module.exports = init;,即没有括号。编辑,我写这篇文章时你改变了你的评论,所以忽略。
    猜你喜欢
    • 1970-01-01
    • 2021-07-02
    • 2013-08-10
    • 2012-08-09
    • 2012-08-09
    • 2019-08-20
    • 2022-01-17
    • 2015-11-01
    • 2014-01-20
    相关资源
    最近更新 更多