ECMAScript 6

20130807-es6.png

ECMAScript là một đặc tả ngôn ngữ được chuẩn hoá và đăng kí bản quyền bởi Ecma International. Nó nổi tiếng vì được áp dụng bởi các ngôn ngữ client-side cho Web như Javascript, JScript, ActionScript.

Lịch sử

Đầu tiên, một đặc tả ngôn ngữ kịch bản được phát triển bởi Brendan Eich của Netscape và nó có tên là Mocha. Sau đó nó được đổi tên thành LiveScript và cuối cùng là Javascript. Vào tháng 12 năm 1995, Sun Microsystem và Netscape đã công bố Javascript. Tháng 3, 1996 trình duyệt Netscape Navigator 2.0 ra đời và hỗ trợ Javascript. Sau đó, Microsoft ra mắt một ngôn ngữ tương tự tên là JScript để cạnh tranh và tránh vấn đề bản quyền. JScript được thêm vào trong Internet Explorer 3.0 và ra mắt vào tháng 8, 1996.

Netscape chuyển Javascript tới Ecma International để làm công tác chuẩn hoá và viết đặc tả, được gọi là ECMA-262, bắt đầu vào tháng 11, 1996. Và cái tên ECMAScript được hình thành từ đây bởi sự thoả thuận giữa những công ty đang tham gia vào quá trình chuẩn hoá nó, đặc biệt là Netscape và Microsoft, những công ty có cống hiến lớn trong thời kì đầu. Eich, người sáng lập đặc tả này, cho biết: "ECMAScript luôn là một cái tên không mong đợi chút nào, nó nghe như một loại bệnh ngoài da"

Trong khi cả Javascript và JScript đều cố gắng tuân thủ chuẩn ECMASCript, song nó cũng cung cấp cả những tính năng khác không được mô tả trong đặc tả ECMA.

ECMAScript 6 (hay còn được gọi là ES6, ES2015) là phiên bản mới nhất của chuẩn ECMAScript. Chuẩn này được phê duyệt vào tháng 6/2015. Nó là một bản nâng cấp quan trọng cho ES kể từ ES5 đã được chuẩn hoá vào năm 2009.

Những tính năng của ES6

Sau đây, mình xin nêu một số tính năng mới nổi bật và thú vị của ES6

Arrows

Arrows là cách khai báo hàm sử dụng cú pháp =>. Nó hỗ trợ cả cấu trúc thân hàm kiểu khối (block body) và thân hàm biểu thức (expression body). Điểm đặc biệt thú vì của arrow là nó sử dụng chung biến this với code bao hàm nó. Trong khi đối với function thường, để sử dụng được đối tượng this của function cha, chúng ta phải gán self = this hoặc dùng bind(this).

// Expression bodies
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
var pairs = evens.map(v => ({even: v, odd: v + 1}));

// Statement bodies
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

// Lexical this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
}

Lớp (Classes)

Class của ES6 có cấu trúc tương tự với các ngôn ngữ hướng đối tượng khác. Nó được khai báo bằng từ khoá class và hỗ trợ đầy đủ các tính năng như kế thừa (inheritance), gọi lớp cha (super calls), thực thể (instance), phương thức tĩnh (static methods) và hàm tạo (constructor).

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    super(geometry, materials);

    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  update(camera) {
    //...
    super.update();
  }
  get boneCount() {
    return this.bones.length;
  }
  set matrixType(matrixType) {
    this.idMatrix = SkinnedMesh[matrixType]();
  }
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}

Chuỗi mẫu (Template Strings)

Template Strings là một cách mới để khởi tạo một chuỗi kí tự trong ES6. Nếu như trước đây, để làm việc với những chuỗi dài, trải trên nhiều dòng, chúng ta phải dùng đến toán tử + để nối chuỗi. Hoặc, để chèn thêm giá trị từ biến vào string, chúng ta cũng phải dùng đến toán tử +. Tuy nhiên, với template string thì mọi thứ trở nên dễ dàng hơn rất nhiều. Nó được định nghĩa bởi cặp dấu , có thể trải trên nhiều dòng và nhúng biến vào trong bằng cấu trúc${variable}`

// Basic literal string creation
`In JavaScript '\n' is a line-feed.`

// Multiline strings
`In JavaScript this is
 not legal.`

// String interpolation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Construct an HTTP request prefix is used to interpret the replacements and construction
POST`http://foo.org/bar?a=${a}&b=${b}
     Content-Type: application/json
     X-Credentials: ${credentials}
     { "foo": ${foo},
       "bar": ${bar}}`(myOnReadyStateChangeHandler);

Destructuring

Destructuring cho phép gán giá trị sử dụng khớp mẫu (pattern matching), hỗ trợ match arrays và objects. Destructuring là fail-soft, giống như khi bạn truy cập vào một phần tử của mảng foo["bar"] mà phần tử này không tồn tại, nó sẽ trả lại undefined thay vì gây ra lỗi chương trình như fail-hard.

// list matching
var [a, , b] = [1,2,3];

// object matching
var { op: a, lhs: { op: b }, rhs: c }
       = getASTNode()

// object matching shorthand
// binds `op`, `lhs` and `rhs` in scope
var {op, lhs, rhs} = getASTNode()

// Can be used in parameter position
function g({name: x}) {
  console.log(x);
}
g({name: 5})

// Fail-soft destructuring
var [a] = [];
a === undefined;

// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;

Parameters

ES6 hỗ trợ gán giá trị mặc định cho tham số trong hàm. Trước kia, chúng ta phải kiểm tra tham số có bằng undefined không và gán giá trị cho nó.

function f(x, y=12) {
  // y is 12 if not passed (or passed as undefined)
  return x + y;
}
f(3) == 15

Ngoài ra ES6 còn hỗ trợ hàm có số lượng tham số không giới hạn. Tham số này có thể được truy cập như là một array,

function f(x, ...y) {
  // y is an Array
  return x * y.length;
}
f(3, "hello", true) == 6

Let + Const

Có 2 keywords mới được bổ sung là letconst. let là alias của var còn const thì dùng để định nghĩa một hằng số.

function f() {
  {
    let x;
    {
      // okay, block scoped name
      const x = "sneaky";
      // error, const
      x = "foo";
    }
    // error, already declared in block
    let x = "inner";
  }
}

Modules

ES6 hỗ trợ việc sử dụng module, và phong cách thì được lấy cảm hứng theo các module loaders phổ biến như AMD, CommonJS. Trong file module, chúng ta dùng từ khoá export để định nghĩa những hàm, biến muốn nơi khác sử dụng. Và ở file dùng module thì dùng từ khoá import để nạp. Modules được hoạt động theo cơ chế không đồng bộ (async), tức là code của module sẽ không được chạy cho tới khi module đó được nhập và thực thi.

// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
import {sum, pi} from "lib/math";
alert("2π = " + sum(pi, pi));

Cạnh đó, chúng ta còn có export default để đặt một hàm hoặc biến làm đối tượng mặc định được export. Và export * để export lại một thư viện khác.

// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.log(x);
}
// app.js
import ln, {pi, e} from "lib/mathplusplus";
alert("2π = " + ln(e)*pi*2);

Kiểu dữ liệu mới

ES6 hỗ trợ thêm 4 kiểu dữ liệu mới là Map, Set, WeakMap và WeakSet.

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });

Tham khảo

https://en.wikipedia.org/wiki/ECMAScript

https://github.com/lukehoban/es6features