丢失对父类的引用

时间:2014-01-02 04:18:59

标签: javascript function reference typescript

我有两个TypeScript类;其中一个有一个方法,它返回对第二个类的实例中的不同方法的引用(是的,有点令人困惑)。这是仍然重新解决问题的最简单的例子(我为那些更喜欢在底部的人包括了编译的JS):

class OuterClass {
    public InnerClassInstance: InnerClass;

    constructor() {
        this.InnerClassInstance = new InnerClass(7); //Create an instance of the inner class
                                                     //7 is just a test value
    }

    public DoStuff(): any { //Return a reference to the instance's method
        return this.InnerClassInstance.DoMoreStuff;
    }
}

class InnerClass {
    public VariableInstance: number; //Keep a variable (this is the main issue)

    constructor(Num: number) {
        this.VariableInstance = Num;
    }

    public DoMoreStuff() {
        alert(this.VariableInstance); //Demonstrate (hopefully) that everything worked
                                      //Displays 'undefined' instead
    }
}

var OuterClassInstance: OuterClass = new OuterClass();
OuterClassInstance.DoStuff()(); //Call DoMoreStuff from the instance in OuterClass

问题是,一旦DoMoreStuff被调用,它似乎已经失去了与它的父类的所有连接。此时,实例InnerClassInstance仍然正确(变量为7),但直接从VariableInstance访问时DoMoreStuff未定义。所有在InnerClass内定义的变量都会发生这种情况。

我错过了某种规格吗?我认为引用会保留它的上下文,但是当从引用中调用它时,它似乎会失去它。

这是JS:

var OuterClass = (function () {
    function OuterClass() {
        this.InnerClassInstance = new InnerClass(7); //Create an instance of the inner class
                                                     //7 is just a test value
    }
    OuterClass.prototype.DoStuff = function () {
        return this.InnerClassInstance.DoMoreStuff;
    };
    return OuterClass;
})();

var InnerClass = (function () {
    function InnerClass(Num) {
        this.VariableInstance = Num;
    }
    InnerClass.prototype.DoMoreStuff = function () {
        alert(this.VariableInstance); //Demonstrate (hopefully) that everything worked
                                      //Displays 'undefined' instead
    };
    return InnerClass;
})();

var OuterClassInstance = new OuterClass();
OuterClassInstance.DoStuff()(); //Call DoMoreStuff from the instance in OuterClass

3 个答案:

答案 0 :(得分:2)

直接调用

DoMoreStuff(即不作为方法调用),因此this获取window全局对象的值。

DoMoreStuff正试图获取window.VariableInstance,这确实是未定义的。

您需要做的工作如下:

var InnerClass = (function () {
    var _this = this;                  // <--- closure for class instance
    function InnerClass(Num) {
        this.VariableInstance = Num;
    }
    InnerClass.prototype.DoMoreStuff = function () {
        alert(_this.VariableInstance); // <--- using class instance
    };
    return InnerClass;
}

在阅读其他响应后,看起来bind()就是解决方案。麻烦的是,它只受ECMA5浏览器支持,因此旧的IE版本不会有它。

bind()的可能替代是:

function bind (proc, _this) {
    if (proc.prototype.bind) return proc.bind (_this);
    return function () { proc.call (_this); };
}

答案 1 :(得分:2)

如果要传递函数,可以使用arrow functions

public DoMoreStuff = () => { // you plan to pass this function around
    alert(this.VariableInstance); //Demonstrate (hopefully) that everything worked
                                  //Displays 'undefined' instead
}

完整的代码:

class OuterClass {
    public InnerClassInstance: InnerClass;

    constructor() {
        this.InnerClassInstance = new InnerClass(7); //Create an instance of the inner class
                                                     //7 is just a test value
    }

    public DoStuff(): any { //Return a reference to the instance's method
        return this.InnerClassInstance.DoMoreStuff;
    }
}

class InnerClass {
    public VariableInstance: number; //Keep a variable (this is the main issue)

    constructor(Num: number) {
        this.VariableInstance = Num;
    }

    public DoMoreStuff = () => { // you plan to pass this function around
        alert(this.VariableInstance); //Demonstrate (hopefully) that everything worked
                                      //Displays 'undefined' instead
    }
}

var OuterClassInstance: OuterClass = new OuterClass();
OuterClassInstance.DoStuff()(); //Call DoMoreStuff from the instance in OuterClass

它不是默认值的原因是它消耗更多内存(因为箭头成员继续this而不是prototype)并且它不是继承友好的(同样{{1 }}与this逻辑)。

答案 2 :(得分:1)

this对象的值由正在使用的方法调用模式确定。当函数作为函数(OuterClassInstance.DoStuff()();)而不是作为方法(object.method())调用时,它将绑定到Global对象。

OuterClass.prototype.DoStuff = function () {
        return this.InnerClassInstance.DoMoreStuff;
};

OuterClassInstance.DoStuff()()与:

相同
var doStuff = OuterClassInstance.DoStuff();
doStuff();

由于Global对象上没有名为VariableInstance的属性,因此会生成undefined

要解决此问题,请使用InnerClass

返回其上下文绑定到Function.prototype.bind实例的函数
OuterClass.prototype.DoStuff = function () {
        return this.InnerClassInstance.DoMoreStuff.bind(this.InnerClassInstance);
};

考虑这个例子:

var o = {
  a: 'asdf',
  method: function () {
    return this.other;
  },
  other: function () {
    alert(this.a);
  }
};

o.method()(); //alerts undefined

method: function () {
    return this.other.bind(this);
}

o.method()(); //alerts asdf