【问题标题】:ES6 + Angular Controller class, getting this is undefined in callbackES6 + Angular Controller 类,回调中未定义
【发布时间】:2016-08-30 14:36:38
【问题描述】:

考虑下面的类

class LoginController{
    constructor(authService,$timeout,$state){
        let vm = this;
        this.loading = false;
        this._authService = authService;
        this._$timeout = $timeout;
        this._$state = $state;
        this.loading = false;
        this.statusMessage = null;
    }

    login(){
        this.loading = true;
        this.statusMessage = null;

        let loginModel = {
            UserName : this.username,
            Password : this.password,
            RememberMe : this.rememberMe
        };

        //Login User
        this._authService.login(loginModel).then(function(user){
            //Set User Login & send to Dashboard
            this._authService.setUser(user);
            this._$state.go("dashboard");

        }, function(error){
            const errorMessage = error ? error.Message : "Undefined Login Issue occurred !";
            this.loading = false;
        });
    }
}

一切正常,除了我点击了错误回调函数,它到达this.loading = false;,由于某种原因,这是未定义的。

如何在错误回调中保留对“this”类的引用?

【问题讨论】:

  • 您是否已经解决了问题或需要更多帮助?

标签: javascript angularjs class ecmascript-6 webpack


【解决方案1】:

您必须使用粗箭头来保持范围。

//Login User
this._authService.login(loginModel).then((user) => {
    //Set User Login & send to Dashboard
    this._authService.setUser(user);
    this._$state.go("dashboard");
}, (error) => {
    const errorMessage = error ? error.Message : "Undefined Login Issue occurred !";
    this.loading = false;
});

【讨论】:

  • 如果胖箭头在 ES6 中有什么新东西?我曾经将父作用域的 this 定义为 self 或 that。
  • 真的吗?抱歉,我对 ES6 了解不多,但如果我使用 => 我在回调中有相同的 this 实例?真的很奇怪
  • @seahorsepip 是的,我爱他们。它们替换了 self/me/vm/function(){}.bind(this) 代码。
  • @gianlucatursi 这并不奇怪,它是 ES6 的一个很棒的特性 :)(他们从 C# 中借用了这个想法)
  • @NielsSteenbeek 太棒了!非常感谢!这是个好主意(复制):)
【解决方案2】:

这是将上下文传递给回调函数的一个非常常见的问题。通用的答案是声明类似

var self=this; 在您想要保留“this”的上下文中 然后在你的回调函数中像这样引用它

function callback () { self.myvariable=true; };

在您的特定情况下,您已经声明 let vm = this; 所以你可以使用 vm._authService.setUser(user); vm._$state.go("dashboard");

【讨论】:

  • 正如 Niels 所说,您可以使用 ecmascript 6 中的 => 箭头来维护范围,这是合理的,因为您使用需要相同版本的 ecmascript 的“let”关键字。
【解决方案3】:
function(error){
    this.loading = false;
}

函数内部的 this 是一个不同的作用域,所以 this 指的是函数而不是父函数。

解决方案,

将此定义为自我:

class LoginController{
    constructor(authService,$timeout,$state){
        let vm = this;
        this.loading = false;
        this._authService = authService;
        this._$timeout = $timeout;
        this._$state = $state;
        this.loading = false;
        this.statusMessage = null;
    }

    login(){
        var self = this; //Define this as self

        this.loading = true;
        this.statusMessage = null;

        let loginModel = {
            UserName : this.username,
            Password : this.password,
            RememberMe : this.rememberMe
        };

        //Login User
        this._authService.login(loginModel).then(function(user){
            //Set User Login & send to Dashboard
            self._authService.setUser(user);
            self._$state.go("dashboard");

        }, function(error){
            const errorMessage = error ? error.Message : "Undefined Login Issue occurred !";
            self.loading = false; //Self refers to this of parent scope
        });
    }
}

【讨论】:

  • 1) ES6 fat-arrows 解决了丑陋的 self/me/vm 变量。 2)您的代码在 then 内仍然失败。
  • 当时我的坏修好了。可惜我的项目还不能使用 ES6,需要支持 IE :'(
  • IE中可以使用babel-polyfill支持Promise。
  • 同样,很多移动设备不支持一些新的 ecmascript 功能,cordova、browserfy 等也不支持=s
  • 很好,我会调查的!尽管我正在编写的一些 jQuery 插件在 ES5 中编写仍然更好,因为 polyfill 会在文件大小中增加几 kB,我尽量在项目中保持最小。如果不增加太多额外的文件大小,也许我将来会转移到 ES6 并将其编译为 ES5。
猜你喜欢
  • 2017-07-06
  • 2016-01-04
  • 2018-07-14
  • 1970-01-01
  • 2019-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-28
相关资源
最近更新 更多