【问题标题】:es6 template string + short object literal transpilation failed [gulp, babel]es6 模板字符串 + 短对象文字转译失败 [gulp, babel]
【发布时间】:2016-10-24 16:45:46
【问题描述】:

我有一个非常小的 ES6 代码:

var name = "MyName";
var version = "1.2.3";

var theThing = {
  name,
  version,
  run: () => {
    console.log(`You're using ${this.name}@${this.version}`);
  }
};

theThing.run();

当我在浏览器控制台(chrome 53)中运行它时,我得到了预期的结果:You're using MyName@1.2.3 被记录到控制台。两个模板字符串都与缩短的对象文字语法一起使用。

但是,当我尝试使用 gulp/babel 将此代码转换为 ES5 时,使用最基本的设置(取自 here):

const gulp = require('gulp');
const babel = require('gulp-babel');

gulp.task('default', () => {
    return gulp.src('src/app.js')
        .pipe(babel({
            presets: ['es2015']
        }))
        .pipe(gulp.dest('dist'));
});

我得到以下输出:

"use strict";

var name = "MyName";
var version = "1.2.3";

var theThing = {
  name: name,
  version: version,
  run: function run() {
    console.log("You're using " + undefined.name + "@" + undefined.version);
  }
};

theThing.run();

如您所见,它调用的是undefined.name 而不是this.name,我完全不知道为什么thisundefined 取代。当然,这段代码并没有按预期工作:

VM329:8 Uncaught TypeError: Cannot read property 'name' of undefined(…)

并且符合 ES6(在 chrome53 中 ES6 的原始实现可以正常工作)。

你也可以在Babel REPL看到这个问题。

我做错了什么 - 还是 babel 中的错误?

【问题讨论】:

    标签: javascript syntax ecmascript-6 babeljs


    【解决方案1】:

    在您的原始来源中尝试替换

    var theThing = {
      name,
      version,
      run: () => {
        console.log(`You're using ${this.name}@${this.version}`);
      }
    };
    

    通过

    var theThing = {
      name,
      version,
      run: function () {
        console.log(`You're using ${this.name}@${this.version}`);
      }
    };
    

    箭头语法函数改变了this的工作方式

    【讨论】:

      【解决方案2】:

      箭头函数不绑定到this(参见here)。因此,当你定义函数时,对象还不存在......所以 Babel 不知道上下文。

      摆脱箭头功能将解决它。

      【讨论】:

        【解决方案3】:

        箭头函数this 指向window,因为词法绑定。当您调用theThing.run() 时,您实际上会在模板中得到window.namewindow.version。如果您重命名全局变量,它将不起作用:

        var n = "MyName";
        var v = "1.2.3";
        
        var theThing = {
          name: n,
          version: v,
          run: () => {
            console.log(`You're using ${this.name}@${this.version}`);
          }
        };
        
        theThing.run();

        要解决这个问题,不要使用箭头函数:

            var n = "MyName";
            var v = "1.2.3";
        
            var theThing = {
              name: n,
              version: v,
              run() {
                console.log(`You're using ${this.name}@${this.version}`);
              }
            };
        
            theThing.run();

        【讨论】:

          【解决方案4】:

          正确答案包括两点:

          • 箭头函数和经典的 ES5 函数有完全不同的this 绑定。 this 在经典函数中是非常动态的(在运行时确定,无论它在哪里定义),而在箭头中,它是词法绑定的(绑定在它放置的位置,运行时对此没有影响,运行时已经来不及改变它)。词法范围从最近的封闭经典函数(如果存在)生成箭头函数 borrow this。如果不存在,则取自全局范围...
          • 如果不在严格模式下,则采用window。如果在严格模式下,则采用undefined

          ...正好回答了上述问题。

          【讨论】:

            猜你喜欢
            • 2019-02-25
            • 2015-02-18
            • 2016-09-19
            • 2018-01-23
            • 1970-01-01
            • 2015-09-14
            • 1970-01-01
            相关资源
            最近更新 更多