ES2015

ES2015 (לשעבר ES6) הוא פתרון מצוין ליצירת שפת JavaScript. הוא מספק תכונות חדשות וייצור סוכר לדפוסים שדרשו פלטת חימום משמעותית ב-ES5. כולל המחלקות, פונקציות החיצים והמודולים. בפרק הזה נעסוק בכלים שאנחנו משתמשים בהם כדי לנצל את מלוא היתרונות של ES2015 כשיוצרים אפליקציות אינטרנט ב-JavaScript.

טרנספילציה עם Babel

למרות שמנועי JavaScript משיגים התקדמות נהדרת בהטמעת התכונות של ES2015 באופן מקומי, יש דרך אחת פשוטה. כדי להשתמש בכל התכונות הזמינות כיום, תצטרכו להמיר את הקוד חזרה ל-ES5 כדי שדפדפנים יוכלו לתרגם אותו. למרבה המזל, כלים כמו Babel קיימים שהופכים את התהליך הזה לפשוט וקל.

שימוש ב-Babel בתהליך הבנייה

באמצעות Babel ניתן להשתמש ב-JavaScript שנכתב באמצעות תכונות של ES2015 ולהעביר אותו חזרה ל-ES5, כך שיפעל בדפדפנים שאינם תומכים כיום בתכונות האלה. כך ניתן להוסיף את Babel לתהליך ה-build.

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 מרובים

הדוגמה שלמעלה מחייבת אתכם להגדיר קובץ ספציפי, שעלול להיות נטל קל .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

JSHint ו-JSCS הם הכלים הנפוצים ביותר שמשמשים לבדיקת הסגנון ב-JavaScript כיום.

JSHint ידגיש בעיות אפשריות בקוד ויפרט את הדפוסים שנחשבים בדרך כלל כשיטות עבודה לא תקינות.

JSCS יבחן את סגנון הקוד שלך, כולל דברים כמו לוודא שנעשה שימוש רק בכרטיסיות או ברווחים ושרווחים נמצאים במקומות עקביים.

כדי להשתמש ב-JSHint וב-JSCS בקוד ES2015, צריך להוסיף את "esnext": true לקבצים .jshintrc ו-.jscsrc

ESLint

ESLint הוא כלי חלופי ובודק סגנון בכלי אחד. הכלי הזה קולט הרבה מאוד נתונים, ויש בו כמה תכונות נחמדות על פני JSHint, כמו האפשרות לציין סביבות שבהן ה-JavaScript נכתב והגדרה של רמת השגיאה או האזהרה לבעיות ספציפיות.

ESLint ניתנים להתאמה אישית מלאה ומספקים כללי הטמעה מותאמים אישית, שבהם אתם קובעים אם אפשר לכבות או להחליש את האפשרויות באמצעות קובצי התצורה שלו. נוסף לכך, אם אתם משתמשים ב-React, ESLint פועל גם עם JSX.

גם לא קשה להגדיר את ESLint בתהליך ה-build.

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 בתהליך העבודה שלכם בתמיכת linting של ES2015 ב-Sublime Text.

באיזה מהם כדאי להשתמש? מומלץ לנסות להשתמש בהם ולבדוק מה הכי מתאים לך.

ES2015 הדגשת תחביר

כמובן שתרצה שקוד ES2015 שלך יודגש כראוי בתחביר. אנחנו נהנים מהשימוש ב-babel-sublime, שאפשר להתקין דרך Package Control. בזמן ההגדרה, מומלץ להקפיד להגדיר אותה כברירת מחדל לכל קובץ שרוצים להדגיש שעליו לפעול. זה כמובן יכלול את JS, אבל יכול גם לכסות את JSX כשמשתמשים ב-React.

תיעוד של ES2015

בעבר הסתמכנו על JSDoc במידה רבה לצורך תיעוד קוד ה-JavaScript שלנו. לצערנו, יש בו בעיות פתוחות לתמיכה ב-ES2015 (עקב בעיות מטופלות ב-JSDoc 3), אך יש מספר הולך וגדל של חלופות זמינות בזמן שאנחנו ממתינים עד שהוא יתקרב. ESDoc היא אחת האפשרויות האלה, וג'ונתן קרמר כתב עליו כתבה מהזמן האחרון.

יצירת קובצי Gulp.js באמצעות Babel

אם אתם משתמשים ב-Gulp לתהליך ה-build, עכשיו אפשר לכתוב Gulpfiles באמצעות כל תחביר שנתמך על ידי Babel. אנחנו עושים זאת ב-Web Starter Kit, וזה יחסית טריוויאלי. באמצעות גרסה עדכנית של Gulp ו-Gulp CLI, פשוט צריך לשנות את השם של gulpfile.js ל-gulpfile.babel.js, ו-Gulp יפרש ויתרגם את קובץ ה-Gulp 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.

תוכלו לקבל מידע נוסף בפוסט השימושי הזה בבלוג מאת 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);
});

מלבד התחביר הקצר יותר, אחת התכונות הנהדרות של השימוש בפונקציות fat Arrow היא שההיקף של האובייקט זהה להצהרה המקיפה. פירוש הדבר הוא שלא צריך לקרוא לפונקציה .bind(this) או ליצור משתנה = this.

יש עוד המון דוגמאות ב-MDN.

מאגר הכלים של Addy's ES6

Addy עסוקה ברישום רשימה של הכלים ל-ES2015, ואם הכלים שלמעלה לא מתאימים לכם, יכול להיות שאתם משתמשים ב-Grunt במקום ב-Gulp, אולי זה יכול לעזור לכם.

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

המידע שלמעלה כולל גם קישורים לכלים נוספים של Babel שיכולים לעזור במהלך בדיקת היחידה ואחריה.

ספרים לקריאה

יש שני ספרים שאפשר לעיין בחינם באינטרנט כדי לקבל מידע נוסף על ES2015. הבנת ECMAScript 6 שנכתב על ידי ניקולס סי. Zakas ו-Exploring ES6 שנכתב על ידי ד"ר אקסל ראושמאייר.

מגדל בבל

אם אתם רוצים ללמוד את התכונות של ES2015 בשורת הפקודה, תוכלו להיעזר ב-tower-of-babel בשורת תרגילים שעשויים לעניין אתכם. כולם עוברים דרך Babel.

משאבים נוספים שעשויים לעניין אותך: