ES2015

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

טרנספיקציה באמצעות Babel

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

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

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

הדוגמה שלמעלה דורשת הגדרה של קובץ ספציפי, וייתכן מהווה נטל, מאט מבצע את הפעולות הבאות ב-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();
});

איתור שגיאות בקוד (linting) ובדיקות סגנון

יש כמה אפשרויות לאיתור שגיאות בקוד (linting) כדי לאתר בעיות אפשריות והסגנון תאימות למדיניות.

JSHint ו-JSCS

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

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

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

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

ESLint

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

אפשר להתאים אישית את ESLint באופן מלא, ויש בו כללים מותאמים אישית לאיתור שגיאות בקוד (linting) כשאתם נמצאים מושב הנהג לקבוע אם ניתן לכבות או להנמיך את האפשרויות קובצי תצורה. בנוסף, אם אתם משתמשים ב-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
  }
}

Dan Abramov כתב מאמר מעולה על הגדרת ESLint ו-babel-eslint במאמר Lint Like It's 2015. בנוסף, מוסבר איך לשלב את SublimeLinter-eslint בתהליך העבודה כדי לקבל תמיכה ב-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);
});

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

יש דוגמאות רבות נוספות ב-MDN.

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

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

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

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

ספרים לקריאה

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

מגדל בבל

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

מקורות מידע אחרים שאולי יעניינו אותך: