ES2015

ES2015 (формально ES6) — это фантастический шаг вперед для языка JavaScript. Он предоставляет новые функции и усовершенствование шаблонов, которые требовали значительного количества шаблонов в ES5. Сюда входят классы, стрелочные функции и модули. В этом выпуске мы рассмотрим инструменты, которые мы используем, чтобы в полной мере использовать преимущества ES2015 при создании веб-приложений на JavaScript.

Транспиляция с помощью Babel

Хотя движки JavaScript добились большого прогресса в реализации функций ES2015, есть одна ошибка. Чтобы использовать полный набор функций сегодня, вам нужно будет перенести свой код обратно в ES5, чтобы его можно было интерпретировать текущими браузерами. К счастью, существуют такие инструменты, как Babel, которые делают этот процесс практически безболезненным.

Использование Babel в процессе сборки

Babel позволяет вам взять JavaScript, написанный с использованием функций ES2015, и перенести его обратно в ES5, чтобы он мог работать в браузерах, которые сегодня не поддерживают эти функции. Добавить Babel в процесс сборки можно следующим образом.

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

gulp.task('default', function () {
    return gulp.src('src/app.js')
        .pipe(babel())
        .pipe(gulp.dest('dist'));
});

Единственная функция, которую Babel не может перенести, — это модули. Модули в ES6 позволяют создавать классы и экспортировать/импортировать классы между файлами. Чтобы транспилировать модули, передайте ваш JavaScript через Browserify , который объединит файлы, а затем передаст их через Babelify (версия Babel, которая может обрабатывать выходные данные Browserify).

var babelify = require('babelify');
var source = require('vinyl-source-stream');
var browserify = require('browserify');

gulp.task('babelify', function() {
  browserify({ entries: './src.js', debug: true })
    .transform(babelify)
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest('./dist/js/'));
});

Несколько файлов JavaScript

В приведенном выше примере вам необходимо определить конкретный файл, что может оказаться немного обременительным. Мэтт делает в Gulp следующее для поиска и переноса файлов, заканчивающихся на .es6.js.

var config = {
  src: 'src/scripts',
  dest: 'dist/scripts'
};
var es6FileGlob = '/**/*.es6.js';

var gulp = require('gulp');
var plugins = require('gulp-load-plugins')();
var glob = require('glob');
var path = require('path');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');

// Takes an array of bundles to run through browserify and babelify
function transpileES6Modules(browserifyFileEntries) {
  browserifyFileEntries.forEach(function(fileEntry) {
    var browserifyBundle = browserify({
        entries: [fileEntry.srcPath]
      })
      .transform(babelify);

    var finalStream = browserifyBundle.bundle()
      .on('log', plugins.util.log.bind(plugins.util, 'Browserify Log'))
      .on('error', plugins.util.log.bind(plugins.util, 'Browserify Error'))
      .pipe(source(fileEntry.outputFilename));

    return finalStream.pipe(gulp.dest(fileEntry.dest));
  });
}

// This takes a source path and finds all files ending
// with .es6.js and creates the bundles to run through browserify
// and babelify
function handleES6Scripts(srcPath) {
  var browserifyFileEntries = [];

  var es6Filepaths = glob.sync(srcPath + es6FileGlob);
  es6Filepaths.forEach(function(filepath) {
    var filename = path.basename(filepath);
    var directoryOfFile = path.dirname(filepath);
    var relativeDirectory = path.relative(
      srcPath,
      directoryOfFile);

    // Create an object and add to the browserify bundle array
    browserifyFileEntries.push({
      srcPath: './' + filepath,
      outputFilename: filename,
      dest: path.join(config.dest, relativeDirectory)
    });
  });

  transpileES6Modules(browserifyFileEntries);
}

gulp.task('scripts:es6', ['scripts:lint'], function(cb) {
  handleES6Scripts(config.src);

  cb();
});

Линтинг и проверка стиля

Существует несколько вариантов проверки кода на предмет возможных проблем и соответствия стилю.

JSHint и АОС

JSHint и JOSS — наиболее распространенные инструменты, используемые сегодня для проверки стиля JavaScript.

JSHint выделит любые возможные проблемы в вашем коде, а также выявит любые шаблоны, которые обычно считаются плохой практикой.

JCS будет учитывать стиль вашего кода, включая такие вещи, как обеспечение использования только табуляции или пробелов, а также размещение пробелов в одинаковых местах.

Чтобы использовать JSHint и JOSS в коде ES2015, вам необходимо добавить "esnext": true в ваши файлы .jshintrc и .jscsrc .

ESLint

ESLint — это альтернативный линтер и средство проверки стилей в одном. Этот инструмент набирает обороты и имеет несколько приятных функций по сравнению с JSHint, таких как возможность указывать среды, для которых написан ваш JavaScript, и устанавливать уровень ошибок/предупреждений для конкретных проблем.

ESLint полностью настраиваемый и предоставляет настраиваемые правила проверки, где вы сами решаете, можно ли отключить или смягчить параметры с помощью файлов конфигурации. Кроме того, если вы используете React, ESLint также работает с JSX.

Настройка ESLint в процессе сборки также не представляет особых сложностей.

var gulp = require('gulp'),
    eslint = require('gulp-eslint');

gulp.task('lint', function () {
    return gulp.src(['js/**/*.js'])
        // eslint() attaches the lint output to the eslint property
        // of the file object so it can be used by other modules.
        .pipe(eslint())
        // eslint.format() outputs the lint results to the console.
        // Alternatively use eslint.formatEach() (see Docs).
        .pipe(eslint.format())
        // To have the process exit with an error code (1) on
        // lint error, return the stream and pipe to failOnError last.
        .pipe(eslint.failOnError());
});

gulp.task('default', ['lint'], function () {
    // This will only run if the lint task is successful...
});

Команда Babel поддерживает Babel-estlint — инструмент, который позволяет вам анализировать любой действительный код Babel с помощью ESLint. Хотя ESLint поддерживает пользовательские синтаксические анализаторы, некоторая часть синтаксиса, поддерживаемого Babel, не поддерживается ESLint напрямую, поэтому это еще один вариант, если вам требуется еще большая гибкость. Это можно настроить, настроив раздел parser вашего файла .eslintrc :

{
  "parser": "babel-eslint",
  "rules": {
    "strict": 0
  }
}

Дэн Абрамов написал отличную статью о настройке ESLint и Babel-eslint в Lint Like It’s 2015 . Здесь также рассказывается, как интегрировать SublimeLinter-eslint в ваш рабочий процесс для поддержки проверки ES2015 в Sublime Text.

Что вам следует использовать? Попробуйте их и выберите то, что лучше всего подходит для вас.

Подсветка синтаксиса ES2015

Вы, конечно, захотите, чтобы ваш код ES2015 был правильно выделен синтаксисом. Нам нравится использовать Babel-Sublime , который можно установить из Package Control . При настройке мы рекомендуем убедиться, что он установлен по умолчанию для всех файлов, которые вам нужно выделить для работы. Это, конечно, будет включать JS, но может также охватывать и JSX, если вы используете React.

Документирование ES2015

Исторически мы довольно широко полагались на JSDoc для документирования нашего кода JavaScript. К сожалению, у него есть открытые проблемы с поддержкой ES2015 (которые будут решены в JSDoc 3), однако количество доступных альтернатив растет, пока мы ждем, пока они наверстают упущенное. ESDoc — один из таких вариантов, и у Джонатана Кримера есть недавняя статья о нем, которую стоит прочитать.

Создание файлов Gulp.js с помощью Babel

Если вы используете Gulp для процесса сборки, Gulpfiles теперь можно создавать с использованием любого синтаксиса, поддерживаемого Babel. Мы делаем это в Web Starter Kit , и настроить его относительно просто. Используя последнюю версию Gulp и Gulp CLI, просто переименуйте свой gulpfile.js в gulpfile.babel.js , и Gulp автоматически интерпретирует и транспилирует ваш gulpfile ES2015 с помощью Babel.

Любимые функции ES2015

Модули

Модули — это способ экспорта значений, функций и классов из одного файла, чтобы вы могли импортировать их в другой файл.

export function exampleFunction() {
  console.log('I\'m an example. #TrueStory');
}



import { exampleFunction } from './example-function';
import BaseController from './base-controller';

export default class ExampleController extends BaseController {
  constructor() {
    super();

    exampleFunction();
  }

  doSomething() {
    console.log('What should I do? Change the DOM? Print a dancing shark to the console?');
  }
}

На этом сайте есть несколько замечательных примеров и объяснений модулей .

Строки шаблона

Строки шаблона позволяют заменить порт строки переменной.

// Simple string substitution
var name = "Brendan";
console.log('Yo, ${name}!');

// => "Yo, Brendan!"

Преимущество строк шаблона в том, что замена представляет собой выполнение JavaScript, то есть вы можете использовать функции или встроенные выражения.

var a = 10;
var b = 10;
console.log('a+b = ${a+b}.');
//=> a+b = 20.

function fn() { return "I am a result. Rarr"; }
console.log('foo ${fn()} bar');
//=> foo I am a result. Rarr bar.

Вы можете узнать больше из этой полезной записи в блоге Адди .

Сокращенные литералы объектов

Литералы объекта позволяют избежать необходимости определять ключ и значение при создании объекта, если переменная имеет то же имя, что и ключ, который вы хотите, чтобы объект имел.

Имея в виду это:

function createObject(name, data) {
  return { name: name, data: data };
}

Становится это:

function createObject(name, data) {
  return { name, data };
}

Вычисляемые имена свойств

Эта функция в ES2015 позволяет динамически создавать имена свойств объекта. Документы Mozilla — отличный источник информации, и в них есть отличный пример .

var a = {
  ["foo" + ++i]: i,
  ["foo" + ++i]: i,
  ["foo" + ++i]: i
};

console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3

Функции жирной стрелки

Функции с толстыми стрелками позволяют вам писать функции в сокращенном виде, где это:

button.addEventListener('click', function(event) {
  console.log('The button has received a click', event);
});

Становится это:

button.addEventListener('click', (event) => {
  console.log('The button has received a click', event);
});

Помимо более короткого синтаксиса, еще одной замечательной особенностью использования функций с толстыми стрелками является то, что область действия объекта такая же, как и у заключающего его оператора. Это означает, что вам не нужно вызывать .bind(this) для вашей функции или создавать переменную, которая = this.

На MDN есть еще много примеров .

Репозиторий инструментов Addy ES6

Адди был занят составлением списка инструментов ES2015, и если приведенные выше инструменты вам не подходят, возможно, вы используете Grunt вместо Gulp, тогда здесь может быть для вас ответ.

https://github.com/addyosmani/es6-tools

Вышеупомянутое также включает ссылки на дополнительные инструменты Babel, которые могут помочь во время модульного тестирования и за его пределами.

Книги для чтения

Есть две книги, которые вы можете бесплатно прочитать в Интернете, чтобы узнать больше о ES2015. «Понимание ECMAScript 6» , написанное Николасом К. Закасом, и «Изучение ES6», написанное доктором Акселем Раушмайером.

Вавилонская башня

Если вы заинтересованы в изучении функций ES2015 в командной строке, Вавилонская башня предлагает серию упражнений, которые могут вас заинтересовать. Все они проходят через Babel.

Другие ресурсы в случае интереса: