ES2015

ES2015 (이전 명칭: ES6)는 JavaScript 언어 발전에 한 걸음 더 나아간 것입니다. ES5에서 상당한 상용구가 필요한 패턴에 새로운 기능과 슈가링을 추가했습니다. 여기에는 클래스, 화살표 함수, 모듈이 포함됩니다. 이 에피소드에서는 JavaScript 웹 앱을 빌드할 때 ES2015를 최대한 활용하는 데 사용하는 도구를 다룹니다.

Babel을 사용한 트랜스파일

자바스크립트 엔진이 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/'));
});

여러 자바스크립트 파일

위의 예에서는 특정 파일을 정의해야 하는데 이 과정에서 다소 부담이 될 수 있습니다. 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는 코드의 스타일을 확인합니다. 여기에는 탭이나 공백만 사용하고 공백은 일관된 위치에 배치하는 등의 작업이 포함됩니다.

ES2015 코드에서 JSHint 및 JSCS를 사용하려면 .jshintrc.jscsrc 파일에 "esnext": true를 추가해야 합니다.

ESLint

ESLint는 대체 린터와 스타일 검사기입니다. 이 도구는 많은 부담을 주며 JavaScript가 작성된 환경을 표시하고 특정 문제의 오류 / 경고 수준을 설정하는 등 JSHint보다 유용한 기능을 제공합니다.

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팀은 ESLint를 사용하여 유효한 Babel 코드를 린트할 수 있는 도구인 babel-estlint를 유지관리합니다. ESLint는 맞춤 파서를 지원하지만 Babel에서 지원하는 일부 문법은 ESLint에서 직접 지원되지 않으므로 훨씬 더 유연성이 필요한 경우 또 다른 옵션입니다. 이는 .eslintrc 파일의 parser 섹션을 맞춤설정하여 설정할 수 있습니다.

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

댄 아브라모프는 Lint It's 2015에서 ESLint 및 babel-eslint 설정에 관한 훌륭한 저술을 했습니다. 또한 Sublime Text의 ES2015 린트 작업 지원 워크플로에 SublimeLinter-eslint를 통합하는 방법도 다룹니다.

어떤 방법을 사용해야 할까요? 시도해 보고 가장 효과적인 방법을 계속 사용하세요.

ES2015 구문 강조표시

물론 ES2015 코드에 구문이 올바르게 강조표시되어야 합니다. Package Control에서 설치할 수 있는 babel-sublime을 사용하는 것이 좋습니다. 설정 시 강조표시가 필요한 파일의 기본값으로 설정하는 것이 좋습니다. 여기에는 물론 JS가 포함되지만 React를 사용하는 경우 JSX도 다룰 수 있습니다.

ES2015 문서화

지금까지 Google은 자바스크립트 코드를 문서화하는 데 JSDoc를 많이 사용했습니다. 안타깝지만 ES2015 지원과 관련하여 미해결 문제가 있습니다 (JSDoc 3에서 해결 예정). 하지만 Google에서 따라잡기를 기다리는 동안 사용할 수 있는 대안의 수가 증가하고 있습니다. 이러한 옵션 중 하나는 ESDoc이며 조나단 크리머에 관한 최근 게시물에서 읽어볼 만한 가치가 있습니다.

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)를 호출하거나 이 변수에 대한 var를 만들 필요가 없습니다.

MDN에 대해 더 많은 예가 있습니다.

Addy의 ES6 도구 저장소

Addy는 ES2015 도구 목록을 작성하느라 바쁜데, 위의 도구가 적합하지 않다면 Gulp 대신 Grunt를 사용 중인 경우 이 방법이 도움이 될 수 있습니다.

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

위 페이지에는 단위 테스트 등에 도움이 되는 추가 Babel 도구에 대한 링크도 포함되어 있습니다.

읽을 만한 책

ES2015에 대해 자세히 알아보기 위해 온라인에서 무료로 확인할 수 있는 두 권의 책이 있습니다. 니콜라스 C가 작성한 ECMAScript 6 이해 악셀 라우쉬마이어 박사가 집필한 Zakas 및 Exploring ES6입니다.

바벨탑

명령줄에서 ES2015 기능을 익히는 데 관심이 있다면 tower-of-babel 참조에 관한 유용한 실습 시리즈를 확인해 보세요. 모두 Babel을 사용해 진행합니다.

기타 리소스(관심이 있는 경우):