ошибка переноса строки шаблона es6 короткого объектного литерала [gulp, babel]

#javascript #syntax #ecmascript-6 #babeljs

#javascript #синтаксис #ecmascript-6 #babeljs

Вопрос:

У меня чрезвычайно маленький код 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, используя самую базовую настройку (взятую из здесь):

 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 , я понятия не имею, почему this заменяется на undefined . Конечно, этот код работает не так, как ожидалось:

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

и не совместим с ES6 (оригинальная реализация ES6 в chrome53 работает корректно).

Вы также можете увидеть эту проблему в {
console.log(`You’re using ${this.name}@${this.version}`);
}
};

theThing.run();» rel=»nofollow»>Babel REPL.

Я делаю что-то неправильно — или это ошибка в babel?

Ответ №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}`);
  }
};
  

Синтаксическая функция arrow изменяет способ this работы

Ответ №2:

Функции со стрелками не привязываются к this (смотрите здесь). Поэтому, когда вы определяете функцию, объект еще не существует … поэтому Babel не знает о контексте.

Избавление от функции arrow исправит это.

Ответ №3:

Функция стрелки this указывает на window из-за лексической привязки. При вызове theThing.run() вы фактически получаете window.name и window.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();  

Чтобы решить эту проблему, не используйте функцию arrow:

     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:

Правильный ответ состоит из 2 баллов:

  • функции со стрелками и классические функции ES5 имеют совершенно разную this привязку. this в классических функциях он очень динамичен (определяется во время выполнения, независимо от того, где он определен), тогда как в arrows он лексически привязан (привязан к тому месту, где он размещен, среда выполнения на это не влияет, время выполнения уже слишком поздно это менять). Из-за лексической области видимости функция arrow заимствует this из ближайшей заключающей классической функции, если она присутствует. Если нет, то оно взято из глобальной области видимости…
  • если не в строгом режиме, window выполняется. Если в строгом режиме, undefined выполняется

… что точно отвечает на приведенный выше вопрос.