11/08/2018, 20:02

Giới thiệu Spread Operator của ES2015 (hay ES6)

Trong ES6 spec có giới thiệu một chức năng mới khá là lợi hại mà không phải ai cũng hay dùng, đó là Spread Operator . Chức năng này không có gì là xa lạ với các ngôn ngữ khác, trong thế giới Ruby thì nó tương đương splat operator . Spread Operator cho phép chuyển đổi một chuỗi thành nhiều ...

Trong ES6 spec có giới thiệu một chức năng mới khá là lợi hại mà không phải ai cũng hay dùng, đó là Spread Operator. Chức năng này không có gì là xa lạ với các ngôn ngữ khác, trong thế giới Ruby thì nó tương đương splat operator.

Spread Operator cho phép chuyển đổi một chuỗi thành nhiều argument (trong trường hợp gọi với hàm) hoặc thành nhiều phần tử (cho array). Thêm vào nữa nó cũng cho phép làm nhiệm vụ destructure. Operator này có syntax là 3 dấu chấm ..., khá là dị hợm và khó hiểu nhỉ, nhưng nói thế chứ cái splat bên Ruby cũng chẳng mấy dễ hiểu hơn cho người mới nhập môn.

Dùng operator này ra sao? Hãy cùng xem xét các chức năng chính của nó thông qua các ví dụ minh hoạ ở dưới.

Nếu chúng ta có một hàm như sau:

function sayMyName(firstName, lastName) {}

và chúng ta có một array object có thông tin của firstName và lastName:

var fullName = ["Rơi", "Lệ"]

để gán biến fullName vào argument firstName và lastName của hàm thì chúng ta làm như sau:

sayMyName(fullName[0], fullName[1])

Hoặc một cách khác tốt hơn nếu chúng ta không biết đc biến đó dài bao nhiêu với Function.prototype.apply:

sayMyName.apply(null, fullName)

với ES6 thì chúng ta có thể áp dụng spread operator ở đây:

sayMyName(...fullName)

ở đây spread sẽ tự động biến array fullName và tách chúng ra thành 2 arguments.

Mở rộng ví dụ thêm 1 tí:

function sayMyName(firstName, lastName, concertName, nickName) {}

chúng ta còn có thể áp dụng spread nhiều lần:

sayMyName(...fullName, "Thím Rợi", ...["Lợi"])

Có thể thấy là spread rất lợi hại trong việc biến đổi array thành argument.

Nếu chúng ta có 2 array như sau:

var album1 = ["Tình thôi xót xa", "Sài Gòn lụt"]
var album2 = ["Sót xa"]

vâng, ca sĩ Lệ Rơi muốn gộp tất cả các bài của album1 vào album2 thì phải làm sao? Cổ điển thì dùng hàm concat:

var album2 = album2.concat(album1)

Nhưng chúng ta có thể áp dụng spread ở đây:

var album2 = ["Sót xa", ...album1]

À, còn một cách khác nữa, đó là dùng hàm push:

for (let song in album1) {
  album2.push(song)
}

đấy là cách hơi chuối vì chúng ta phải vòng lặp rồi sau đó áp dụng hàm push, lưu ý là hàm này cho phép thêm vào nhiều phần từ dưới định dạng argument như sau:

array.push(arg1, arg2, arg3)

với ... thì chúng ta có thể tuỳ biến lại:

album2.push(...album1)

Gọn và đẹp nhỉ :)

Ví dụ chúng ta có một array danh sách học sinh như sau

var studentList = fetchStudentFromDb();

và chúng ta có một class ScienceClass nhận vào một array dánh sách, trong trường hợp này thường thì chúng ta sẽ nghĩ đến cách áp dụng Function.prototype.apply, nhưng tiếc là không thể dùng đc nó trong trường hợp này, tại vì hàm apply không thể đc gọi trên một construct, trong trường hợp này là construct new.

Để giải quyết chúng ta có thể áp dụng spread:

var myClass = new ScienceClass(...studentList)

Spread operator là một bổ sung đáng hoan nghênh của ngôn ngữ JS, nó giúp biến đổi array thành argument một cách dễ dàng, nó giống splat operator của ngôn ngữ Ruby.

Thế tôi mới tự hỏi là bây giờ muốn nhóm argument vào thành một array thì sao (chiều ngược lại), đáng tiếc là điều đó không thể làm được. Vd nhé:

function say(...messages) {
  return messages;
}

say('hello', 'world') // => ['hello', 'world']

tiếc là cú pháp trên không hợp lệ, chúng ta có thể dùng hàm arguments để trả về array tất cả argument nhưng dù gì cũng thiếu một bước là bị mất cái tên biến của cái array này.

hi vọng một ngày nào đó JS sẽ hỗ trợ, trong thời điểm bây giờ thì các bạn độc giả dùng Ruby cứ vững tin tiếp tục với Ruby nhé.

0