ES6 và những tính năng vượt trội nên biết

0
66
views
es6 va javascript

ES6 là gì

Trước hết ES6 là một phiên bản của ECMAScript, một tập hợp các quy chuẩn dành cho các ngôn ngữ lập trình dạng kịch bản (scripts) và javascript vẫn được coi là ngôn ngữ kịch bản tuân thủ ECMAScript chặt chẽ nhất thời điểm hiện tại. Chính vì thế ECMAScript vẫn thường bị nhầm lẫn với Javascript. Thường mỗi năm sẽ có một phiên bản ES mới được công bố cùng với phiên bản của nó. Ví dụ ES6 là ES phiên bản số 6 ra đời năm 2015, ES7 là phiên bản số 7 và ra đời năm 2016…

Hầu hết chúng ta đều đã quen thuộc với ES5 từ thời còn dùng jQuery, là buổi sơ khai của javascript. Đến phiên bản ES6 ra đời là lúc javascript đã trở nên phổ biến hơn bao giờ hết và cũng chính vì thế ES6 ra đời giúp các lập trình viên đỡ mất công hơn và ứng dụng có hiệu năng tốt hơn. Bài này chúng ra sẽ tìm hiểu những điểm nổi bật nhất, thú vị nhất và phổ biến nhất của ES6 so với các phiên bản trước của nó.

1. Default parameters

Chắc hẳn các bạn còn nhớ operator sau :

var value = params || 1;

nếu params not null thì value sẽ nhận giá trị của params. Ngược lại value sẽ có giá trị 1. Phương pháp này thường được dùng để đặt giá trị mặc định cho các tham số của hàm.

function getResult(param1, param2) {
  param1 = param1 || 10;
  param2 = param2 || 'hello';
  ...
}

Cách này rất nguy hiểm vì nếu param1 mang giá trị false hoặc 0 (rõ ràng là not null) thì param1 sẽ mang giá trị mặc định là 10. Vì trong javascript false, 0 hay undefined nều được convert thành false. Giờ ta có cách khác ngắn gọn và an toàn hơn.

function getResult(param1 = 10, param2 = 'hello') {
  ...
}

Chỉ khi nào user không cung cấp giá trị của param1, param2 hoặc giá trị truyền vào là undefined thì các params mới nhận các giá trị mặc đinh. Cú pháp này khá giống với cách dùng trong PHP.

2. Template string

Là cách chèn giá trị biến vào trong một string, giống cách dùng của sprintf trong PHP, trước đây ta phải dùng phép + để thực hiện

var keyword = 'es6';
var url = 'https://example.com/search?q=' + keyword;

Với cách này, trước hết javascript intepreter sẽ phải convert keyword thành một string sau đó mới nối với chuối trước nó. Có vẻ khó nhìn và không liền mạch, giờ ta sử dụng ký tự ` (back tick)

var keyword = 'es6';
var url = `https://example.com/search?q=${keyword}`;

3. Multiline string

Nhớ lại cách trước đây chúng ta dùng để định nghĩa một đoạn html template

var template = '<a href="https://viettut.com" target="_blank">' + '\n' + 
                  '<span>Click Me</span>' + '\n' +
               '</a>';

Khá mất công để viết, căn chỉnh sao cho gần giống một file html và phải kết hợp với các phép cộng rất dễ nhầm lẫn và thiếu sót. Tuy nhiên trong es6, với ký tự back tick ta có cách viết hoàn toàn tự nhiên như sau:

var template = `<a href="https://viettut.com" target="_blank">
                  <span>Click Me</span>
                </a>`;

hoặc có thể kết hợp template string như ở phần 2

var title = 'Click Me';
var template = 
`<a href="https://viettut.com" target="_blank">
  <span>${title}</span>
</a>`;

4. Destructuring cho object và array

Nôm na destructuring là cách lấy gía trị một property của object hay một phần tử của array, gán cho một biến mà không cần phải truy cập bằng toán tử . (dot operator) của object hay [] của array, thậm chí cùng một lúc gán nhiều biến.

var obj = {name: "viettut", username: "viettut", email: "support@viettut.com"};
var {name, username, email} = obj;

thậm chí thứ tự các biến hoàn toàn có thể thay đổi

var obj = {name: "viettut", username: "viettut", email: "support@viettut.com"};
var {username, email, name} = obj;

cách viết mới này hoàn toàn tương đương với cách cũ ta vẫn dùng

var obj = {name: "viettut", username: "viettut", email: "support@viettut.com"};
var name = obj.name, username = obj.username, email = obj.email;

với array ta có cách dùng tương tự

var arr = [1,2,3,4,5,6];
var [first] = arr;
// first có giá trị phần tử đầu tiên (1)

hoặc

var arr = [1, 2, 3, 4, 5, 6];
var [first, second] = arr;
// second có giá trị phần tử thứ hai (2)

hoặc

var arr = [1,2,3,4,5,6];
var [first, second, ...rest] = arr;
// rest là phần array còn lại trừ hai phần tử đầu [3, 4, 5, 6]

toán tử ... gọi là shallow copy.

5. Arrow functions

Arrow functions giúp code ngắn gọn hơn nhưng quan trọng là chúng giúp ta sử dụng this một cách chính xác hơn mà không phải bind hoặc các phương pháp bind thủ công khác. Nhớ lại cách trước đây chúng ta làm

function test() {
  var name = 'viettut';
  var self = this;
  var callback = function() {
    console.log(self.name);
  }
}

Từ khóa this trong javascript phụ thuộc vào context khi hàm được gọi, thường this sẽ là scope nơi gọi hàm. Trong trường hợp có nhiều hàm lồng nhau sẽ rất khó để xác định đúng scope nào trong trường hơp nào. Nếu bạn nào chưa quen với các khái niệm của closure sẽ hơi khó hiểu một chút. Với arrow function ta có thể việt lại ngắn gọn hơn

function test() {
  var name = 'viettut';

  var callback = () => {
    console.log(this.name);
  }
}

với arrow function ta có thể dùng từ khóa this một cách thoải mái yên tâm, bộ intepreter sẽ lưu giữ trạng thái scope của nơi gọi hàm nên ta không cần phải xác định xem cần phải bind scope nào. Có vẻ ta sẽ tìm hiểu rõ hơn về vấn đề này trong một bài khác.

6. Promise

Ta đã từng bàn luận về Promise trong một bài viết nhưng là dùng thư viện ngoài. Nay ES6 đã tích hợp sẵn Promise và ta sẽ không cần phải dùng thư viện ngoài. Tất nhiên cách viết cũng sẽ có khác biệt, nếu như trước đây ta viết

"use strict";
const Todo = require('models/todo');
const Q = require("q");

function getList(params) {
  const deferred = Q.defer();

  Todo.find({}, function(error, todos) {
    if (error) {
      deferred.reject(error);
    } else {
      deferred.resolve(blogs);
    }
  });

  return deferred.promise;
}

giờ ta có thể viết lại

"use strict";
const Todo = require('models/todo');

function getList(params) {
  return new Promise( (resolve, reject) => {
    Todo.find({}, function(error, todos) {
      if (error) {
        reject(error);
      } else {
        resolve(blogs);
      }
    });        
  });
}

7. Let và Const

letconst tương ứng là 2 cách khai báo biến và hằng mới trong ES6. Như ta đã biết var là cách khai báo biến cũ với function scope và có hoisting. Tức là biến có giá trị trong phạm vi của một function.

function calculateTotalAmount (vip) {
  var amount = 0
  if (vip) {
    var amount = 1
  }
  {
    var amount = 100
    {
      var amount = 1000
    }
  }  

  return amount
}

console.log(calculateTotalAmount(true))

cuối cùng kết quả sẽ là 1000. Hoisting là cách biên dịch của trình interpreter khi đưa các lệnh khai báo (var) lên đầu hàm. Tức là ta có thể khai báo biến ở cuối một hàm nhưng vẫn có thể sử dụng biết đó ở đầu hàm, khi đó biến sẽ mang giá trị là undefined. Ví dụ

function test() {
  console.log('the value is ' + value); //truy xuất value mà chưa đến đoạn khai báo value
  var value = '1'
}

let cũng giống như var khác ở chỗ là không có hoisting, chỉ có giá trị trong một block, một block là một đoạn code nằm trong hai ký tự {}. Trong một block thì ta không thể 2 lần khai báo một biến

function calculateTotalAmount (vip) {
  var amount = 0
  if (vip) {
    let amount = 1 // first amount is still 0
  } 
  {
    let amount = 100 // first amount is still 0
    {
      let amount = 1000 // first amount is still 0
    }
  }  

  return amount
}

console.log(calculateTotalAmount(true))

kết quả sẽ là 0amount chỉ có giá trị trong các block, trong khi amount lại được return ở trong function. const trong khi đó là cách khai báo hằng, cũng là block scope. Khi khai báo const thì ta phải cung cấp một giá trị khởi tạo nào đó và giá trị này sẽ là immutable, tức là khởi tạo một lần và không thể thay đổi.

function test() {
  const i; //báo lỗi vì không có giá trị khởi tạo
  const i = 0;
  ...
  i = 1;// báo lỗi vì i là immutable
}

8. Class

Đây là một tin vui với những tín đồ của OOP bởi vì trước đó ta không có cách nào khai báo class mà phải dùng cách giả class, không có cách nào sử dụng tính năng kế thừa.

class baseModel {
  constructor(options = {}, data = []) { // class constructor
    this.name = 'Base'
    this.url = 'https://viettut.com'
    this.data = data
    this.options = options
  }

  getName() { // class method
    console.log(`Class name: ${this.name}`)
  }
}

các method trong class không cần phải có từ khóa function, ta cũng không thể set giá trị có các property chỉ bằng cách thông thường. Cách duy nhất để set đó là đặt trong constructor. Khai báo kế thừa như sau

class AccountModel extends baseModel {
  constructor(options, data) {
    super({private: true}, ['32113123123', '524214691']) //call the parent method with super
    this.name = 'Account Model'
    this.url +='/accounts/'
  }
}

để gọi constructor của parent ta dùng super. Để có getter ta khai báo như sau, tên hàm sẽ trở thành property của class

get accountsData() { //calculated attribute getter
  // ... make XHR
  return this.data
}

let accounts = new AccountModel(5)
accounts.getName()
console.log('Data is %s', accounts.accountsData)

Từ khóa class không có tác động nào đó quá đặc biệt nó chỉ là một cách viết, một cú pháp giúp tiết kiệm công sức cho lập trình viên. Nó cũng không tạo ra một data type mới cho javascript:

let options = {a: 1};
let data = ['google.com', 'facebook.com'];
let account = new AccountModel(options, data);
console.log(typeof account)
// kết quả sẽ là **function**

Nếu bạn dùng angular hoặc react thì sẽ thấy việc sử dụng class rất phổ biến, ngoài class ra thì các tính năng được sử dụng nhiều nhất của es6 đó là : let và const, arrow function, template string và promise

Happy coding 🙂

BÌNH LUẬN

Please enter your comment!
Please enter your name here