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

Tập hợ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à được truy cập bằng chỉ mục được đánh số. Những giá trị được lưu trữ trong một tập hợp đã lập chỉ mục là gán chỉ mục được đánh số bắt đầu từ 0, một mẫu có tên là "zero-indexing". 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 chúng.

Mảng là một vùng chứa có thể chứa 0 hoặc nhiều giá trị 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 các mảng khác. Các giá trị được lưu trữ trong một mảng là đôi khi được gọi là "phần tử" của mảng.

Tạo một mảng

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

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

const myArray = [];

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

const myArray = new Array();

Cả cú pháp giá trị cố định mảng và cú pháp hàm khởi tạo mảng đều cho phép bạn điền dữ liệu cho mảng khi thông tin đó được tạo, mặc dù các cú pháp có khác nhau một chút về cách các giá trị được xác định. Cú pháp ký tự mảng sử dụng các giá trị được phân tách bằng dấu phẩy giữa dấu ngoặc, 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 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 giá trị ngoại lệ hành vi đặc biệt:

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 bằng số chỗ trống cho các giá trị. Điều này không áp đặt bất kỳ các giới hạn của mảng. Bạn có thể thêm và xoá các mục khỏi thư viện theo cách tương tự giống như giá trị cố định mảng.

// 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 ô trống (đôi khi được gọi là "mảng thưa") là các mảng đặc biệt trường hợp. Thay vì chứa giá trị undefined hoặc null rõ ràng, hãy để trống vị trí thường, nhưng không phải lúc nào cũng được coi là giá trị undefined ở nơi khác trong ngôn ngữ.

Bạn có thể vô tình tạo một mảng thưa thớt bằng cú pháp giá trị cố định của mảng bằng cách bỏ qua một giá trị giữa dấu phẩy khi bạn tạo 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à một giá trị có ý nghĩa trong mọi ngữ cảnh, nhưng ô trống được tính vào tổng độ dài của mảng, có khả năng dẫn đến kết quả không mong muốn khi lặp lại qua các giá trị của 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à hạn chế so với một số quyết định thiết kế ban đầu của JavaScript. Tránh sử dụng các mảng thưa trong quá trình phát triển hiện đại.

Giống như giá trị gốc, giá trị cố định của 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. Do mảng là một dạng đặc biệt của đối tượng, nên cú pháp giá trị cố định của mảng và Cú pháp new Array() tạo ra các kết quả giống hệt nhau về chức năng: một đối tượng mà 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ì hai kết quả giống hệt nhau và cú pháp giá trị cố định của mảng ngắn gọn hơn và giá trị cố định, chúng tôi khuyên bạn nên luôn sử dụng cú pháp mảng giá trị thay vì Cú pháp new Array().

Truy cập các giá trị mảng

Bạn có thể truy cập các phần tử riêng lẻ bên trong mảng bằng cách sử dụng ký hiệu dấu ngoặc, a một cặp dấu ngoặc vuông ([]) theo sau mảng hoặc giá trị nhận dạng của mảng đó có chứa 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

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

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 thao tác chỉ định

Giải cấu trúc gán là một cách ngắn gọn để trích xuất một phạm vi giá trị từ các mảng hoặc đối tượng và gán chúng vào một tập hợp mã 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ù nó không sửa đổi mảng hoặc đối tượng gốc.

Quá trình gán huỷ cấu trúc sử dụng một danh sách giá trị nhận dạng giống mảng hoặc giống đối tượng để theo dõi các giá trị. Ở hình thức đơn giản nhất, được gọi là mẫu liên kết phá cấu trúc, mỗi giá trị sẽ được giải nén khỏi mảng hoặc đối tượng và được 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

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 xảy ra theo trình tự, từ trái sang phải. Một mã nhận dạng 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 huỷ cấu trúc một đối tượng. Tuy nhiên, nếu các giá trị nhận dạng dùng trong quá trình gán gỡ lỗi khớp với các khoá của đối tượng thuộc tính, thì các giá trị nhận dạng đó được điền sẵn bằng thuộc tính tương ứng bất kể thứ tự chỉ định các giá trị đó:

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 phá cấu trúc cũng cho phép bạn gán giá trị mặc định trong trường hợp phá cấu trúc giá trị là một ô trống, như trong trường hợp một mảng thưa thớt hoặc một Giá trị undefined.

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

firstValue;
> true

secondValue;
> "Default string."

Quá trình giải cấu trúc không ép buộc các giá trị vào các loại cụ thể. Điều này có nghĩa là giá trị "falsy", chẳng hạn như trống chuỗi ("") hoặc null, vẫn được coi là các giá trị được tách rời 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ử trải rộng

Sử dụng toán tử trải rộng (...), đã ra mắt trong ES6 để mở rộng dữ liệu có thể lặp lại cấu trúc 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ử phân tán đứng ngay trước cấu trúc dữ liệu cần 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 trải rộng 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 trải rộng trong các ngữ cảnh sau:

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

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 '...'

Nhưng bạn sao chép một mảng bằng cách trải rộng mảng ban đầu thành một giá trị cố định của 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 2 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 các đối số riêng lẻ trong 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ử phân tán đã được mở rộng để tương thích với giá trị cố định của đối tượng trong ES2018. Tương tự như với mảng, bạn có thể sử dụng toán tử phân tán để sao chép hoặc hợp nhất đố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ử phân tán tạo ra "nông" sao chép. Điều này có nghĩa là tính năng này không sao chép nguyên mẫu của đối tượng gốc và không thể liệt kê các thuộc tính.

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 nhớ rằng 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 vào một mảng hoặc một mảng vào một đối tượng.

Nhân viên vận hành phần còn lại

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

Khi được sử dụng cùng với thao tác gán huỷ cấu trúc, cú pháp được gọi là "thuộc tính còn lại" của bạn.

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ó tên là "thông số còn lại" cú pháp:

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 của ES6 được thiết kế để lưu trữ dữ liệu nhị phân có cấu trúc, dành cho chẳng hạn như khi làm việc với các tệp được tải lên hoặc WebGL.

Tương tự như với Symbols (Biểu tượng), %TypedArray% hàm nội tại (thường được ghi nhận là %TypedArray% hoặc @@TypedArray để tránh 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 trong theo nghĩa thông thường và bạn không thể gọi nó bằng new hoặc gọi nó trực tiếp. Thay vào đó, %TypedArray% đề cập đến một lớp cấp cao mẹ của cá nhân hàm dựng, mỗi hàm khởi tạo hoạt động với một định dạng dữ liệu nhị phân cụ thể. Chiến lược phát hành đĩa đơn lớp cấp cao %TypedArray% nội tại cung cấp các thuộc tính và phương thức tiện ích tất cả lớp con hàm khởi tạo %TypedArray% và thực thể của lớp đó sẽ kế thừa.

Kiểm tra kiến thức

Cho `const myArray = [ 30, 50, 70 ];` `myArray[1]` có nghĩa là gì quay lại?

70
30
50

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

Một thông báo lỗi
Undefined
Null
9