打字机回调函数中的'this'范围

时间:2016-05-21 11:12:35

标签: javascript scope typescript callback

我无法理解'this'语境在打字稿中是如何运作的。我无法访问方法中的类成员。以下是我的代码

class adopterDetailCtrl {
    public adopter: IAdopter;
    public $router: any;

    static $inject = ['app.common.services.AdopterService'];
    constructor(private adopterService: app.common.services.IAdopterServices) {
        this.adopter = null;
    }

    $routerOnActivate(next) {
        if (next.params.id > 0) {
            this.getAdopterById(next.params.id);
        }
    }

    getAdopterById(adopterId: number): void {
        var AdopterList = this.adopterService.getAdopterById();
        AdopterList.query({ id: adopterId }, (data: adopter.IAdopter[]) => {
            this.adopter = data[0];//this.adopter is undefined here. this refers to 'window'
        });
    }

    setAdopter(data: IAdopter) {
        this.adopter = data;//can access this.adopter
    }
}

1 个答案:

答案 0 :(得分:3)

this上下文在typescript中与在javascript中的相同,因为您实际运行的代码是typescript编译器输出的已编译的javascript。

在javascript中,您有两种方法可以解决此问题:

  1. 使用arrow function
  2. 使用Function.prototype.bind function
  3. 您可能正在传递getAdopterById作为回调,如果是这样,那么使用bind很容易解决:

    let myobj = new adopterDetailCtrl(...);
    
    ...
    
    someFunction(myobj.getAdopterById.bind(myobj));
    

    您还可以在ctor中修改实例方法的引用:

    (1)

    class adopterDetailCtrl {
        public adopter: IAdopter;
        public $router: any;
    
        static $inject = ['app.common.services.AdopterService'];
        constructor(private adopterService: app.common.services.IAdopterServices) {
            this.adopter = null;
    
            this.getAdopterById = (adopterId: number) => {
                var AdopterList = this.adopterService.getAdopterById();
                AdopterList.query({ id: adopterId }, (data: adopter.IAdopter[]) => {
                    this.adopter = data[0];//this.adopter is undefined here. this refers to 'window'
                });
            }
        }
    
        $routerOnActivate(next) {
            if (next.params.id > 0) {
                this.getAdopterById(next.params.id);
            }
        }
    
        getAdopterById: (adopterId: number) => void;
    
        setAdopter(data: IAdopter) {
            this.adopter = data;//can access this.adopter
        }
    }
    

    请注意,方法声明为空,并且使用箭头函数在ctor中设置实现。

    (2)

    class adopterDetailCtrl {
        public adopter: IAdopter;
        public $router: any;
    
        static $inject = ['app.common.services.AdopterService'];
        constructor(private adopterService: app.common.services.IAdopterServices) {
            this.adopter = null;
    
            this.getAdopterById = this.getAdopterById.bind(this);
        }
    
        $routerOnActivate(next) {
            if (next.params.id > 0) {
                this.getAdopterById(next.params.id);
            }
        }
    
        getAdopterById(adopterId: number): void {
            var AdopterList = this.adopterService.getAdopterById();
            AdopterList.query({ id: adopterId }, (data: adopter.IAdopter[]) => {
                this.adopter = data[0];//this.adopter is undefined here. this refers to 'window'
            });
        }
    
        setAdopter(data: IAdopter) {
            this.adopter = data;//can access this.adopter
        }
    }
    

    在ctor中,您将绑定的this.getAdopterById.bind(this)重新分配给this.getAdopterById

    在这两种情况下,您都可以自由地将getAdopterById方法作为回调传递,而不必担心this的范围。

    关于箭头功能的另一个注意事项是这是ES6中的新功能,如果您不在compilation options中选择ES6目标,则编译器赢了& #39; t实际上使用这种表示法,而是转换它:

    class A {
        private x: number;
    
        fn(): void {
            setTimeout(() => console.log(this.x), 1);
        }
    }
    

    要:

    var A = (function () {
        function A() {
        }
        A.prototype.fn = function () {
            var _this = this;
            setTimeout(function () { return console.log(_this.x); }, 1);
        };
        return A;
    }());
    

    这样this的范围保存在_this中,并使用回调函数_this.x代替this.x