1. 数组、对象、字符串等常用的操作方法
- 数组方法
unshift:在数组的头部添加内容,返回新数组的长度
// array.unshift(element1, element2, ..., elementN)
const array = [1, 2, 3];
console.log(array.unshift(4, 5)); // 5(新数组长度)
console.log(array); // [4, 5, 1, 2, 3]
push:在数组的尾部添加内容,返回新数组的长度
// array.push(element1, element2, ..., elementN)
const array = [1, 2, 3];
console.log(array.push(4, 5)); // 5(新数组长度)
console.log(array); // [1, 2, 3, 4, 5]
splice:在数组的中部添加、删除内容
// array.splice(start, deleteCount, item1, item2, ..., itemN)
// start:指定操作开始的索引,可以是负值(表示从数组末尾开始数)。
// deleteCount:可选参数,表示要删除的元素数量。如果为0,则不会删除任何元素。
// item1, item2, ..., itemN:可选参数,在 start 索引处插入新元素。
// 插入元素:通过设置 deleteCount 为0,然后在 start 索引位置插入新元素。
// 删除元素:通过设置 deleteCount 大于0,从 start 索引位置开始删除指定数量的元素。
// 替换元素:通过设置 deleteCount 大于0,并且在 start 索引位置插入新元素,达到替换元素的效果。
const array = [1, 2, 3, 4, 5];
// 插入元素 array.splice(2, 0, 6);
// 在索引2处插入元素6
console.log(array); // [1, 2, 6, 3, 4, 5]
// 删除元素 array.splice(3, 2);
// 从索引3处开始删除2个元素
console.log(array); // [1, 2, 6, 5]
// 替换元素 array.splice(1, 1, 7, 8);
// 从索引1处删除1个元素,并插入元素7和8
console.log(array); // [1, 7, 8, 6, 5]
length:设置数组的长度
// 通过设置 length 属性来改变数组的长度。当将 length 设置为较小的值时,数组会被截断,超出指定长度的元素会被移除。当将 length 设置为较大的值时,数组会被扩展,多出的元素会被设置为 undefined
const array = [1, 2, 3, 4, 5];
console.log(array); // [1, 2, 3, 4, 5]
console.log(array.length); // 5
array.length = 3;
console.log(array); // [1, 2, 3]
console.log(array.length); // 3
array.length = 7;
console.log(array); // [1, 2, 3, 空属性 × 4]
console.log(array.length); // 7
// 通过设置 length 可以增加或减少数组的长度,但不会影响实际存储在内存中的数组缓冲区大小。只会改变数组对象的逻辑长度,对应的内存空间不会改变
shift:删除数组的头部元素
// 从数组中移除并返回第一个元素
// 会改变原数组,并将其他元素在内部重新排序,使得索引位置发生变化
const array = [1, 2, 3, 4, 5];
const firstElement = array.shift();
console.log(firstElement); // 1
console.log(array); // [2, 3, 4, 5]
// shift() 方法会修改原数组。如果只是想获取数组的第一个元素而不改变原数组,可以使用 array[0] 来访问第一个元素
pop:尾部删除元素
// 返回最后一个元素
// 会改变原数组,并将其他元素在内部重新排序,使得索引位置发生变化
const array = [1, 2, 3, 4, 5];
const lastElement = array.pop();
console.log(lastElement); // 5
console.log(array); // [1, 2, 3, 4]
// pop() 方法会修改原数组。如果只是想获取数组的最后一个元素而不改变原数组,可以使用 array[array.length - 1] 来访问最后一个元素
slice:从数组中提取指定范围的元素,然后返回这些元素组成的新数组
// 不会修改原始数组
// array.slice(startIndex, endIndex)
// startIndex:提取的起始位置的索引。如果为负数,则从数组末尾开始计算。省略该参数表示从头开始
// endIndex:提取的结束位置的索引(不包括在内),如果为负数,则从数组末尾开始计算。省略该参数表示提取到数组末尾
// 返回一个新的数组,包含从原始数组中提取的元素
const array = [1, 2, 3, 4, 5];
const newArray = array.slice(1, 4);
console.log(newArray); // [2, 3, 4]
const newArray2 = array.slice(-3);
console.log(newArray2); // [3, 4, 5]
const newArray3 = array.slice();
console.log(newArray3); // [1, 2, 3, 4, 5]
// slice() 方法不会修改原始数组,返回一个包含提取元素的新数组。如果省略 startIndex 参数,则默认从头开始提取。如果 endIndex 参数不指定,则提取到数组末尾
map:迭代数组
// array.map(callback(element, index, array))
// callback:对每个元素进行处理的回调函数
// element:当前正在处理的元素 // index:当前元素的索引
// array:原始数组,即被 map 方法调用的数组本身
const array = [1, 2, 3, 4, 5];
const newArray = array.map(function(element, index) { return element * 2; });
console.log(newArray); // [2, 4, 6, 8, 10]
// map 方法可以对数组进行处理并生成一个新的数组,不会改变原始数组的结构
filter:过滤数组
// array.filter(callback(element, index, array))
// callback:用于确定每个元素是否满足条件的回调函数
// element:当前正在处理的元素
// index:当前元素的索引
// array:原始数组,即被 filter 方法调用的数组本身
const numbers = [2, 5, 8, 10, 3, 6];
const filteredNumbers = numbers.filter((number) => number >= 5); console.log(filteredNumbers); // [5, 8, 10, 6]
// filter 方法可以对数组进行筛选,并生成一个新的数组,新数组中只包含满足特定条件的元素,不会改变原始数组的结构
reduce:累加
// array.reduce(callback(accumulator, currentValue, index, array), initialValue)
// callback:对每个元素进行处理的回调函数
// accumulator:累加器,用于存储累积的结果,是上一次回调函数的返回值
// currentValue:当前正在处理的元素
// index:当前元素的索引
// initialValue(可选):作为累加器初始值的参数。如果提供了初始值,则第一次调用回调函数时,accumulator 的值将是初始值,而 currentValue 则为数组的第一个元素;如果没有提供初始值,则第一次调用回调函数时,accumulator 的值将为数组的第一个元素,而 currentValue 则为数组的第二个元素。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue);
console.log(sum); // 15
// reduce 方法可以对数组进行累积操作,返回一个单个的值,即将数组中所有值累积后的结果。可以通过设置初始值来控制累加器的初始状态
find:查找第一个满足条件的元素
// array.find(callback(element, index, array))
// callback:用于确定每个元素是否满足条件的回调函数
// element:当前正在处理的元素
// index:当前元素的索引
const numbers = [2, 5, 8, 10, 3, 6];
const foundNumber = numbers.find((number) => number >= 5); console.log(foundNumber); // 5
// find 方法可以查找数组中满足特定条件的第一个元素,并返回该元素。如果只需要找到满足条件的元素而不需要遍历整个数组,使用 find 方法会更高效
findIndex:查找第一个满足条件的下标
// array.findIndex(callback(element, index, array))
// callback:用于确定每个元素是否满足条件的回调函数
// element:当前正在处理的元素
// index:当前元素的索引
const numbers = [2, 5, 8, 10, 3, 6];
const foundIndex = numbers.findIndex((number) => number >= 5); console.log(foundIndex); // 1
// findIndex 方法可以查找数组中满足特定条件的第一个元素,并返回该元素的索引。如果只需要找到满足条件的元素的索引而不需要遍历整个数组,使用 findIndex 方法会更高效
some:是否有元素符合条件
// array.some(callback(element, index, array))
// callback:用于确定每个元素是否满足条件的回调函数
// element:当前正在处理的元素
// index:当前元素的索引
const numbers = [1, 3, 5, 7, 2, 9];
const hasEvenNumber = numbers.some((number) => number % 2 === 0); console.log(hasEvenNumber); // true
// some 方法可以检查数组中是否存在满足特定条件的元素。如果只需要确定是否存在满足条件的元素而不需要遍历整个数组,使用 some 方法会更高效
every:每一个元素是否都符合条件
// array.every(callback(element, index, array))
// callback:用于确定每个元素是否满足条件的回调函数
// element:当前正在处理的元素
// index:当前元素的索引
const numbers = [1, 3, 5, 7, 2, 9];
const allPositive = numbers.every((number) => number > 0); console.log(allPositive); // true
// every 方法可以检查数组中的所有元素是否满足特定条件。如果只需要确定是否所有元素都满足条件而不需要遍历整个数组,使用 every 方法会更高效
sort:排序
// array.sort(compareFunction)
// compareFunction:可选参数,用于指定排序规则的比较函数。该函数接受两个参数 a 和 b,分别代表数组中的两个元素。比较函数需要返回一个数字值,表示 a 和 b 的相对关系
// 当返回值小于 0 时,a 在排序后的数组中排在 b 前面
// 当返回值等于 0 时,a 和 b 的相对位置保持不变
// 当返回值大于 0 时,a 在排序后的数组中排在 b 后面
// 如果不提供 compareFunction 参数,sort 方法会将数组元素转换为字符串并按照 Unicode 字符顺序进行排序。这意味着,默认情况下,sort 方法将会将数组元素视为字符串进行排序,而不是按照数值大小进行排序
const fruits = ["apple", "banana", "orange", "grape"];
fruits.sort();
console.log(fruits); // ["apple", "banana", "grape", "orange"]
// 根据自定义的比较函数 const numbers = [10, 5, 8, 2, 3];
numbers.sort((a, b) => a - b);
console.log(numbers); // [2, 3, 5, 8, 10]
// sort 方法会修改原始数组,并返回排序后的数组
join:拼接
// array.join(separator)
// separator:可选参数,用于指定连接元素的分隔符。分隔符可以是任何字符串,默认为逗号","
const fruits = ["apple", "banana", "orange"];
const result = fruits.join("-");
console.log(result); // "apple-banana-orange"
// 如果不提供分隔符参数,join 方法会使用默认的逗号","作为分隔符
const numbers = [1, 2, 3, 4, 5];
const result = numbers.join();
console.log(result); // "1,2,3,4,5"
reverse:翻转
// reverse() 方法会直接修改原始数组,而不会创建一个新的数组
const array = [1, 2, 3, 4, 5];
array.reverse();
console.log(array); // [5, 4, 3, 2, 1]
concat:拼接
// concat() 方法不会改变原始数组,会返回一个新数组,其中包含了所有被连接的数组元素。可以将多个数组合并为一个数组
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8, 9];
const newArray = array1.concat(array2, array3);
console.log(newArray); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
includes:判断是否包含特定元素
// includes() 方法会遍历数组,从数组的开头开始逐个比较元素,如果找到了匹配的元素,返回 true;如果没有找到匹配的元素,返回 false
const array = [1, 2, 3, 4, 5];
console.log(array.includes(3)); // true
console.log(array.includes(6)); // false
// includes() 方法还可以接受第二个参数,表示从数组的指定索引位置开始搜索
const array = [1, 2, 3, 4, 5];
console.log(array.includes(3, 2)); // true
console.log(array.includes(3, 4)); // false
- 对象常用方法
Object.keys(obj): 返回对象的所有键名组成的数组
const obj = { name: 'Alice', age: 30, city: 'New York' };
const keys = Object.keys(obj);
console.log(keys); // 输出:["name", "age", "city"]
Object.values(obj): 返回对象的所有值组成的数组
const obj = { name: 'Alice', age: 30, city: 'New York' };
const values = Object.values(obj);
console.log(values); // 输出:["Alice", 30, "New York"]
Object.entries(obj): 返回对象的所有键值对组成的数组
const obj = { name: 'Alice', age: 30, city: 'New York' };
const entries = Object.entries(obj);
console.log(entries);
// 输出:
// [
// ["name", "Alice"],
// ["age", 30],
// ["city", "New York"]
// ]
Object.assign(target, …sources): 将多个对象的属性合并到目标对象中
const target = { a: 1, b: 2 };
const source1 = { b: 3, c: 4 };
const source2 = { c: 5, d: 6 };
const result = Object.assign(target, source1, source2);
console.log(result); // 输出:{ a: 1, b: 3, c: 5, d: 6 }
console.log(target); // 输出:{ a: 1, b: 3, c: 5, d: 6 }
// 如果源对象具有相同的属性,则后面的对象会覆盖前面的对象
- 字符串方法
length:返回字符串的长度。
const str = 'Hello';
console.log(str.length); // 输出:5
charAt(index):返回指定索引位置的字符。
const str = 'Hello';
console.log(str.charAt(0)); // 输出:H
console.log(str.charAt(4)); // 输出:o
substring(startIndex, endIndex):提取从 startIndex 到 endIndex(不包括)之间的子字符串。
const str = "Hello, World!";
console.log(str.substring(0, 5)); // 输出 "Hello"
console.log(str.substring(7)); // 输出 "World!"
slice(startIndex, endIndex):提取从 startIndex 到 endIndex(不包括)之间的子字符串,支持负数索引。
const str = "Hello, World!";
console.log(str.slice(0, 5)); // 输出 "Hello"
console.log(str.slice(7)); // 输出 "World!"
console.log(str.slice(-6)); // 输出 "World!"
toLowerCase():将字符串转换为小写。
const str = "Hello, World!";
console.log(str.toLowerCase()); // 输出 "hello, world!"
toUpperCase():将字符串转换为大写。
const str = "Hello, World!";
console.log(str.toUpperCase()); // 输出 "HELLO, WORLD!"
indexOf(substring, startIndex):返回指定子字符串首次出现的索引,可指定起始搜索位置(默认为 0)
const str = "Hello, World!";
console.log(str.indexOf("World")); // 输出 7
console.log(str.indexOf("Earth")); // 输出 -1,表示未找到
replace(searchValue, replaceValue):将指定的子字符串或模式替换为新的字符串。
const str = "Hello, World!";
console.log(str.replace("World", "Earth")); // 输出 "Hello, Earth!"
split():拆分
// string.split(separator, limit)
// string:要操作的原始字符串
// separator:可选参数,用于指定字符串的分隔符。可以是一个字符串或正则表达式
// limit:可选参数,用于指定返回数组的最大长度
const str = "apple, banana, orange";
const result = str.split(", ");
console.log(result); // ["apple", "banana", "orange"]
// 如果不提供分隔符参数,split 方法会将整个字符串作为一个元素存储在数组中
const str = "Hello, world!";
const result = str.split();
console.log(result); // ["Hello, world!"]
// 也可以通过提供限制参数 limit 来指定返回数组的最大长度。拆分后的数组将不会超过限制的长度
const str = "apple, banana, orange";
const result = str.split(", ", 2);
console.log(result); // ["apple", "banana"]
2. 了解常用的操作方法的原理并能够进行简单实现
- 字符串 (String) 操作方法:
- charAt(index):返回指定索引位置的字符。
- substring(startIndex, endIndex):提取从 startIndex 到 endIndex(不包括)之间的子字符串。
- toLowerCase():将字符串转换为小写形式。
- toUpperCase():将字符串转换为大写形式。
String.prototype.customCharAt = function(index) {
if (index < 0 || index >= this.length) {
return "";
}
return this[index];
};
String.prototype.customSubstring = function(startIndex, endIndex) {
if (startIndex > endIndex) {
[startIndex, endIndex] = [endIndex, startIndex];
}
if (startIndex < 0) {
startIndex = 0;
}
if (endIndex > this.length) {
endIndex = this.length;
}
return this.slice(startIndex, endIndex);
};
String.prototype.customToLowerCase = function() {
let newStr = "";
for (let i = 0; i < this.length; i++) {
const charCode = this.charCodeAt(i);
if (charCode >= 65 && charCode <= 90) {
newStr += String.fromCharCode(charCode + 32);
} else {
newStr += this[i];
}
}
return newStr;
};
String.prototype.customToUpperCase = function() {
let newStr = "";
for (let i = 0; i < this.length; i++) {
const charCode = this.charCodeAt(i);
if (charCode >= 97 && charCode <= 122) {
newStr += String.fromCharCode(charCode - 32);
} else {
newStr += this[i];
}
}
return newStr;
};
- 数字 (Number) 操作方法:
- toFixed(decimalPlaces):将数字转换为指定小数位数的字符串表示。
- toPrecision(precision):将数字转换为指定精度的字符串表示。
Number.prototype.customToFixed = function(decimalPlaces) {
const factor = 10 ** decimalPlaces;
return Math.round(this * factor) / factor;
};
Number.prototype.customToPrecision = function(precision) {
return this.toExponential(precision - 1);
};
- 数组 (Array) 操作方法:
- push(item):向数组末尾添加一个元素。
- pop():移除并返回数组末尾的元素。
- shift():移除并返回数组开头的元素。
- unshift(item):向数组开头添加一个或多个元素。
Array.prototype.customPush = function(item) {
this[this.length] = item; return this.length;
};
Array.prototype.customPop = function() {
if (this.length === 0) {
return undefined;
}
const lastItem = this[this.length - 1];
delete this[this.length - 1];
this.length--; return lastItem;
};
Array.prototype.customShift = function() {
if (this.length === 0) {
return undefined;
}
const firstItem = this[0];
for (let i = 0; i < this.length - 1; i++) {
this[i] = this[i + 1];
}
delete this[this.length - 1];
this.length--;
return firstItem;
};
Array.prototype.customUnshift = function(item) {
for (let i = this.length - 1; i >= 0; i--) {
this[i + 1] = this[i];
}
this[0] = item;
this.length++;
return this.length;
};
3. 不同操作方法之间的对比,如时间、空间、返回值等差异
-
字符串 (String) 操作方法:
- 时间:大多数字符串操作方法在时间复杂度上都是线性的 O(n),其中 n 是字符串的长度。某些特定操作,如 charAt 和 substring,可以在常数时间内完成,即 O(1)。
- 空间:字符串操作方法通常不会占用额外的空间,除非创建了新的字符串。
- 返回值:字符串操作方法通常返回新的字符串,而不会修改原始字符串。
-
数字 (Number) 操作方法:
- 时间:数字操作方法通常在常数时间内完成,即 O(1)。它们只执行简单的数学计算,不会随着数字大小的增加而变慢。
- 空间:数字操作方法不会占用额外的空间,除非创建了新的数字。
- 返回值:数字操作方法通常返回新的数字,并不改变原始数字。
-
布尔值 (Boolean) 操作方法:
- 时间:布尔值操作方法通常在常数时间内完成,即 O(1)。
- 空间:布尔值操作方法不会占用额外的空间。
- 返回值:布尔值操作方法通常返回新的布尔值,并不改变原始布尔值。
-
数组 (Array) 操作方法:
- 时间:数组操作方法的时间复杂度可以根据不同的操作而有所不同。例如,push 和 pop 方法在末尾添加或删除元素时通常具有常数时间复杂度 O(1),而 shift 和 unshift 方法在开头添加或删除元素时可能涉及到重新分配内存,平均时间复杂度为 O(n)。
- 空间:数组操作方法可能会占用额外的空间,特别是在需要调整数组大小时。例如,push 和 unshift 可能需要重新分配内存来容纳新的元素。
- 返回值:数组操作方法通常返回修改后的数组或被删除的元素。