简体   繁体   中英

Converting Typescript to Javascript Best Practices

How would you recommend I convert this JavaScript to TypeScript?

JAVASCRIPT:

function MyClass() {
    var self = this,
        var1 = "abc",
        var2 = "xyz";

    // Public
    self.method1 = function () {
       return "something " + self.var1;
    };

    self.method2 = function (parm1) {
        var x = self.method1();
        return x + " something";
    };

    // Private 
    function func1(parm1, parm2) {
        return parm1 + parm2;
    }
}

This is what I would like to do in TypeScript, or at least how I would expect to write it:

module MyNamespace {
    export class MyClass {

        private var1: string = "abc";
        private var2: string = "xyz";

        constructor() {
        }

        // Public
        public method1() {
            return "something " + self.var1;
        }
        public method2(parm1) {
            var x = this.method1();
            return x + " something";
        }

        // Private 
        private func1(parm1, parm2) {
            return parm1 + parm2;
        }
    }
}

But the generated JavaScript puts everything on the prototype and I will have some "this" scoping issues:

var MyNamespace;
(function (MyNamespace) {
    var MyClass = (function () {
        function MyClass() {
            this.var1 = "abc";
            this.var2 = "xyz";
        }
        // Public
        MyClass.prototype.method1 = function () {
            return "something " + this.var1;
        };
        MyClass.prototype.method2 = function (parm1) {
            var x = this.method1();
            return x + " something";
        };

        // Private
        MyClass.prototype.func1 = function (parm1, parm2) {
            return parm1 + parm2;
        };
        return MyClass;
    })();
    MyNamespace.MyClass = MyClass;
})(MyNamespace || (MyNamespace = {}))

I know I can declare the methods within the constructor, use lambda functions to get "_this" instead of "this", etc. but what are the best practices of "porting to TypeScript"?

But the generated Javascript puts everything on the prototype

I think that's what you want to happen. The only time it creates a "this" issue is when you want to pass the function as a callback. That's a known concern when passing callbacks and when doing so is the right time to worry about it. To me it feels like the JavaScript way and it's better to embrace the system rather than fight it.

If every instance has a unique function closure you're using a lot more memory or at a minimum creating way more work for the optimizer.

I think the porting you have there looks right. You should consider letting class methods stay on the prototype for memory, performance, and reusability reasons. But if you have some methods you really want to be on the instance for the purposes of keeping this , you can use the member initialization + lambda syntax:

class MyClass {
    greeting = 'hello, ';

    /** someFunc is safe to use in callback positions */
    someFunc = (msg: string) => {
        console.log(this.greeting + msg);
    }
}

JavaScript determines the value of this when calling/invoking the method, not when you declare it. https://stackoverflow.com/a/16063711/1641941 (under "The this variable")

To set the right context you can use =>

class MyClass {
    greeting = 'hello, ';
    someFunc(msg: string) {
        console.log(this.greeting + msg);
    }
}

var m = new MyClass();
setTimeout(() => {m.someFunc("hello")},100);

setTimeout will be passed a closure that is created in the current scope.

If you were to set an interval or event handler and the current scope has a very large irrelevant variable(s) in it then it's better to declare a function that returns the closure somewhere outside of the current scope and pass it the only the variables that are relevant for this closure.

Code that will return a closure function for you and limit scope:

class MyClass {
    greeting = 'hello, ';
    someFunc(msg: string) {
        console.log(this.greeting + msg);
    }
    public static closures ={
        someFunc(me:MyClass,msg:string){
            return function(){
                me.someFunc(msg);
            };
        }
    }
}

var m = new MyClass();
setTimeout(MyClass.closures.someFunc(m,"hello"),100);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM