如何从用作回调的其他类方法访问方法?

时间:2019-01-24 05:52:07

标签: javascript

我有以下Javascript类:

class App {

    log_text(text) {
        console.log(text)
    }

    process_response(response) {
        this.log_text(response) // Uncaught TypeError: this.log_text is not a function
        // self.log_text(response) // Uncaught TypeError: self.log_text is not a function
    }

    do_stuff() {
        this.log_text('hello') // OK
    }

    fetch_data() {
        jQuery.get('http://example.com/data/sample.txt', this.process_response, 'text')
    }
}

调用方法do_stuff时,我可以通过调用log_text来访问this.log_text。但是,在此示例中用作process_response的回调处理程序的方法jQuery.get失败了,因为this在该上下文中表示完全不同的对象。

类似地,self.log_text也会引发TypeError。

在此示例中,从log_text调用process_response的可能(或正确的)方法是什么?

3 个答案:

答案 0 :(得分:3)

发生的事情是,您正在传递process_response函数,仅此而已,正如您所看到的那样,这些更改的上下文。一种解决方法是使用箭头语法将其包装,当jQuery触发回调时,它将保留此值。

 fetch_data() {
        jQuery.get('http://example.com/data/sample.txt', (r)=> this.process_response(r), 'text')
    }

答案 1 :(得分:1)

您可以使用Function.bind()来设置process_response函数的上下文

fetch_data() {
  jQuery.get('http://example.com/data/sample.txt', this.process_response.bind(this), 'text')
}

答案 2 :(得分:1)

您可以使用箭头功能,该功能具有词法this-

fetch_data() {
  jQuery.get
    ( 'http://example.com/data/sample.txt'
    , r => this.process_response(r)
    , 'text'
    )
}

或使用Function#bind将上下文(以及可选的一些参数)绑定到函数-

fetch_data() {
  jQuery.get
    ( 'http://example.com/data/sample.txt'
    , this.process_response.bind(this)
    , 'text'
    )
}

或者像历史上一样,用var保存上下文;现在,相对于上述技术而言,它已经不那么受欢迎了-

fetch_data() {
  var ctx = this
  jQuery.get
    ( 'http://example.com/data/sample.txt'
    , function (r) { ctx.process_response(r) }
    , 'text'
    )
}

但是,新的JS功能将改善您的生活质量。考虑将您的 jqXHR 强制为 Promise ,以便您可以使用asyncawait-

const get = (opts = {}) =>
  new Promise
    ( (resolve, reject) =>
        $.get(opts)
         .done((req, status, res) => resolve(res))
         .fail((req, status, err) => reject(err))
    )

结果是代码更加扁平,不再需要许多多余的功能,例如fetch_dataprocess_response。更好的是,我们的思想从绑定功能和动态上下文的思考中解放出来-

class App {

    log_text(text) {
        console.log(text)
    }

    async main () {
      const res = await
        get ({ url: '/data/sample.txt', dataType: 'text' })

      this.log_text(res)
    }

}

您甚至可以为get包装器设置默认选项-

const defaultOpts =
  { dataType: 'text' }

const get = (opts = {}) =>
  new Promise
    ( (resolve, reject) =>
        $.get({ ...defaultOpts, ...opts })
         .done((req, status, res) => resolve(res))
         .fail((req, status, err) => reject(err))
    )

然后使用它-

async main () {
  const res = await
    get ({ url: '/data/sample.txt' })

  this.log_text(res)
  // ...
}