31 Array@@iterator
31.1 基本介绍
@@iterator
方法(通过 array[Symbol.iterator]
访问)返回一个新的数组迭代器对象,该对象包含数组中每个索引的值。
array[Symbol.iterator]()
输入参数:无。
输出:一个新的迭代器对象,可用于遍历数组的元素。
注意事项:
- 该迭代器遵循迭代器协议,具有
next()
方法。 - 每次调用
next()
方法会返回一个包含value
和done
属性的对象。value
:当前迭代的数组元素的值。done
:布尔值,表示迭代是否完成。
- 该方法是通用的,可用于类数组对象。
- 方法返回值和
Array.prototype.values
一致
31.2 手写实现
MyArray.prototype[Symbol.iterator] = function() {
let index = 0;
let array = this;
return {
// 返回对象包含next方法
next: function() {
if (index < array.length) {
let value = array[index];
index++;
// next()返回值有value和done属性
return { value: value, done: false };
} else {
return { value: undefined, done: true };
}
},
// 实现迭代器协议,返回自身(也是迭代器)
[Symbol.iterator]: function() { return this; }
};
};
// 测试用例
let arr = new MyArray(1, 2, 3);
for (let item of arr) {
console.log(item); // 输出 1, 2, 3
}
let iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
难点总结:
- 实现迭代器协议:需要提供
next()
方法和[Symbol.iterator]()
方法,使迭代器本身可迭代。 - 正确处理索引:需要跟踪当前索引,确保遍历完整个数组。
- 处理稀疏数组:迭代器会遍历所有索引,包括空槽,空槽的值为
undefined
。
32 Array.toLocaleString()
32.1 基本介绍
toLocaleString()
方法返回一个表示数组元素的字符串。数组中的元素将使用各自的 toLocaleString
方法转换成字符串,这些字符串由一个特定语言环境的字符串(例如逗号 ","
)分隔。
array.toLocaleString()
输入参数:无。
输出:一个字符串,表示数组的元素。
注意事项:
- 该方法不会修改原数组,是一个复制方法。
- 对于每个元素,调用其
toLocaleString
方法。如果元素为null
或undefined
,则转换为空字符串。 - 使用的分隔符是特定于语言环境的。
- 争对稀疏数组,空槽的行为和
undefined
一致
32.2 手写实现
MyArray.prototype.toLocaleString = function() {
let result = '';
let separator = ','; // 分隔符,实际应根据本地化设置,这里简化处理
for (let i = 0; i < this.length; i++) {
if (i > 0) result += separator;
let element = this[i];
if (element == null) { // null 或 undefined
result += '';
} else if (typeof element.toLocaleString === 'function') {
result += element.toLocaleString();
} else {
result += element.toString();
}
}
return result;
};
// 测试用例
let date = new Date('2020-01-01');
let arr = new MyArray(1234.567, date, 'Hello', null, undefined);
console.log(arr.toLocaleString());
// 输出示例:"1,234.567,1/1/2020, 12:00:00 AM,Hello,,"
难点总结:
- 处理不同类型的元素:需要调用元素的
toLocaleString
方法,处理数字、日期、字符串等类型。 - 处理
null
和undefined
:应转换为空字符串。 - 分隔符:分隔符应根据语言环境确定,简化情况下使用逗号。
33 Array.toReversed()
33.1 基本介绍
toReversed()
方法是 reverse() 方法对应的复制版本。它返回一个元素顺序相反的新数组。
array.toReversed()
输入参数:无。
输出:一个新的数组,元素顺序与原数组相反。
注意事项:
- 该方法不会修改原数组,是一个复制方法。
- 返回的新数组是原数组的浅拷贝。
- 对于稀疏数组,空槽的处理和
reverse
方法不一致,在该函数空槽将被视为undefined
33.2 手写实现
MyArray.prototype.toReversed = function() {
let length = this.length >>> 0;
let result = new MyArray();
result.length = length;
for (let i = 0; i < length; i++) {
// 直接赋值,空槽将被处理为undefined
result[i] = this[length - 1 - i];
}
return result;
};
// 测试用例
let arr = new MyArray(1, 2, 3);
let reversedArr = arr.toReversed();
console.log(reversedArr); // [3, 2, 1]
console.log(arr); // [1, 2, 3]
let sparseArr = new MyArray();
sparseArr[1] = 'a';
sparseArr[3] = 'b';
let reversedSparseArr = sparseArr.toReversed();
console.log(reversedSparseArr); // ['b', undefined, 'a', empty]
难点总结:
- 创建新数组:需要正确设置新数组的长度。
- 处理稀疏数组:和
reverse
不同,空槽将会被看作undefined
。 - 不修改原数组:必须确保原数组未被修改。
34 Array.toSorted()
34.1 基本介绍
toSorted()
方法是 sort() 方法的复制方法版本。它返回一个新数组,其元素按升序排列。
array.toSorted(compareFunction)
输入参数:
compareFunction(a, b)
(可选):用于定义排序顺序的函数。
输出:一个新的已排序数组。
注意事项:
- 该方法不会修改原数组,是一个复制方法。
- 排序行为与
sort()
方法相同。 - 对于稀疏数组,空槽处理行为和sort不一致,将会被视为
undefined
。
34.2 手写实现
MyArray.prototype.toSorted = function(compareFunction) {
let length = this.length >>> 0;
let elements = [];
let holesCount = 0;
// 将所有元素(包括空槽视为 undefined)收集到 elements 数组中
for (let i = 0; i < length; i++) {
if (i in this) {
let value = this[i];
elements.push(value);
} else {
// 空槽视为 undefined
elements.push(undefined);
}
}
if (typeof compareFunction !== 'function') {
compareFunction = function(a, b) {
// 将 undefined 元素排序到末尾
if (a === undefined && b === undefined) return 0;
if (a === undefined) return 1;
if (b === undefined) return -1;
let strA = String(a);
let strB = String(b);
if (strA < strB) return -1;
if (strA > strB) return 1;
return 0;
};
} else {
// 包装用户提供的 compareFunction,确保 undefined 被排序到末尾
const originalCompareFunction = compareFunction;
compareFunction = function(a, b) {
if (a === undefined && b === undefined) return 0;
if (a === undefined) return 1;
if (b === undefined) return -1;
return originalCompareFunction(a, b);
};
}
// 使用排序算法(这里使用快速排序)
function quickSort(arr, left, right) {
if (left >= right) return;
let pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
function partition(arr, left, right) {
let pivot = arr[right];
let i = left - 1;
for (let j = left; j < right; j++) {
if (compareFunction(arr[j], pivot) <= 0) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
[arr[i + 1], arr[right]] = [arr[right], arr[i + 1]];
return i + 1;
}
quickSort(elements, 0, elements.length - 1);
// 构建结果数组
let result = new MyArray();
for (let i = 0; i < elements.length; i++) {
result[i] = elements[i];
}
result.length = elements.length;
return result;
};
// 测试用例 1
let arr = new MyArray(3, 1, 4, 1, 5, 9);
let sortedArr = arr.toSorted();
console.log(sortedArr); // [1, 1, 3, 4, 5, 9]
console.log(arr); // [3, 1, 4, 1, 5, 9]
// 测试用例 2:含有空槽和 undefined
let sparseArr = new MyArray();
sparseArr[2] = 'c';
sparseArr[5] = 'a';
sparseArr[7] = undefined;
sparseArr[9] = 'b';
let sortedSparseArr = sparseArr.toSorted();
console.log(sortedSparseArr); // ['a', 'b', 'c', undefined, undefined, undefined, undefined, undefined, undefined, undefined]
console.log(sparseArr); // [empty × 2, 'c', empty × 2, 'a', empty, undefined, empty, 'b']
// 测试用例 3:自定义比较函数
let arr2 = new MyArray('banana', undefined, 'apple', , 'cherry');
let sortedArr2 = arr2.toSorted((a, b) => a.localeCompare(b));
console.log(sortedArr2); // ['apple', 'banana', 'cherry', undefined, undefined]
console.log(arr2); // ['banana', undefined, 'apple', empty, 'cherry']
// 测试用例 4:全是空槽的数组
let arr3 = new MyArray(5);
let sortedArr3 = arr3.toSorted();
console.log(sortedArr3); // [undefined, undefined, undefined, undefined, undefined]
难点总结:
- 将空槽视为
undefined
:在遍历数组时,如果索引不存在(空槽),将其视为 undefined 并添加到 elements 数组中。。 - 排序时将
undefined
排到末尾:在比较函数中,明确规定 undefined 应排在末尾。 - 处理用户自定义的
compareFunction
:当用户提供比较函数时,需要包装一下,确保 undefined 被正确处理。 - 创建新数组:构建结果数组时,按照排序后的 elements 数组逐个赋值,确保长度和索引正确。
35 Array.toSpliced()
35.1 基本介绍
toSpliced()
方法返回一个数组的浅拷贝,其中从指定的开始索引删除或替换了指定数量的元素,并插入了新元素。该方法不会修改原数组。
array.toSpliced(start)
array.toSpliced(start, deleteCount)
array.toSpliced(start, deleteCount, item1, item2, ...)
输入参数:
start
:开始修改的索引位置。deleteCount
(可选):要删除的元素数量。item1, item2, ...
(可选):要插入的新元素。
输出:一个新的数组,包含修改后的元素。
注意事项:
- 该方法不会修改原数组,是一个复制方法。
- 行为类似于
splice()
方法,但返回的是新数组。 - 对于稀疏数组,将会将空槽处理为
undefined
35.2 手写实现
MyArray.prototype.toSpliced = function(start, deleteCount, ...items) {
let length = this.length >>> 0;
let result = new MyArray();
let actualStart = start < 0
? Math.max(length + start, 0)
: Math.min(start, length);
let actualDeleteCount = deleteCount === undefined
? length - actualStart
: Math.min(Math.max(Number(deleteCount), 0), length - actualStart);
let k = 0;
// Copy elements before actualStart, treating holes as undefined
for (let i = 0; i < actualStart; i++, k++) {
result[k] = this[i]; // Holes will be assigned undefined
}
// Insert new items
for (let i = 0; i < items.length; i++, k++) {
result[k] = items[i];
}
// Copy elements after the deleted section, treating holes as undefined
for (let i = actualStart + actualDeleteCount; i < length; i++, k++) {
result[k] = this[i]; // Holes will be assigned undefined
}
// Set the length of the new array
result.length = k;
return result;
};
// Test Case 1: Basic usage with holes treated as undefined
let arr = new MyArray(1, 2, 3, 4, 5);
let splicedArr = arr.toSpliced(2, 2, 'a', 'b');
console.log(splicedArr); // [1, 2, 'a', 'b', 5]
console.log(arr); // [1, 2, 3, 4, 5]
// Test Case 2: Deleting elements without adding new ones
let arr2 = new MyArray(1, 2, 3);
let splicedArr2 = arr2.toSpliced(1);
console.log(splicedArr2); // [1]
console.log(arr2); // [1, 2, 3]
// Test Case 3: Inserting into a sparse array (holes treated as undefined)
let sparseArr = new MyArray(1, , 3); // [1, <empty>, 3]
let splicedSparseArr = sparseArr.toSpliced(1, 0, 'a');
console.log(splicedSparseArr); // [1, 'a', undefined, 3]
console.log(sparseArr); // [1, <empty>, 3]
// Test Case 4: Deleting from a sparse array (holes treated as undefined)
let splicedSparseArr2 = sparseArr.toSpliced(1, 2);
console.log(splicedSparseArr2); // [1]
console.log(sparseArr); // [1, <empty>, 3]
// Test Case 5: Negative start index
let arr3 = new MyArray('x', 'y', 'z');
let splicedArr3 = arr3.toSpliced(-2, 1, 'a', 'b');
console.log(splicedArr3); // ['x', 'a', 'b', 'z']
console.log(arr3); // ['x', 'y', 'z']
// Test Case 6: Deleting more elements than remain
let arr4 = new MyArray(1, 2, 3, 4);
let splicedArr4 = arr4.toSpliced(2, 10);
console.log(splicedArr4); // [1, 2]
console.log(arr4); // [1, 2, 3, 4]
// Test Case 7: Deleting zero elements
let arr5 = new MyArray(1, 2, 3);
let splicedArr5 = arr5.toSpliced(1, 0, 'a', 'b');
console.log(splicedArr5); // [1, 'a', 'b', 2, 3]
console.log(arr5); // [1, 2, 3]
难点总结:
- 处理稀疏数组:空槽将会被视为undefined。
- 处理新数组赋值:不需要修改原始数组,直接拼接原始数组以及添加元素内容即可完成。