首页 > 解决方案 > 将回调作为值传递和作为扩展箭头函数传递之间的区别

问题描述

传递回调时,按值执行:

utility.subscribe(this.callback);

与将其作为扩展形式传递不同吗?

utility.subscribe(arg => this.callback(arg));

我理解它们是等效的,但是当需要将上下文与回调一起传递时遇到了问题。

var utility = {
  name: 'utility',
  subscribe(callback) {
    var msgForCallback = 'Hey callback!';
    callback(msgForCallback);
  }
}

var user = {
  name: 'user',
  useSubscriber() {
    utility.subscribe(
      this.callback
    );
  },
  useSubscriberWithArrow() {
    utility.subscribe(
      arg => this.callback(arg)
    );
  },
  callback (arg) {
    console.log(`Context: ${this.name}`);
    console.log(`The utility says: ${arg}`);
  }
}

console.log('\nCall user.useSubscriber();');
user.useSubscriber();
console.log('\nCall user.useSubscriberWithArrow();');
user.useSubscriberWithArrow();

我意识到回调函数是一个常规函数,这就是上下文可能丢失的原因。所以我尝试将其更改为箭头函数,但即使是带有扩展回调的调用也会丢失上下文。

callback: (arg) => { .. }

代替

callback (arg) { .. }

var utility = {
  name: 'utility',
  subscribe(callback) {
    var msgForCallback = 'Hey callback!';
    callback(msgForCallback);
  }
}

var user = {
  name: 'user',
  useSubscriber() {
    utility.subscribe(
      this.callback
    );
  },
  useSubscriberWithArrow() {
    utility.subscribe(
      arg => this.callback(arg)
    );
  },
  callback: (arg) => {
    console.log(`Context: ${this.name}`);
    console.log(`The utility says: ${arg}`);
  }
}

console.log('\nCall user.useSubscriber();');
user.useSubscriber();
console.log('\nCall user.useSubscriberWithArrow();');
user.useSubscriberWithArrow();

标签: javascript

解决方案


  1. 要了解您的代码有什么问题,您首先必须了解regular function声明和arrow function声明之间的区别。arrow function's this绑定到它的环境this(即它被定义的地方)。

  2. 其次,您必须了解, a 中的函数object method不指向'this' of the object,而是指向global thisie,如下所示:

let obj = {
  someMethod() {
    function someFun() {
      // here 'this' points to 'global this'
      // i.e. 'this' does not points to obj
    }
  }
}

我想以上几点很清楚......

现在,来到你的代码:

首先重写callbackregular function. 不要把它写成arrow.

我在下面的代码中提供了更多的行(用于调试目的):

let utility = {
  name: 'utility',  
  subscribe(callback) {
    let msgForCallback = 'Hey callback!';
    callback(msgForCallback);
  }
};


let user = {
  name: 'user',

  useSubscriber() {
    utility.subscribe(this.callback);
  },

  useSubscriberWithArrow() {
    utility.subscribe(arg => this.callback(arg + " With Arrow Huh "));
  },

  callback(arg) {
    console.log('this: ');
    console.log(this);
    console.log("-----------");
    console.log(`Context: ${this.name}`);
    console.log(`The utility says: ${arg}`);
    console.log("__________________________________________________________________________");
  }
};


console.log('\nCall user.useSubscriber();');
user.useSubscriber();

console.log('\nCall user.useSubscriberWithArrow();');
user.useSubscriberWithArrow();

我们将讨论上面给出的代码有什么问题。

this.name代码的错误是 user.useSubscriber() 在被调用时将无法解析callback

为什么?

注意:user.callback()不是arrow函数,而是常规函数并传递给utility.subscribe(). 所以,它变成了,就像我上面描述的第二点一样,function with in object method,所以,this将绑定到global this。您可以通过运行代码来证明这一点。代码的输出有点像下面(我已经测试过node v10.16.*):

Call user.useSubscriber();
this:
Object [global] {
  DTRACE_NET_SERVER_CONNECTION: [Function],
  DTRACE_NET_STREAM_END: [Function],
  DTRACE_HTTP_SERVER_REQUEST: [Function],
  DTRACE_HTTP_SERVER_RESPONSE: [Function],
...
...
-----------
Context: undefined
The utility says: Hey callback!
__________________________________________________________________________

Call user.useSubscriberWithArrow();
this:
{ name: 'user',
  useSubscriber: [Function: useSubscriber],
  useSubscriberWithArrow: [Function: useSubscriberWithArrow],
  callback: [Function: callback] }
-----------
Context: user
The utility says: Hey callback! With Arrow Huh
__________________________________________________________________________

我想,这解决了问题。

现在,为什么user.useSubscriberWithArrow()有效

它有效,请记住我在第一点中讨论过的内容 - arrow function is bind to it's environments 'this'(i.e. where it is defined)。所以,你传递了一个arrow函数 as callback,而不是user.callback()它本身,它arrow function用于调用this.callback(). 并且,arrow's this绑定到user,因为它是在user对象中定义的。

我想这可以解决你的问题。如果您还有问题,请在评论中问我...


推荐阅读