jsb 回调的this 如何绑定

cc.Class({
    extends: cc.Component,

    properties: {
        ...
    },

    service: function(message) {

        switch (message) {
            case Const.Socket_JoinRes:
                this.myfunction(response);
                break;
            default:
                break;
        }
    },

    myfunction: function(response) {
        ...    
    },

service 是jsb那边用C++的std::function 回调的
this, 调用到这里时是this.myfunction 不存在.

你是怎么注册回调的,代码发出来看看

    onLoad: function () {
        let socket = User.instance.gameSocket;
        socket.setRoomCallback(this.service);
    }

注册很简单

typedef std::function<void(...)> ccRoomCallback;
setRoomCallback(const ccRoomCallback &callback);

jsb binding是没有问题的(自动binding),回调的数据也是没有问题的.
C++ 那边大概就是这样. 代码现在没在身边.

C++ 那边只是调用一个函数,没有使用调用者,所以 this 肯定不对

var self = this;
socket.setRoomCallback(function () {
    self.service();
});

这样写回调就有问题了, 报错
message is undefined.

typedef std::function<void(std::string)> ccRoomCallback;
void setRoomCallback(const ccRoomCallback &callback);

应该是这样?

var self = this;
socket.setRoomCallback(function (message) {
    self.service(message);
});
1赞

谢谢哈, 就是这样的, 想不到jsb回调要注意这么多地方

再问一句, 可以告诉我这种写法叫什么么, 为什么需要用一个function来封装
而不是直接

var self = this;
socket.setRoomCallback(
    self.service(message);
);

用function封装起来叫闭包。
区别:

  1. socket.setRoomCallback(this.service);会把this.service这个方法当作一个普通的函数传给setRoomCallback当参数,setRoomCallback在调用它的时候,丢失了this。
  2. socket.setRoomCallback(this.service.bind(this));将this绑定在this.service上,可以实现你需要的功能。bind的文档链接
  3. socket.setRoomCallback(this.service(message));这种写法会先执行this.service(message),把它的返回值作为setRoomCallback的参数,不符合你的需求,且message这里应该也未定义。
var self = this;
socket.setRoomCallback(function (message) {
    self.service(message);
});

这种写法利用闭包中可以访问当前作用域变量的特点,把当前作用域中的this用self保存起来,这样不管在其它任何地方调用这个闭包函数,其中的self都是当前作用域的this。这种写法跟方法2的bind作用类似,但据说bind的效率比较低。

3赞

谢谢toddlxt, cocos社会还是多活跃的. 比国内某些开源社区好.

是时候分享我刚刚完成的这个handler类了

用法:

这是回调时的用法,cb是个handler对象: