最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - TypeScript - how to inherit class and override lambda method - Stack Overflow

programmeradmin3浏览0评论

I have an inherited class, and need the parent to have a virtual method, which is overridden in the child class. This method is called from the base constructor, and needs access to instance properties, so it needs to be a lambda function, so "this" is "_this". The problem is, overriding a lambda method does not work for me like overriding a non-lambda does. Is this possible? If not, I'd like to understand why.

Also, will "this" always be the same as "_this" when the method is only called from the constructor?

class Base {
    protected prop = null;
    constructor() {
        this.init();
        this.initLambda();
    }
    init() {
        console.log("Base init");
    }
    initLambda = () => {
        console.log("Base initLambda");
    }
}
class Derived extends Base {
    constructor() {
        super();
    }
    init() {
        console.log("Derived init");
    }
    initLambda = () => {
        //let x = this.prop;
        console.log("Derived initLambda");
    }
}

Output:
Derived init
Base initLambda

I have an inherited class, and need the parent to have a virtual method, which is overridden in the child class. This method is called from the base constructor, and needs access to instance properties, so it needs to be a lambda function, so "this" is "_this". The problem is, overriding a lambda method does not work for me like overriding a non-lambda does. Is this possible? If not, I'd like to understand why.

Also, will "this" always be the same as "_this" when the method is only called from the constructor?

class Base {
    protected prop = null;
    constructor() {
        this.init();
        this.initLambda();
    }
    init() {
        console.log("Base init");
    }
    initLambda = () => {
        console.log("Base initLambda");
    }
}
class Derived extends Base {
    constructor() {
        super();
    }
    init() {
        console.log("Derived init");
    }
    initLambda = () => {
        //let x = this.prop;
        console.log("Derived initLambda");
    }
}

Output:
Derived init
Base initLambda

Share Improve this question asked Jul 28, 2016 at 15:39 user210757user210757 7,38618 gold badges74 silver badges120 bronze badges 3
  • 1 Why does it need to be a "lambda"? – Nitzan Tomer Commented Jul 28, 2016 at 15:44
  • @NitzanTomer - I typically use the "instance arrow function" when the function needs access to "_this", to ensure I always have the correct context. – user210757 Commented Jul 28, 2016 at 16:01
  • I don't believe the arrow function are going to do what you think. The this in them is going to be the this of whatever surrounding environment happens to be. You say * This method is called from the base constructor, and needs access to instance properties, so it needs to be a lambda function, so "this" is "_this"*, but I don't think you understand how derived classes. A method called in the constructor will always invoke the version on the base class if it exists, even when it is defined in the normal way. – user663031 Commented Jul 28, 2016 at 17:52
Add a comment  | 

3 Answers 3

Reset to default 14

Well, you can't have that.
There's an issue that was opened but it was closed as "by design".

You should use regular methods:

class Base {
    protected prop = null;

    constructor() {
        this.init();
        this.initLambda();
    }

    init() {
        console.log("Base init");
    }

    initLambda() {
        console.log("Base initLambda");
    }
}

class Derived extends Base {
    constructor() {
        super();
    }

    init() {
        console.log("Derived init");
    }

    initLambda() {
        console.log("Derived initLambda");
    }
}

And then it will work.

As for keeping the right this, you can always pass a call to the method as an arrow function:

doit() {
    setTimeout(() => this.init(), 1);
}

Or use the Function.prototype.bind function:

setTimeout(this.init.bind(this));

Also, the _this thing that the typescript compiler produces is just a hack to polyfil the arrow functions for ES5, but if you change the target to ES6 then it won't use it.


Edit:

You can save the bound methods as members:

class Base {
    ...
    public boundInit: () => void;

    constructor() {
        ...
        this.boundInit = this.initLambda.bind(this);
        setTimeout(this.boundInit, 500);
    }

...

With that, when I do new Derived() this is what I get:

Derived init
Derived initLambda // after 200 millis

The problem is that your lambda is a property.

When compiled to javascript, the Baseclass becomes

var Base = (function () {
    function Base() {
        this.prop = null;
        this.initLambda = function () {
            console.log("Base initLambda");
        };
        this.init();
        this.initLambda();
    }
    Base.prototype.init = function () {
        console.log("Base init");
    };
    return Base;
}());

As you can see initLambda is defined inside the constructor of Base, so there is no way you can override that.

Calling super() calls the Base constructor which defines the this.initLambda with the code in Base and runs it. Hence your result.

View on playground

Try using using a getter property.

i.E.

get initLambda() {
    return () => {
        console.log("...");
    }
}

In such way that the whole code looks like that:

class Base {
    protected prop = null;
    constructor() {
        this.init();
        this.initLambda();
    }
    init() {
        console.log("Base init");
    }
    get initLambda() {
        return () => {
            console.log("Base initLambda");
        }
    }
}
class Derived extends Base {
    constructor() {
        super();
    }
    init() {
        console.log("Derived init");
    }
    get initLambda() {
        return () => {
            //let x = this.prop;
            console.log("Derived initLambda");
        }
    }
}
发布评论

评论列表(0)

  1. 暂无评论