Tập hợp được lập chỉ mục

Bộ sưu tập được lập chỉ mục là một cấu trúc dữ liệu, trong đó các phần tử được lưu trữ và truy cập bằng chỉ mục được đánh số. Các giá trị lưu trữ trong tập hợp được lập chỉ mục được chỉ định cho các chỉ mục được đánh số bắt đầu từ 0, một mẫu gọi là "zero-Indexed". Sau đó, bạn có thể truy cập các giá trị được lưu trữ trong tập hợp được lập chỉ mục bằng cách tham chiếu chỉ mục của tập hợp đó.

Mảng

Mảng là một vùng chứa có thể chứa hoặc không chứa bất kỳ giá trị nào thuộc bất kỳ loại dữ liệu nào, bao gồm cả các đối tượng phức tạp hoặc mảng khác. Các giá trị được lưu trữ trong một mảng đôi khi được gọi là "phần tử" của mảng đó.

Tạo mảng

Tương tự như với các loại dữ liệu gốc, có 2 cách tiếp cận để tạo mảng: dưới dạng giá trị cố định dạng mảng hoặc bằng cách gọi hàm khởi tạo Array() tích hợp của JavaScript bằng new Array(). Việc chỉ định một mảng cho một biến cung cấp một cách thức rất linh hoạt và có thể lặp lại để gán nhiều giá trị cho một giá trị nhận dạng duy nhất.

Cú pháp giá trị cố định dạng mảng sử dụng một tập hợp dấu ngoặc ([]) xung quanh các giá trị dữ liệu được phân tách bằng dấu phẩy hoặc 0:

const myArray = [];

Cú pháp hàm khởi tạo mảng sử dụng đối tượng Array tích hợp của JavaScript làm hàm khởi tạo với từ khoá new:

const myArray = new Array();

Cả cú pháp giá trị cố định mảng và hàm khởi tạo mảng đều cho phép bạn điền thông tin vào một mảng khi mảng đó được tạo, mặc dù cú pháp hơi khác nhau về cách xác định các giá trị đó. Cú pháp giá trị cố định của mảng sử dụng các giá trị được phân tách bằng dấu phẩy giữa các dấu ngoặc vuông, trông giống như mảng thu được:

const myArray = [ true, null, "String", false ];

myArray;
> [ true, null, "String", false ]

Cú pháp hàm khởi tạo mảng sẽ lấy các giá trị được phân tách bằng dấu phẩy làm đối số, với một ngoại lệ đặc biệt về hành vi:

const myArray = new Array( true, null, "String", false );

myArray;
> Array(4) [ true, null, "String", false ]

Khi một giá trị số được truyền đến hàm khởi tạo Array, giá trị đó không được gán cho vị trí thứ 0 trong mảng thu được. Thay vào đó, một mảng sẽ được tạo với số lượng khe trống đó cho các giá trị. Việc này không áp dụng bất kỳ giới hạn nào đối với mảng. Bạn có thể thêm và xoá các mục khỏi phần tử đó theo cách tương tự như đối với mảng giá trị cố định.

// Firefox:\
const myArray = new Array( 10 );

myArray;
> Array(10) [ <10 empty slots> ]
// Chrome:
const myArray = new Array( 10 );

myArray;
> (10) [empty × 10]

Mảng chứa các khe trống (đôi khi gọi là "mảng thưa") là các trường hợp đặc biệt. Thay vì chứa giá trị undefined hoặc null rõ ràng, các khe trống thường (nhưng không phải lúc nào cũng) được coi là giá trị undefined ở những nơi khác trong cùng một ngôn ngữ.

Bạn có thể vô tình tạo một mảng thưa bằng cú pháp giá trị cố định mảng bằng cách bỏ qua một giá trị giữa các dấu phẩy khi tạo một giá trị cố định mảng:

const myArray = [ true,, true, false ];

myArray;
> Array(4) [ true, <1 empty slot>, true, false ]

Mặc dù không được coi là giá trị có ý nghĩa trong mọi ngữ cảnh, nhưng vị trí trống cũng là yếu tố ảnh hưởng đến tổng thời lượng của mảng. Điều này có thể dẫn đến các kết quả không mong muốn khi lặp lại các giá trị của một mảng:

const myArray = [ 1,, 3, 4 ];

myArray.length;
> 4

for( const myValue of myArray ) {
  console.log( myValue + 10 );
}
> 11
> NaN
> 13
> 14

Hành vi này là sự kế thừa từ một số quyết định thiết kế ban đầu của JavaScript. Tránh sử dụng mảng thưa trong quá trình phát triển hiện đại.

Giống như dữ liệu gốc, giá trị cố định dạng mảng kế thừa các thuộc tính và phương thức từ hàm khởi tạo tương ứng. Vì mảng là một dạng đối tượng đặc biệt, nên cú pháp giá trị cố định của mảng và cú pháp new Array() sẽ tạo ra kết quả giống hệt nhau về mặt chức năng: một đối tượng kế thừa nguyên mẫu từ hàm khởi tạo Array.

const arrayLiteral = [];
const arrayConstructor = new Array();

typeof arrayLiteral;
> "object"

arrayLiteral;
> Array []
    length: 0
    <prototype>: Array []

typeof arrayConstructor;
> "object"

arrayConstructor;
> Array []
    length: 0
    <prototype>: Array []

Vì 2 kết quả giống nhau và cú pháp giá trị cố định dạng mảng ngắn gọn và cố định hơn, bạn nên luôn sử dụng cú pháp giá trị cố định dạng mảng thay vì cú pháp new Array().

Truy cập vào các giá trị mảng

Bạn có thể truy cập vào từng phần tử bên trong mảng bằng cách sử dụng ký hiệu dấu ngoặc, một cặp dấu ngoặc ([]) theo sau mảng hoặc giá trị nhận dạng của mảng có chứa một số tham chiếu đến chỉ mục của phần tử đó:


[ "My string", "My other string" ][ 1 ];
> "My other string"

const myArray = [ "My string", 50, true ];

myArray[ 0 ];
> "My string"

myArray[ 1 ];
> 50

myArray[ 2 ];
> true

Mảng trong JavaScript không có tính kết hợp, nghĩa là bạn không thể sử dụng một chuỗi tuỳ ý làm chỉ mục. Tuy nhiên, các giá trị số dùng để truy cập vào các phần tử trong một mảng sẽ bị buộc thành giá trị chuỗi, nghĩa là bạn có thể sử dụng giá trị chuỗi chỉ chứa các ký tự số:

const myArray = [ "My string", 50, true ];

myArray[ 2 ];
> true

myArray[ "2" ];
> true

Việc cố gắng truy cập vào một phần tử bên ngoài những phần tử được xác định trong mảng sẽ dẫn đến undefined, không phải là lỗi:

const myArray = [ "My string", 50, true ];

myArray[ 9 ];
> undefined

Huỷ cấu trúc chỉ định

Chỉ định giải cấu trúc là một cách ngắn gọn để trích xuất một dải giá trị từ các mảng hoặc đối tượng và gán chúng cho một tập hợp các giá trị nhận dạng, một quá trình đôi khi được gọi là "giải nén" cấu trúc dữ liệu gốc, mặc dù không sửa đổi mảng hoặc đối tượng gốc.

Việc chỉ định cấu trúc giải mã sử dụng một danh sách giá trị nhận dạng giống mảng hoặc đối tượng để theo dõi các giá trị. Ở dạng đơn giản nhất, được gọi là giải cấu trúc mẫu liên kết, mỗi giá trị được giải nén khỏi mảng hoặc đối tượng và gán cho một biến tương ứng, được khởi tạo bằng let hoặc const (hoặc var):

const myArray = [ "A string", "A second string" ];
const [ myFirstElement, mySecondElement ] = myArray;

const myObject = { firstValue: false, secondValue: true };
const { myProp, mySecondProp } = myObject;

myFirstElement;
> "My string"

mySecondElement;
> "Second string"

myProp;
> false

mySecondProp;
> true

Sử dụng dấu ngoặc nhọn ({}) để huỷ cấu trúc một đối tượng và dấu ngoặc vuông ([]) để huỷ cấu trúc một mảng.

const myArray = [ false, true ];
const myObject = { firstValue: false, secondValue: true };

const [ myProp, mySecondProp ] = myObject;
> Uncaught TypeError: myObject is not iterable

const { myElement, mySecondElement } = myArray;

myElement
> undefined

mySecondElement;
> undefined

Việc huỷ cấu trúc một mảng diễn ra theo thứ tự tuần tự, từ trái sang phải. Mỗi giá trị nhận dạng trong quá trình chỉ định giải cấu trúc tương ứng với phần tử của mảng có cùng chỉ mục:

const myArray = [ 1, 2, 3 ];
const [ myElement, mySecondElement, myThirdElement ] = myArray;

myElement;
> 1

mySecondElement;
> 2

myThirdElement;
> 3

Đây cũng là hành vi mặc định khi giải cấu trúc một đối tượng. Tuy nhiên, nếu giá trị nhận dạng dùng trong quá trình chỉ định giải cấu trúc khớp với khoá thuộc tính của đối tượng, thì các giá trị nhận dạng đó sẽ được điền bằng giá trị thuộc tính tương ứng, bất kể thứ tự được chỉ định trong:

const myObject = { firstValue: 1, secondValue: 2, thirdValue 3 };
const { secondValue, thirdValue, firstValue } = myObject;

firstValue;
> 1

secondValue;
> 2

thirdValue;
> 3

Bạn có thể bỏ qua các phần tử bằng cách bỏ qua giá trị nhận dạng:

const myArray = [ 1, 2, 3 ];
const [ firstValue,, secondValue ] = myArray;

firstValue;
> 1

secondValue;
> 3

Cú pháp giải cấu trúc cũng cho phép bạn chỉ định các giá trị mặc định trong trường hợp giá trị được giải cấu trúc là một vùng trống, như trong trường hợp một mảng thưa thớt hoặc giá trị undefined.

const myArray = [ true, ];
const [ firstValue = "Default string.", secondValue = "Default string." ] = myArray;

firstValue;
> true

secondValue;
> "Default string."

Việc giải cấu trúc không ép buộc các giá trị thành một số loại cụ thể. Điều này có nghĩa là các giá trị "falsy" (chẳng hạn như chuỗi trống ("") hoặc null) vẫn được coi là các giá trị có cấu trúc có ý nghĩa:

const myArray = [ false, null, 0, "",, undefined ];
const [ falseValue = true, nullValue = true, zeroValue = true, emptyStringValue = true, emptySlot = true, undefinedValue = true ] = myArray;

falseValue;
> false;

nullValue;
> null

zeroValue;
> 0

emptyStringValue;
> ""

emptySlot;
> true

undefinedValue;
> true

Toán tử mở rộng

Sử dụng toán tử mở rộng (...), ra mắt trong ES6 để mở rộng cấu trúc dữ liệu lặp, chẳng hạn như mảng, chuỗi hoặc giá trị cố định đối tượng thành các phần tử riêng lẻ. Toán tử mở rộng đứng ngay theo cấu trúc dữ liệu sẽ được mở rộng hoặc giá trị nhận dạng của một biến chứa cấu trúc dữ liệu đó.

const myArray = [ 1, 2, 3 ];

console.log( ...myArray );
> 1 2 3

Cú pháp lan truyền được dùng chủ yếu để sao chép và kết hợp các mảng:

const myArray = [ 4, 5, 6 ];
const mySecondArray = [1, 2, 3, ...myArray ];

mySecondArray;
> Array(6) [ 1, 2, 3, 4, 5, 6 ]

Bạn chỉ có thể sử dụng cú pháp mở rộng trong các ngữ cảnh sau:

Đối với mảng và chuỗi, cú pháp mở rộng chỉ áp dụng khi không có hoặc có nhiều đối số trong một lệnh gọi hàm hoặc các phần tử trong một mảng. Ví dụ đầu tiên về cú pháp toán tử lan truyền trong phần này sẽ phù hợp vì nó truyền ...myArray dưới dạng một đối số cho phương thức console.log tích hợp.

Ví dụ: bạn không thể chỉ định dữ liệu đang được trải rộng cho một biến bên ngoài một mảng khác:

const myArray = [ 1, 2, 3 ];
const spreadVariable = ...myArray;
> Uncaught SyntaxError: Unexpected token '...'

Tuy nhiên, bạn sao chép một mảng bằng cách mở rộng mảng ban đầu thành một giá trị cố định mảng:

const myArray = [ 1, 2, 3 ];
const spreadArray = [ ...myArray ];

spreadArray;
> Array(3) [ 1, 2, 3 ]

Cách hợp nhất các phần tử tạo thành hai hoặc nhiều mảng thành một mảng duy nhất:

const myArray = [ 1, 2, 3 ];
const mySecondArray = [ 4, 5, 6 ];
const myNewArray = [ ...myArray, ...mySecondArray ];

myNewArray;
> Array(6) [ 1, 2, 3, 4, 5, 6 ]

Hoặc để truyền các phần tử của một mảng dưới dạng đối số riêng lẻ trong một lệnh gọi hàm:

const myArray = [ true, false ];
const myFunction = ( myArgument, mySecondArgument ) => {
    console.log( myArgument, mySecondArgument );
};

myFunction( ...myArray );
> true false

Toán tử trải rộng được mở rộng để hoạt động với giá trị cố định đối tượng trong ES2018. Tương tự như mảng, bạn có thể sử dụng toán tử mở rộng để sao chép hoặc hợp nhất các đối tượng:

const myObj = { myProperty : true };
const mySecondObj = { ...myObj };

mySecondObj;
> Object { myProperty: true }
const myFirstObj = { myProperty : true };
const mySecondObj = { additionalProperty : true };
const myMergedObj = { ...myFirstObj, ...mySecondObj };

myMergedObj;
> Object { myProperty: true, additionalProperty: true }

Toán tử mở rộng sẽ tạo các bản sao "cận". Như vậy có nghĩa là thuộc tính này không sao chép các thuộc tính nguyên mẫu và không thể liệt kê của đối tượng gốc.

const myCustomPrototype = { protoProp: "My prototype." };
const myObj = Object.create( myCustomPrototype, {
    myEnumerableProp: {
        value: true,
        enumerable: true
    },
    myNonEnumerableProp: {
        value: false,
        enumerable: false
    }
});
const myNewObj = { ...myObj };

myObj;
> Object { myEnumerableProp: true, … }
    myEnumerableProp: true
    myNonEnumerableProp: false
    <prototype>: Object { protoProp: "My prototype." }

myNewObj;
> Object { myEnumerableProp: true }
    myEnumerableProp: true
    <prototype>: Object { … }

Hãy lưu ý rằng các mảng và đối tượng không thể dùng thay thế cho nhau. Bạn không thể trải một đối tượng thành một mảng hoặc một mảng vào một đối tượng.

Đơn vị vận hành dịch vụ nghỉ ngơi

Mặc dù cú pháp của chính toán tử là giống nhau, nhưng toán tử còn lại (...) thực hiện hàm ngược lại dựa trên ngữ cảnh sử dụng toán tử đó. Thay vì mở rộng cấu trúc dữ liệu lặp lại thành các phần tử riêng lẻ, như trong quá trình huỷ cấu trúc chỉ định hoặc dưới dạng tham số hàm, toán tử còn lại sẽ kết hợp các phần tử vào một cấu trúc dữ liệu lặp. Tên này xuất phát từ việc dữ liệu này được dùng để thu thập "phần còn lại" của một tập hợp giá trị dữ liệu.

Khi dùng cùng với thao tác chỉ định cấu trúc, cú pháp được gọi là cú pháp "rest property" (thuộc tính còn lại).

const myArray = [ "First", "Second", "Third", "Fourth", "Fifth" ];

[ myFirstElement, mySecondElement, ...remainingElements ] = myArray;

myFirstElement;
> "First"

mySecondElement;
> "Second"

remainingElements;
> Array(3) [ "Third", "Fourth", "Fifth"]

Khi dùng để cung cấp số lượng đối số vô hạn cho một hàm, cú pháp được gọi là cú pháp "tham số còn lại":

function myFunction( ...myParameters ) {
    let result = 0;
    myParameters.forEach( ( myParam ) => {
        result += myParam;
    });
    return result;
};

myFunction( 2, 2 );
> 4

myFunction( 1, 1, 1, 10, 5 );
> 18

myFunction( 10, 11, 25 );
> 46

%TypedArray%

Mảng được nhập là một tính năng ES6 được thiết kế để lưu trữ dữ liệu nhị phân có cấu trúc, chẳng hạn như khi làm việc với các tệp được tải lên hoặc WebGL.

Giống như Biểu tượng, hàm nội tại %TypedArray% (thường được ghi nhận là %TypedArray% hoặc @@TypedArray để không bị nhầm lẫn với thuộc tính toàn cục) không phải là hàm khởi tạo theo nghĩa thông thường và bạn không thể gọi hàm này bằng new hoặc gọi trực tiếp hàm này. Thay vào đó, %TypedArray% đề cập đến một lớp cấp cao mẹ của các hàm khởi tạo riêng lẻ, mỗi hàm này hoạt động với một định dạng dữ liệu nhị phân cụ thể. Lớp cấp cao %TypedArray% hàm nội tại cung cấp các thuộc tính và phương thức tiện ích mà tất cả các lớp con của hàm khởi tạo %TypedArray% và các thực thể của các lớp con đó đều kế thừa.

Kiểm tra kiến thức

Cho sẵn `const myArray = [ 30, 50, 70 ];` `myArray[1]` trả về gì?

50
30
70

Nếu "myArray" có 3 giá trị, thì "myArray[9]" sẽ trả về giá trị gì?

Undefined
Thông báo lỗi
9
Null