ES6 có gì mới?

Note: This post is over 9 years old. The information may be outdated.

ES6 là phiên bản mới nhất của bộ tiêu chuẩn ECMAScript. ES6 ra mắt giữa 2015 với rất nhiều những tính năng mới lạ, và cần thiết đối với sự phát triển chóng mặt của Javascript trong những năm gần đây. Cụ thể ES6 sẽ có những điểm mới nào nổi bật?

Bài viết có thể sẽ không bao quát được hết những gì có trong ES6, nhưng sẽ nêu ra những điểm mới, điểm hay mà mình tiếp xúc trong quá trình sử dụng. Để xem đầy đủ changelog vui lòng xem tại đây.

let/const

ES6 bổ sung thêm cách khai báo biến cục bộ (Block-scoped variables), let khai báo biến trong block mà không làm ảnh hưởng đến giá trị trong block khác, hoặc const cho các biến không thay đổi giá trị. Ngoài ra let chỉ có giá trị trong phạm vi block code được khai báo.

const koa = require('koa')
if (true) {
  let x = 1
  console.log(x) // in ra: "1"
}
console.log(x) // undefined x do x chỉ được khai báo trong khối lệnh if() { ... }

Arrow

Arrow là một dạng viết tắt của các function sử dụng dấu =>, giống Java, C# hoặc Coffee Script.

Tạo hàm bằng arrow: param => returnValue

;(a, b) => a + b
;(a, b) => {
  return a + b
}

Hữu ích khi lập trình hàm (funtional programing) [1, 2].map(x => x * 2)

// 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))
  },
}

Class

ES5 không hỗ trợ class, mà mô tả các đối tượng thông qua các function và prototype. Hiện ES6 đã hỗ trợ Class, đúng chất của OOP.

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

Enhanced Object Literals

Enhanced Object Literals giúp rút gọn quá trình khai báo foo: foo trong Object. Ví dụ ngày trước bạn khai báo như thế này:

var obj = {};
obj.theProtoObj = theProtoObj;

var handler = function() { ... }
var obj = {
    handler: handler
};

Thì bây giờ có thể viết gọn handler: handler lại thành handler luôn:

var obj = {
  // __proto__
  __proto__: theProtoObj,
  // Shorthand for ‘handler: handler’
  handler,
  // Methods
  toString() {
    // Super calls
    return 'd ' + super.toString()
  },
  // Computed (dynamic) property names
  ['prop_' + (() => 42)()]: 42,
}

Exporting

ES6 có một chút thay đổi về cú pháp export

// Nodejs (AMD) ES5
module.exports = 1
module.exports = { foo: 'bar' }
module.exports = ['foo', 'bar']
module.exports = function bar () {}

// ES6
export default 1
export default { foo: 'bar' }
export default ['foo', 'bar']
export default function bar () {}
// ES5
module.exports.name = 'David'
module.exports.age = 25

// ES6
export var name = 'David'
export var age = 25
// math/addition.js
function sumTwo(a, b) {
  return a + b
}
function sumThree(a, b) {
  return a + b + c
}
export { sumTwo, sumThree }

Importing Modules

// ES5
var _ = require('underscore');​

// ES6
import _ from 'underscore';
import { sumTwo, sumThree } from 'math/addition'
import {
  sumTwo as addTwoNumbers,
  sumThree as sumThreeNumbers} from
} from 'math/addition'
import * as util from 'math/addition'

Template Strings + Escaping Characters + Multi-line Strings

Template Strings: Cái này khá dễ hiểu, giống như C/C++, Python. Template String được bao bởi dấu huyền (`)

// 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)

Escaping Characters: Không cần phải quan tâm khi string chứa dấu nháy đơn và kép lẫn lộn

// ES5
var text = 'This string contains "double quotes" which are escaped.'

// ES6
let text = `This string contains "double quotes" which are escaped.`

Multi-line Strings:

// ES5
var text = 'cat\n' + 'dog\n' + 'nickelodeon'
var text = ['cat', 'dog', 'nickelodeon'].join('\n')

// ES6
var text = `cat
  dog
  nickelodeon`

Destructuring Assignment

function multi_values() {
  return [1, 2, 3, 4, 5, 6]
}
// khi muốn gọi giá trị từ hàm trả về
;[x1, x2, , , x5, x6] = multi_values()
console.log(x6) // 6

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

Tham số mặc định

ES6 cho thấy sự thông minh trong cách nhận giá trị tham số đầu vào của một function. Bằng cách tự động điền giá trị tham số đầu vào theo thứ tự truyền vào tương ứng.

function default1(x = 1, y = 2, z = 3) {
  console.log(x, y, z)
}
default1(5, 6) // 5 6 3
function default2(x = 1, y = 2, z = 3) {
  console.log(x, y, z)
}
default2(undefined, 6, 7) // 1 6 7

Sử dụng "..." cho đa tham số

"..." trong ES6 có vai trò như định nghĩa một mảng động khi truyền vào tham số cho một function

function three_dot1(...args) {
  console.log(args.length) // in ra "4"
  console.log(args) // in ra "1 2 3 4"
}
three_dot1(1, 2, 3, 4)

For..Of

Giống for..in, for..of dùng để viết vòng lặp trên các iterator function hoặc generator function

let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0,
      cur = 1
    return {
      next() {
        ;[pre, cur] = [cur, pre + cur]
        return { done: false, value: cur }
      },
    }
  },
}

for (var n of fibonacci) {
  // truncate the sequence at 1000
  if (n > 1000) break
  console.log(n)
}

Generators

Có 1 bài giải thích chi tiết về generator function tại đây: function* và yield trong Javascript generator function

Unicode

ES6 hỗ trợ Unicode tốt hơn, không cần phải cài thêm các thư viện nào khác. Ngoài ra RegExp có thêm tham số u sử dụng cho unicode string.

Map + Set + WeakMap + WeakSet

Map, Set, WeakMap, WeakSet là các hàm thường thấy trong các ứng dụng về cấu trúc dữ liệu và giải thuật. Ví dụ:

// 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 })
// Because the added object has no other references, it will not be held in the set

Symbols

Các object state sử dụng chuổi để định danh phần tử của mảng, object. Symbols giúp tạo ra để thay thế string. Cái này giống như cú pháp arr[:name] trong Ruby.

var MyClass = (function() {

  // module scoped symbol
  var key = Symbol("key");

  function MyClass(privateData) {
    this[key] = privateData;
  }

  MyClass.prototype = {
    doStuff: function() {
      ... this[key] ...
    }
  };

  return MyClass;
})();

var c = new MyClass("hello")
c["key"] === undefined

Kết

ES6 còn khá nhiều chức năng hay, mình sẽ giới thiệu sau. Tham khảo thêm tại đây: https://github.com/duyet-collections/es6features

JavascriptNode.jsES6Javascript