Hướng dẫn three dot in javascript

"Three dots" là một khái niệm cực kì khó nhai cho những ai mới bắt đầu nguyên cứu về những tính năng mới của ES6, three dots hay còn gọi với cái tên là "spread syntax". Tại sao ES6 lại đưa syntax mới đầy mạnh mẽ này vào. Sau nhiều ngày mày mò tìm hiểu, mình quyết định chia sẽ bài viết này để chia sẽ với mọi người để cho mọi người hiểu hơn về syntax này. Chúng ta hãy được vấn đề khi chưa có "syntax" này nhé. Như các bạn đã biết khi làm việc với "agruments" object. Thật ra agruments là một biến cục bộ trong function, chứa toàn bộ các tham số được truyền vào. Các bạn xem ví dụ để hiểu hơn về vai trò của arguments. Ở đây mình sẽ đưa ra 2 ví dụ mà ES5 xử lý thông thường.

Kịch bản 1: In ra tất các các tham truyền vào:

function display(){
    // arguments is an array-like object
    var args = Array.apply(null, arguments);
    console.log(args); // [1, 2, 3]
}
display(1, 2, 3)

Arguments is an array-like object. Thật ra arguments là một object giống array nhưng không phải là array. Tại sao lại kì quặc như vậy, arguments có phương thức length, ta có thể gọi value bằng chỉ số index 1,2,3... Nhưng ta không thể gọi được các phương thức của array, vì do không có prototype là array =)). Khi làm việc với arguments thật không dễ chịu tí nào, ta phải chuyển arguments object thành array rồi mới sử dụng được các method của array bằng cách Array.apply(null, arguments). Thật phiền phải không nào

Kịch bản 2: Concat hai array với nhau Đây là cách mà ES5 sử lý vấn đề này:

var fruits = ['banana'];  
var moreFruits = ['apple', 'orange'];  
Array.prototype.push.apply(fruits, moreFruits);  
console.log(fruits); // => ['banana', 'apple', 'orange'] 

Kết quả như kì vọng của chúng ta. Vấn đề ở đây là ta "mượn hàm" của array qua thông prototype, rồi gọi push method, rồi gọi đến apply..Cách tiếp cận này khá rườm rà. Với sự ra đời của "... three dots" đã giải quyết 2 vấn đề thường gặp của chúng ta nhưng thế nào nhé

Three dots

The rest operator

The rest operator được sử dụng lấy tất cả các tham số tryền vào, chúng ta giải quyết kịch bản 1 như thế nào nhé

function display(...args) {  
   console.log(args);
}
display('welcome', 'to', 'Earth'); // => ['welcome', 'to', 'Earth']

Ở đây args là array. Args này có prototype là array => sẽ sử dụng đầy đủ tính năng của array. Gọn hơn rất nhiều phải không ? Với tham số ...args của display method chúng ta nhận bao nhiêu đối số cũng được, hay nói cách khác là chúng ta có thể "spread" các tham số truyền vào.

The spread operator

The spread operator được sử dụng cho array construction and destructuring => chúng ta sẽ giải quyết problem ở kịch bản 2 như sau

let cold = ['autumn', 'winter'];  
let warm = ['spring', 'summer'];  
// construct an array
[...cold, ...warm] // => ['autumn', 'winter', 'spring', 'summer']

// function arguments from an array
cold.push(...warm);  
cold              // => ['autumn', 'winter', 'spring', 'summer']  

Three dots còn làm được nhiều điều hơn nữa. Khi chúng ta khởi tạo new Date (), thì chúng ta không thể inject array vào constructor của Object Date được. Nhưng với three dots thì có thể làm được điều đó

var dateFields = [1970, 0, 1];  // 1 Jan 1970
var d = new Date(...dateFields);

Copy Array

Với three dots chúng ta có thể copy array một cách nhanh chóng

var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4); 

// arr2 becomes [1, 2, 3, 4]
// arr remains unaffected

Inject params to constructor

Với Class là một tính năng được ES6 giới thiệu, với "spread syntax" ta có thể thiết lập được param của constructor một cách nhanh chóng, khi mà chúng ta k thể gọi arguments trong constructor được =))

class King {  
   constructor(name, country) {
     this.name = name;
     this.country = country;     
   }
   getDescription() {
     return `${this.name} leads ${this.country}`;
   }
}
var details = ['Alexander the Great', 'Greece'];  
var Alexander = new King(...details);  
Alexander.getDescription(); // => 'Alexander the Great leads Greece' 

Quickly initial elements from another array

Speard operator thật mạnh mẽ, nó có thể khởi tạo array literal từ array khác nữa nó. Hãy xem cách "..." thực hiện điều này như thế này nhé

var initial = [0, 1];  
var numbers1 = [...initial, 5, 7];  
console.log(numbers1); // => [0, 1, 5, 7]  
let numbers2 = [4, 8, ...initial];  
console.log(numbers2); // => [4, 8, 0, 1]  

Array destructure

Destructuring assignments là một tính năng rất thú vị của ES6, đây là một phương thức khá khó tiêu, nó giúp mình tách data từ array hoặc object, nó rất giống với method list của php =)). Các bạn có thể đọc thêm bài viết này để học hỏi thêm nha https://viblo.asia/vinhnguyen/posts/xlbRBNQgRDM

var seasons = ['winter', 'spring', 'summer', 'autumn'];  
var coldSeason, otherSeasons;  
[coldSeason, ...otherSeasons] = seasons;
console.log(coldSeason);   // => 'winter'  
console.log(otherSeasons); // => ['spring', 'summer', 'autumn'] 

Finale

Qua bài viết này mình đã giới thiệu "three dots" sinh ra để giải quyết vấn đề "arguments" object rườm rà khi nhận giá trị từ param inject vào, việc sử dụng "spread syntax" sẽ làm cho code của chúng ta trở nên clear hơn rất nhiều, qua đây mà sẽ improve khi thao tác với array literals như là khởi tạo, clone, concatenate... và Destructuring bằng cách sử dụng "spread operator". Đối với mình "three dots" rất tuyệt đấy. Happy coding =))