ES2015

ES2015(以前称为 ES6)是 JavaScript 语言的极大进步。它为需要在 ES5 中需要大量样板代码的模式提供了新功能和添加糖服务。其中包括类、箭头函数和模块。在本集视频中,我们将介绍在构建 JavaScript Web 应用时可用于充分利用 ES2015 的工具。

使用 Babel 进行转译

虽然 JavaScript 引擎在以原生方式实现 ES2015 功能方面取得了巨大进步,但有一个问题。若要立即使用全部功能,您需要将代码转译回 ES5,以便当前浏览器解读它们。令人庆幸的是,Babel 这样的工具让这个过程变得无比轻松

在构建流程中使用 Babel

Babel 可让您提取使用 ES2015 功能编写的 JavaScript 并将其转译回 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 中的模块,您可以创建类并在文件之间导出 / 导入类。如需转译模块,请通过 Browserify 传递您的 JavaScript,以便合并文件,然后通过 Babelify(可以处理 Browserify 输出的 Babel 版本)进行传递。

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 文件

上面的示例要求您定义一个特定文件,这可能会变得有点负担,Matt 在 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();
});

执行 lint 请求和样式检查

在对代码执行 lint 检查时,有几个选项可以检查是否存在潜在问题和样式合规性。

JSHint 和 JSCS

JSHintJSCS 是当今用于检查 JavaScript 样式的最常用工具。

JSHint 会突出显示代码中可能存在的问题,并指出所有通常被认为错误做法的模式。

JSCS 会检查代码的样式,包括确保仅使用制表符或空格,以及将空格放在一致的位置等。

如需在 ES2015 代码上使用 JSHint 和 JSCS,您需要将 "esnext": true 添加到 .jshintrc.jscsrc 文件中

ESLint

ESLint 既是 linter 和样式检查工具,也是其中一款工具。与 JSHint 相比,此工具的开发速度非常快,并且具有一些很棒的功能,例如能够指示编写 JavaScript 的环境,以及设置特定问题的错误 / 警告级别。

ESLint 可完全自定义,并提供自定义 lint 规则,您可以决定可以通过其配置文件关闭或削弱选项。此外,如果您使用的是 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,使用以下工具可以使用 ESLint 对任何有效的 Babel 代码执行 lint 请求。虽然 ESLint 支持自定义解析器,但 Babel 支持的某些语法不受 ESLint 直接支持,因此如果您需要更大的灵活性,则这是另一种选择。这可以通过自定义 .eslintrc 文件的 parser 部分来设置:

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

Dan Abramov 在 Lint Like It's 2015 中写了一篇关于设置 ESLint 和 babel-eslint 的文章。此外,还介绍了如何将 SublimeLinter-eslint 集成到您的工作流中,以便在 Sublime Text 中支持 ES2015 lint 检查。

您应该使用以下哪些工具?请试用这些建议并坚持使用最适合您的方法。

ES2015 语法突出显示

您当然希望以正确的语法突出显示 ES2015 代码。我们喜欢使用 babel-sublime,它可以通过软件包控制安装。在设置时,我们建议确保将其设为需要突出显示的所有文件的默认名称。当然,这包括 JS,但如果使用 React,还可能涵盖 JSX。

提供 ES2015 文档

过去,我们高度依赖 JSDoc 来记录 JavaScript 代码。遗憾的是,它在支持 ES2015 方面存在未解决的问题(由于将在 JSDoc 3 中得到解决),但在我们等待它跟上新变化的步伐时,可用的替代方案却越来越多。ESDoc 就是这样一种选择,Jonathan Creamer 最近撰写了一篇论文,值得一读。

使用 Babel 编写 Gulp.js 文件

如果您碰巧在构建过程中使用了 Gulp,可以使用 Babel 支持的任何语法编写 Gulpfile。我们在 Web Starter Kit 中执行此操作,设置相对简单。使用最新版本的 Gulp 和 Gulp CLI,只需将 gulpfile.js 重命名为 gulpfile.babel.js,Gulp 便会使用 Babel 自动解释和转译您的 ES2015 gulpfile。

喜爱的 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.

如需了解详情,请参阅 Addy 发布的这篇实用博文

简写对象字面量

借助对象字面量,如果变量与您希望对象拥有的键具有相同的名称,则您在创建对象时不必定义键和值。

含义:

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 的 var。

MDN 上还有更多示例

Addy 的 ES6 工具代码库

Addy 一直忙于保存 ES2015 工具列表,如果上面的工具不适合您,也许您正在使用 Grunt 而不是 Gulp,这可能可以帮您找到答案。

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

上文中还包含其他 Babel 工具的链接,这些工具在单元测试及其他测试中很有帮助。

推荐图书

您可以在线免费阅读两本图书,详细了解 ES2015。了解 ECMAScript 6(Nicholas C. Zakas 和 Exploring ES6(由 Axel Rauschmayer 博士撰写)。

巴贝尔塔

如果您有兴趣在命令行中学习 ES2015 功能,不妨参阅 tower-of-babel 文档提供了一系列您可能会感兴趣的练习。他们都会使用 Babel 完成演示。

其他您可能感兴趣的资源