【问题标题】:Angular controllerAs and babelAngular 控制器As 和 babel
【发布时间】:2016-08-01 15:25:24
【问题描述】:

我正在使用 ES6 功能创建一个 Angular 应用程序,所以我使用 Babel 来转译 JS。我决定不使用 ES6 模块,所以我使用的是 es2015-script,而不是常规的 es2015 预设。

问题在于 Babel 编译箭头函数的方式。我用的是Angular的controllerAs记法,像这样

angular.module('appControllers')
.controller('StoryController', ['StoryProvider', (StoryProvider)=>{
    this.plaintext='test plain';
}]);

这段代码被转译为

var _this = this;

angular.module('myControllers')
.controller('StoryController', ['StoryProvider', function (StoryProvider)             
{
    _this.plaintext = 'test plain';
}]);

所以this 在完全错误的范围内并且绑定不起作用。当我手动将编译后的代码更改为

angular.module('myControllers')
.controller('StoryController', ['StoryProvider', function (StoryProvider)             
{
    var _this = this;
    _this.plaintext = 'test plain';
}]);

一切正常。

为什么 Babel 以这种方式设置中间 _this 变量?是否有另一个 Babel 预设可以正确处理这个问题?我应该使用 ES6 模块吗?我首先遇到了与本期angular 1.5 component and babel 中描述的相同的问题,这就是我使用es2015-script 预设的原因。

【问题讨论】:

  • 用常规 function() 替换箭头函数有帮助,但我真的很想使用词法 this。
  • 这段代码似乎没有什么问题;这里使用箭头函数是错误的。控制器被设计为拥有自己的this。箭头函数正在做它设计的事情(词法绑定this 值(不绑定自己的this、arguments、super 或super 或new.target)。),这不是控制器期望被声明。
  • " 但我真的很想用这个词法。"你不能,除非你想使用$scope

标签: javascript angularjs this babeljs


【解决方案1】:

好的,这里有几种方法

1) 使用 ES6 class

class StoryController{
    constructor(StoryProvider){
        this.plaintext='test plain';
        this.StoryProvider=StoryProvider;
    }
}

这增加了大约 1k 的辅助函数,而且如您所见,我们需要在构造函数中保存注入的依赖项。

2) 去掉主控制器定义中的箭头函数,只在方法中使用它。像

function StoryController(StoryProvider){
    this.plaintext='test plain';
    this.asyncTest=()=>{
        setTimeout(()=>{
            console.log(this.plaintext);
        }, 100);
    };
}

这转换成一个不错的

function StoryController(StoryProvider) {
    var _this = this;

    this.plaintext = 'test plain';

    this.asyncTest = function () {
        setTimeout(function () {
            console.log(_this.plaintext);
        }, 100);
    }; 
}

正确限定_this 变量的范围。

【讨论】:

    【解决方案2】:

    您的答案中的替代解决方案似乎有效,但我想提供一个问题的答案:

    为什么 Babel 会这样设置中间的 _this 变量?

    首先,一些背景信息。根据MDN:

    直到箭头函数,每个新函数都定义了自己的 this 值(在构造函数的情况下是一个新对象,在严格模式函数调用中未定义,如果函数被称为“对象方法”,则为上下文对象等) .事实证明,这种面向对象的编程风格很烦人。

    关于胖箭头函数需要理解的是,它们不仅仅是用于创建函数的较短语法——它们创建的函数没有它自己的词法范围。这意味着当您在胖箭头函数中使用this.plaintext 时(在非严格模式下)this 并没有像您期望的那样在 controller 上设置,而是在 全局对象。

    现在关于巴别塔。

    Babel 正在尽最大努力使您的转译代码的行为与源代码完全相同(这就是重点,对吗?)因此,当它必须使用 ES5 兼容的函数声明重写您的胖箭头函数时,它必须拉入从某处对全局对象的引用。因此,在前一行中,它以_this 获取对它的引用,并在你的胖箭头函数中使用它,因为它认为这就是你想要的。


    正如您在问题中所展示的,最简单的解决方案是首先用标准函数声明替换胖箭头函数,这样您就有了一个词法范围来挂东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-16
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      相关资源
      最近更新 更多