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
JSHint 和 JSCS 是当今用于检查 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。
了解详情链接
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 完成演示。
其他您可能感兴趣的资源: