我正在使用ES6功能创建一个Angular应用程序,所以我使用Babel来转换JS。我决定不使用ES6模块,因此我使用es2015
而不是常规es2015-script
预设。
问题在于Babel编译箭头功能的方式。我使用Angular的控制器作为符号,如此
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
预设的原因。
答案 0 :(得分: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
变量。
答案 1 :(得分:0)
您答案中的替代解决方案似乎有效,但我想提供问题的答案:
为什么Babel以这种方式设置中间_this变量?
首先,一些背景资料。根据{{3}}:
在箭头函数之前,每个新函数都定义了它自己的这个值(在构造函数的情况下是一个新对象,在严格模式函数调用中是未定义的,如果函数被称为“对象方法”则是上下文对象,等等) 。事实证明,这是一种面向对象的编程风格。
要理解胖箭头功能的一点是,它们不仅仅是创建函数的更短语法 - 它们创建了一个函数而没有它自己的词法范围。这意味着当您在胖箭头功能中使用this.plaintext
时(在非严格模式下),this
未按预期在控制器上设置,但在全局对象。
现在关于巴贝尔。
Babel正在做最好让你的转换代码行为与源完全一样(这就是重点吗?)所以当它必须使用ES5兼容的函数声明重写你的胖箭头函数时,它必须拉入从某个地方引用全局对象。因此,在前一行中,它将对它的引用抓取为_this
并在fat-arrow函数中使用它,因为它认为这是你想要的。
正如您在问题中所展示的那样,最简单的解决方案是首先用标准函数声明替换fat-arrow函数,这样您就可以有一个词法范围来挂起。