0

Toán tử (...) đã thay đổi Javascript (P2)

Bài viết này gồm 2 phần. Bạn có thể xem tiếp phần 1 tại link sau. :family_mmbb:

4. Improved array manipulation

4.1 Array construction

Một mảng [item1, item2, .., itemN] không cung cấp chức năng khác hơn là liệt kê các phần tử mảng ban đầu.

Spread operator cải tiến mảng bằng cách cho phép chèn thêm các mảng khác vào mảng khởi tạo ban đầu. Cải tiến này làm cho việc thực hiện các tác vụ thông thường được mô tả dưới đây trở nên dễ dàng hơn.

Tạo 1 mảng với các phần tử khởi tạo từ 1 mảng khác:

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]  

Mảng number1number2 được tạo ra bởi một array thông thường và trong khi chờ đợi khởi tạo với các item từ ban đầu.

Nối 2 hoặc nhiều arrays:

var odds = [1, 5, 7];  
var evens = [4, 6, 8];  
var all = [...odds, ...evens];  
console.log(all); // => [1, 5, 7, 4, 6, 8]  

Toàn bộ các mảng được tạo từ việc concatentation odds và evens arrays.

Clone một array instance:

var words = ['Hi', 'Hello', 'Good day'];  
var otherWords = [...words];  
console.log(otherWords);           // => ['Hi', 'Hello', 'Good day']  
console.log(otherWords === words); // => false  

Mảng otherWords là một clone version của mảng words.

Lưu ý rằng clone sẽ chỉ xảy ra trên mảng đó, nhưng không phải trên các phần tử chứa trong nó (it's not a deep clone).

4.2 Array destructure

Destructuring assignments, xuất hiện trong ECMAScript 6, là biểu thức mạnh mẽ để trích xuất dữ liệu từ các mảng và các đối tượng.

Là một phần của cấu trúc này, toán tử (...) trích xuất các phần của một mảng. Kết quả trích xuất luôn luôn là một mảng.

Về mặt cú pháp, rest operator phải là toán tử cuối cùng trong destructuring assignment: [extractItem1, ... extractedArray] = destructuredArray.

Nào hãy thử ứng dụng điều đó:

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

[coldSeason, ...otherSeasons] trích xuất first item 'winter' vào trong biến coldSeason và các phần tử còn lại vào trong mảng otherSeasons.

5. Spread operator and iteration protocols

Spread operator sử dụng giao thức iteration điều hướng qua các phần tử và thu thập các kết quả. Điều này làm cho spread operator thậm chí còn có giá trị hơn, bởi vì bất kỳ đối tượng nào cũng có thể định nghĩa toán tử sẽ khai thác dữ liệu như thế nào.

Một đối tượng là iterable(Có thể lặp) khi nó phù hợp với các giao thức iterable.

Giao thức iterable yêu cầu đối tượng chứa một thuộc tính đặc biệt. Tên thuộc tính phải là Symbol.iterator và value như một hàm trả về một iterator object.

interface Iterable {  
  [Symbol.iterator]() {
    //...
    return Iterator;
  }
}

Đối tượng iterator phải tuân theo giao thức Iterator. Nó cần phải cung cấp một thuộc tính next(), giá trị đó là một hàm trả về một đối tượng với các thuộc tính được thực hiện (một boolean để cho biết kết thúc lặp) và giá trị (kết quả lặp).

interface Iterator {  
  next() {
     //...
     return {
        value: <value>,
        done: <boolean>
     };
  };
}

Có vẻ như chúng ta mới chỉ hiểu các giao thức iteration từ mô tả bằng lời nói, nhưng đoạn code đằng sau những điều này là khá đơn giản.

Các đối tượng hoặc kiểu dữ liệu nguyên thủy phải được lặp lại để các spread operator để trích xuất dữ liệu từ nó.

Nhiều loại dữ liệu nguyên thủy và các objectiterable: strings, arrays, typed arrays, sets & maps. Vì vậy, chúng mặc định chạy được với các spread operator.

Ví dụ, chúng ta hãy xem cách một string phù hợp với các giao thức lặp:

var str = 'hi';  
var iterator = str[Symbol.iterator]();  
iterator.toString(); // => '[object String Iterator]'  
iterator.next();     // => { value: 'h', done: false }  
iterator.next();     // => { value: 'i', done: false }  
iterator.next();     // => { value: undefined, done: true }  
[...str];            // => ['h', 'i']

Tôi thích spread operator vì khả năng thực hiện object's custom iteration. Bạn có thể kiểm soát cách toán tử lây lan dùng đối tượng của bạn - một kỹ thuật coding hiệu quả.

Các ví dụ mẫu sau đây làm cho một đối tượng mảng giống như tuân thủ theo các giao thức iteration, sau đó biến đổi nó thành một mảng bằng cách sử dụng spread operator:

function iterator() {  
  var index = 0;
  return {
    next: () => ({ // Conform to Iterator protocol
      done : index >= this.length,
      value: this[index++]
    })
  };
}
var arrayLike = {  
  0: 'Cat',
  1: 'Bird',
  length: 2
};
// Conform to Iterable Protocol
arrayLike[Symbol.iterator] = iterator;  
var array = [...arrayLike];  
console.log(array); // => ['Cat', 'Bird']  

arrayLike[Symbol.iterator] tạo ra một property trên object có chứa iteration function iterator(), làm cho object tuân theo giao thức iterable.

iterator() trả về một object (tuân theo giao thức iteration) với thuộc tính next là một hàm trả về đối tượng: {done: <boolean>, value: <item>}.

Kể từ đó arrayLikeiterable, spread operator được sử dụng để trích xuất các phần tử vào 1 array: [...arrayLike].

6. Finale

Sự xuất hiện của toán tử ba chấm thêm một loạt các tính năng tuyệt vời cho JavaScript.

Rest parameter khiến việc thu thập các tham số trở nên dễ dàng hơn bao giờ hết. Đó là một sự thay thế hợp lý cho các đối số đối tượng mảng được hardcode. Nếu tình huống cho phép lựa chọn giữa rest parameter và các đối số, hãy sử dụng rest parameter.

.apply() không thuận tiện cho cú pháp rườm rà của nó. Spread operator là một sự thay thế tốt khi các đối số phải được lấy ra từ một mảng.

Spread operator cải thiện các mảng thông thường. Bạn có thể khởi tạo, ghép nối và mảng nhân bản đơn giản hơn rất nhiều.

Bạn có thể trích xuất các phần của mảng bằng cách sử dụng các phép gán cấu trúc. Kết hợp với các giao thức lặp, spread operator có thể được sử dụng một cách cấu hình được.

Tôi hy vọng từ bây giờ spread operator sẽ xuất hiện thường xuyên hơn trong các đoạn code của bạn!

Tham khảo

https://rainsoft.io/how-three-dots-changed-javascript/


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí