ES6 - The Good Part (Phần 2)

Tiếp nối phần 1 https://viblo.asia/luongs3/posts/L4x5xQ1mKBM Phần 2 tôi sẽ trình bày về các nội dung còn lại là:

  • destructuring
  • spread operator
  • for of vs for in
  • Array methods
  • class

Destructuring

Destructure có ý nghĩa là phá hủy. Nhưng có lẽ áp dụng trong es6 thì mang nghĩa phân giải thì đúng hơn. Đây là một kỹ thuật giúp chúng ta tạo ra các variable bằng cú pháp ngắn gọn, bớt lặp code hơn. Hãy cùng đi vào ví dụ sau:

Destructuring Object
const animal = {
    dog: 'James',
    cat: {
        bigger: 'Anthony',
        smaller: 'Mimi'
    },
    turtle: 'Knox'
}

// normal way
const dog = animal.dog;
const cat = animal.cat;
const turtle = animal.turtle;

//es6 - destructuring
const {dog, turtle} = animal; 
const {bigger, smaller} = animal.cat; 

console.log(dog, turtle); //James, Knox
console.log(bigger, smaller); //Anthony, Mimi

Thực hiện gán tên và gán giá trị mặc định trong Destructuring Ta dùng dấu : để gán tên khác cho biến khi không muốn dùng tên trùng với property của object. và dùng dấu = để gán giá trị mặc định. Ở đây tôi không hề khai báo giá trị cho publish bên trong dictionary, nên publish sẽ nhận một giá trị mặc định cho nó là '2017-01-10'.

const dictionary = {
    subject: {
        farmily: {
            farther: 'cha',
            mother: 'mẹ',
            son: 'con trai'
        },
        city: {
            house: 'nhà cửa',
            road: 'đường đi',
            'traffic light':  'đèn giao thông'
        }
    },
    quantity: 200,
    title: 'James Nguyen Dictionary'
}

const {subject: sub, quantity: quan, publish: pub = '2017-01-10'} = dictionary;
console.log(quan); // 200
console.log(publish); //2017-01-10
console.log(pub); //2017-01-10
Destructuring Array

Ở trên, ta đã được thấy Destructuring áp dụng với object. Ngoài ra thì kĩ thuật này còn áp dụng được với cả array nữa. Cách thức áp dụng thì tương tự.

const itCompany = ['framgia', 'evolable', 'fpt'];
const [japan, america, vietnam] = itCompany;

console.log(japan); //framgia
console.log(america); //evolable
console.log(vietnam); //itCompany

Có một vài khác biệt khi ta sử dụng Destructuring với ObjectArray. Khi sử dụng với Object, các biến được khai báo sẽ tương ứng với property của Object bị Destructuring, còn với Array thì các biến được khai báo sẽ tương ứng với các vị trí. Nhìn vào ví dụ trên, ta thấy là variable japan sẽ tương ứng với phần tử ở vị trí đầu tiên của Array itCompany nên nó sẽ nhận giá trị là framgia. Khác biệt thứ 2 là syntax. Với Object, ta sử dụng dấu dóng mở ngoặc nhọn: {}, còn với Array, ta sử dụng ngoặc vuông.

Destructuring Function

Ngoài ra, bạn cũng có thể thực hiện Destructoring với function:

function showInfor({firstName, lastName, age}) {
    return `Name: ${firstName} ${lastName} <br/> Age: ${age}`; 
}

const person = {
    firstName: 'james',
    lastName: 'nguyen',
    age: 18
}

showInfor(person); 
//Name: james nguyen
//Age: 18

Có thể thấy việc sử dụng Destructuring với function sẽ rất tiện lợi khi ta sử dụng function đó nhiều lần và biến truyền vào ở dạng object. Đặc biệt khi tôi làm việc với React JS, stateprops rất hay được sử dụng và cả 2 đều là object. Khi này muốn sử dụng bất cứ object nào trong state hoặc props, tôi chỉ việc áp dụng destructuring vào function và truyền state hoặc props vào là xong. Dưới đây là một ví dụ khác khi ta return multiple value.

function operate(a, b) {
    return {
        sum: a + b,
        sub: a - b,
        mul: a * b
    };
}

const {sum, mul, sub} = operate(20, 10);

console.log(sum, sub, mul); //30, 10, 200

Spread Operator

Spread Operator: ... là một toán tử nhận các item bên trong một iterable object (tức là các object có thể loop được như Array, nodes, DOM, hoặc thậm chí là một object có iterator) và apply các item này vào containing object. Khái niệm hơi khó hiểu, nên hãy cùng nhìn vào ví dụ sau đây:

const android = [ 'galaxy s7', 'nokia 1020', 'xiaomi mi5'];
const iphone = ['iphone 7 ', 'iphone8', 'iphone9'];
const phones = [...android, ...iphone, 'viettel phone 100'];
console.log(phones);
//[ 'galaxy s7', 'nokia 1020', 'xiaomi mi5', 'iphone 7 ', 'iphone8', 'iphone9',  'viettel phone 100'];

Ở đây, iterable object chính là androidiphone, các item bên trong các Array này đã được apply vào containing objectphones. Và lưu ý là các item trong phones và các item trong android, iphone là riêng biệt. Tức là spread operator thực hiện clone chứ không đơn thuần là copy các value này. Chính vì vậy nếu ta thay đổi giá trị galaxy s7 bên trong phones, thì giá trị galaxy s7 trong android sẽ không bị thay đổi gì. Vì 2 variable này là 2 biến tham chiếu khác nhau. Một lưu ý khác, và đã được tôi nhắc đến ở trên, đó là spread operator sử dụng được với tất cả iterator, tức là bao gồm cả string, nodes, DOM objects. Ví dụ với string chẳng hạn:

const str = 'Hello';
const strArray = [...str];
console.log(strArray);
//["H", "e", "l", "l", "o"]

Ngoài ra, spread operator còn có một ứng dụng khác gọi là rest params. Hãy cùng đi vào ví dụ sau đây:

const people = ['Tahei', 'Tran Duc Thang', 'Nguyen My Hanh', 'Nguyen Phuc Luong'];
const [CEO, CFO, ...staffs] = people;
console.log(CEO); // Tahei
console.log(CFO); //Tran Duc Thang
console.log(staffs); // ['Nguyen My Hanh', 'Nguyen Phuc Luong'];

Khi sử dụng spread operator với biến staffs thì nó sẽ nhận tất cả các item còn lại trong people kể từ item Nguyen My Hanh trở đi.

for of vs for in

for of mới được sử dụng trong es6 còn for in thì đã được sử dụng trong javascript từ trước. for of giống với spread operator, cũng chỉ sử dụng được với các iterable object. (Muốn biết object nào là iterable, thì bạn hãy console.log nó ra, nếu thấy có prototype là Symbol.iterator tức là có thể sử dụng được với for of hoặc spread operator ....

const currencies = ['Dong', 'USD', 'euro', 'yuan'];

for (const index in currencies) {
    console.log(index, currencies[index]);
}
// 0 Dong
// 1 USD
// 2 euro
// 3 yuan

for (const value of currencies) {
    console.log(value);
}
// Dong
// USD
// euro
// yuan

for of bao gồm cả key, value:

for (const [index, value] of currencies.entries()) {
    console.log(value);
}
// 0 Dong
// 1 USD
// 2 euro
// 3 yuan

for of khá là đa năng khi nó có thể thực hiện loop với Array, Object, DOM nodes. Nhưng nếu bạn đã quen thuộc với vòng lặp for thông thường hoặc forEach thì cũng không nhất thiết phải thay đổi làm gì. Các nội dung mà mình đề cập, được liệt kê theo mức độ sử dụng trong project từ nhiều tới thấp. Nói cách khác, mình cũng thi thoảng mới động tới for of chứ không phải lúc nào loop cũng dùng nó, mà mình thường dùng với map, filter, find hơn (jquery, lodash).

Array Methods

Mình giới thiệu ra đây 6 method mới của Array. 2 cái đầu tiên đó là Array.from()Array.of(). Mục đích của 2 function này đều là để convert các object khác thành Array. Ví dụ như khi mình get 1 list các posts từ server về chẳng hạn. Dữ liệu ở dạng JSON. Vậy thì sẽ không thể sử dụng được các function kèm theo với Array như push, shift hay map được. Giải pháp rất đơn giản: ném listPost đó vào Array.from(listPost), ta sẽ thu được 1 Array chính hiệu với đầy đủ method ta cần.

const numberArr = Array.of(1, 2, 30, 50, 100);
console.log(numberArr); //[1, 2, 30, 50, 100]

2 method tiếp là Array.findArray.findIndex. 2 method này giống với method filter trong jquery, khác biệt là Array.find sẽ chỉ trả lại item đầu tiên nó cho là đúng chứ không phải là trả lại mảng các item thỏa mãn điều kiện, cách làm việc tương tự với Array.findIndex, nhưng findIndex sẽ chả lại index của item.

const people = [
  {name: 'james', age: 18},
  {name: 'Anthony', age: 23},
  {name: 'Hanh America', age: 29}
]

const james = people.find(value => value.name == 'james');
const jamesIndex = people.findIndex(value => value.name == 'james');
console.log(james); //Object {name: "james", age: 18}
console.log(jamesIndex); //0

2 method cuối là Array.someArray.every, cả 2 đều sẽ check xem các item trong Array thỏa mãn 1 điều kiện nào đó hay không, nếu tất cả đều thỏa mãn thì Array.every sẽ trả lại true còn nếu có ít nhất 1 thì Array.some sẽ trả lại true, các trường hợp còn lại là false. Nhưng thực sự ứng dụng của 2 method này khá ít, và cho tới giờ mình vẫn chưa dùng tới nên về chi tiết sẽ để các ban tự tìm hiểu.

class

Thực chất thì class không thay đổi nhiều ở trong ES6 so với javascript. Nếu có thì chỉ là các thay đổi nho nhỏ để code sảng sủa và clear hơn thôi. ES6 bổ sung thêm 1 vài prototype method như set, get, khai báo function, async, generator ngắn gọn hơn.

  class Dog extens  Animal {
      constructor(name) {
          super(name);
          this.bark = "GO GO";
      }

      set setName(name) {
          return this.name = name.toUpperCase();
      }

      get getName() {
          return this.name;
      }

      static information() {
          return "Call without init";
      }
  }

Lời kết

Ngoài những nội dung được đề cập trên, còn các khái niệm khác mà tôi không đề cập đến như promise, symbol, generator, ... các bạn có thể google để biết thêm. Cám ơn đã đọc đến dòng này của bài viết, mỗi comment hoặc up vote đều sẽ là nguồn động lực rất lớn để tôi thực hiện các bài viết khác, thú vị hơn nên mong các bạn đừng ngại 😄. Hẹn gặp lại vào một ngày gần nhất. Thanks.