ES2015

ES2015 (原稱 ES6) 是 JavaScript 語言的最佳進展。其中針對 ES5 中需要大量樣板的模式提供新功能和糖。包括類別、箭頭函式和模組。在本集節目中,我們將說明在建構 JavaScript 網頁應用程式時,如何充分運用 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 的輸出內容) 傳遞此程式碼。

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();
});

內裡和樣式檢查

檢查程式碼是否有可能的問題和樣式合規時,您可以採取以下幾種做法。

JSHint 與 JSCS

JSHintJSCS 是當今 JavaScript 樣式檢查最常用的工具。

JSHint 會醒目顯示程式碼中的所有可能問題,並指出任何一般被視為不良做法的模式。

JSCS 會查看程式碼的樣式,包括確保只使用 Tab 或空格,並將空格放在一致的位置。

如要在 ES2015 程式碼上使用 JSHint 和 JSCS,您需要在 .jshintrc.jscsrc 檔案中新增 "esnext": true

ESLint

ESLint 是替代的 Linter 和樣式檢查工具。這項工具能擷取大量蒸汽,在 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,此工具可讓您使用 ESLint 檢查任何有效的 Babel 程式碼。雖然 ESLint 支援自訂剖析器,但 ESLint 並未直接支援 Babel 支援的部分語法,因此如果您需要進一步彈性,也可以使用這個選項。您也可以透過自訂 .eslintrc 檔案的 parser 區段進行設定:

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

Dan Abramov 在 Lint 例如 It's 2015 中設定 ESLint 和 babel-eslint 大膽的設定。也會探討如何將 SublimeLinter-eslint 整合至您的工作流程,確保 Sublime Text 中的 ES2015 程式碼檢查支援。

應使用下列何者?請試用這些建議,並繼續選擇最適合您的方式

ES2015 語法醒目顯示

當然,建議您確保 ES2015 程式碼的語法正確醒目顯示。我們非常希望使用 babel-sublime,此方法可透過套件控制項安裝。設定時,建議您確實將預設值設為所有需要醒目顯示的檔案。這當然包含 JS,但使用 React 時,也可以涵蓋 JSX。

ES2015 紀錄片

我們向來仰賴 JSDoc 記錄 JavaScript 程式碼。很抱歉,在支援 ES2015 時,仍有尚未解決的問題 (問題已在 JSDoc 3 中解決),但目前仍有日益增加的替代方案,我們會等候中。ESDoc就是其中一個好選擇,而 Jonathan Creamer 最近應該有寫作值得一讀。

使用 Babel 編寫 Gulp.js 檔案

如果打算使用 Gulp 進行建構程序,現在可以使用 Babel 支援的任何語法編寫 Gulpfiles。請在網頁入門套件中完成這項操作,而設定方式相對來說相當簡單。使用最新版本的 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 的變數。

針對 MDN 還有更多範例

Addy 的 ES6 Tools 存放區

Addy 一直忙於保留一份 ES2015 工具清單。如果上述工具不適合您,或許您會使用 Grunt,而非 Gulp,或許能找到答案。

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

上述內容也包含其他 Babel 工具的連結,可協助進行單元測試和其他工作。

推薦閱讀的書籍

您可以免費線上瀏覽兩本書,進一步瞭解 ES2015。瞭解 ECMAScript 6 (由 Nicholas C 撰寫)。Zakas 和 Exploring ES6 (探索 ES6),作者:Axel Rauschmayer。

巴貝爾塔

如果您想在指令列中學習 ES2015 功能,請看 tower-of-babel 提供的一系列練習。所有人員都會逐步瞭解如何使用 Babel

其他感興趣的資源: