来点 JavaScript 基础

Math

Math 对象方法

方法描述
abs(x)返回 x 的绝对值。
ceil(x)返回 x,向上舍入为最接近的整数。
exp(x)返回 Ex 的值。
floor(x)返回 x,向下舍入为最接近的整数。
log(x)返回 x 的自然对数。
max(x, y, z, ..., n)返回值最高的数字。
min(x, y, z, ..., n)返回值最小的数字。
random()返回 0 到 1 之间的随机数。
round(x)将 x 舍入为最接近的整数。
sign(x)返回数的符号(检查它是正数、负数还是零)。
trunc(x)返回数字 (x) 的整数部分。

Array

Array 属性

属性描述
constructor返回创建 Array 对象原型的函数。
length设置或返回数组中元素的数量。
prototype允许您向数组添加属性和方法。

Array 方法

方法描述
copyWithin()将数组中的数组元素复制到指定位置或从指定位置复制。
entries()返回键/值对数组迭代对象。
lastIndexOf()在数组中搜索元素,从末尾开始,并返回其位置。
reduceRight()将数组的值减为单个值(从右到左)。
reverse()反转数组中元素的顺序。
shift()删除数组的第一个元素,并返回该元素。
splice()从数组中添加/删除元素。
unshift()将新元素添加到数组的开头,并返回新的长度。

Array.prototype.flat:

js
1it("flat", () => {
2  expect([1, [2], 3].flat()).toEqual([1, 2, 3]);
3  expect([1, [2, [3, [4]]]].flat(Infinity)).toEqual([1, 2, 3, 4]);
4});

Array.prototype.flatMap:

js
1it("flatMap", () => {
2  expect([1, 2, 3].flatMap((x) => [x, x * 2])).toEqual([1, 2, 2, 4, 3, 6]);
3  expect([1, 2, 3].flatMap(() => 4)).toEqual([4, 4, 4]);
4  expect([1, 2, 3].flatMap(() => [4, 5])).toEqual([4, 5, 4, 5, 4, 5]);
5});

Array.prototype.sort

Parameters

compareFn Optional

Specifies a function that defines the sort order. If omitted, the array elements are converted to strings, then sorted according to each character's Unicode code point value.

  • a
    The first element for comparison.
  • b
    The second element for comparison.

Description

If compareFn is not supplied, all non-undefined array elements are sorted by converting them to strings and comparing strings in UTF-16 code units order. For example, "banana" comes before "cherry". In a numeric sort, 9 comes before 80, but because numbers are converted to strings, "80" comes before "9" in the Unicode order. All undefined elements are sorted to the end of the array.

compareFn(a, b) return valuesort order
> 0sort a after b
< 0sort a before b
=== 0keep original order of a and b

Map

一般情况下的 hash 结构选 object 就行了,如果要频繁的添加和删除元素以及保证 key 的插入顺序,那么选择 Map。

Object

从 ECMAScript 2015 (ES6) 开始,Object 在 JavaScript 中确实保证了其键的插入顺序。但在 ES6 之前的版本中,这个行为是没有明确保证的。不过,大多数的现代浏览器实际上是按照键的插入顺序存储键的。

在 ES6 中,Object 有以下的遍历顺序规则:

  1. 先遍历所有数字键,从小到大。
  2. 然后遍历所有字符串键,按照它们被添加到对象的顺序。
  3. 最后遍历所有符号键,按照它们被添加的顺序。

尽管 ES6 之前的版本并没有明确指定遍历的顺序,但在实践中,大多数的 JavaScript 引擎已经实现了与 ES6 中描述的相似的行为。

然而,需要注意的是,即使现在对象的键的插入顺序得到了保证,依赖于对象键的插入顺序的代码在某些场景下仍然可能会导致不稳定和难以维护的行为。因此,在设计代码时,如果确实需要依赖插入顺序,考虑使用Map可能是一个更好的选择,因为Map明确地保证了键的插入顺序。
在 JavaScript 中,虽然可以使用数字作为对象的键,但这些数字键会被自动转换为字符串。
所以因为数字键的存在,不能使用 object 来保证 key 的插入顺序。

哪些函数带副作用

有副作用的(改变原数组)

建议拷贝数组后再使用避免出现意料之外的问题,会导致 Next.js“Text content does not match server-rendered HTML”React hydration error。

push()

push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

javascript
1const arr = ["1", "2", "3"];
2const length = arr.push("4");
3console.log(length);
4// 4
5
6console.log(arr);
7// ["1", "2", "3", "4"]

shift()

方法从数组中删除第一个元素,并返回该元素。此方法更改数组的长度。

javascript
1const arr = [1, 2, 3];
2
3const firstElement = arr.shift();
4
5console.log(arr);
6//  [2, 3]
7
8console.log(firstElement);
9// 1

unshift()

在数组的首部添加一个或者多个元素,返回的是插入元素后数组的长度

javascript
1var arr = [1, 2, 3, 4];
2arr.unshift(); //4     如果没有插入的值那么返回的长度是当前数组的原长度
3var a1 = [1, 2, 3, 4];
4a1.unshift(1, 2, 3); //7
5a1; //[1, 2, 3, 1, 2, 3, 4]

splice()

对数组进行增、删、改。此方法会改变原数组。

javascript
1//增
2var arr = [1, 2, 3, 4];
3arr.splice(2, 0, "插入"); //返回的是空数组 []
4arr; //[1, 2, "插入", 3, 4]
5
6//删
7var a1 = [1, 2, 3, 4];
8a1.splice(2, 1); // 返回被删除的元素 [3]
9a1; //  [1, 2, 4]  //返回的是删除后剩余的数组元素
10
11//改
12var a1 = [1, 2, 3, 4];
13a1.splice(2, 1, "改"); //返回的是被替换删除掉的元素 [3]
14a1; //[1, 2, "改", 4]

pop()

从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

javascript
1const arr = [1, 2, 3];
2console.log(arr.pop());
3//3
4
5console.log(arr);
6//[1,2]
reverse()

方法将数组中元素的位置颠倒,并返回该数组。该方法会改变原数组。

javascript
1const arr = ["1", "2", "3"];
2console.log(arr.reverse());
3//  ["3", "2", "1"]
4
5console.log(arr);
6//  ["3", "2", "1"]

sort()

对数组的元素进行排序,并返回数组。默认排序顺序是将元素转换为字符串,然后比较它们的 Unicode 码。

javascript
1const months = ["March", "Jan", "Feb", "Dec"];
2months.sort();
3console.log(months);
4// ["Dec", "Feb", "Jan", "March"]
5
6const array1 = [1, 30, 4, 21, 100000];
7array1.sort();
8console.log(array1);
9//  [1, 100000, 21, 30, 4]

fill()

用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。

javascript
1const arr = [1, 2, 3, 4];
2
3console.log(arr.fill(0, 2, 4));
4//[1, 2, 0, 0]
5
6console.log(arr.fill(5, 1));
7//  [1, 5, 5, 5]
8
9console.log(array1.fill(6));
10//  [6, 6, 6, 6] //无 beigin 和  end  则全部填充

无副作用(不改变原数组)

concat()

用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

javascript
1const array1 = ["a", "b", "c"];
2const array2 = ["d", "e", "f"];
3const array3 = array1.concat(array2);
4
5console.log(array3);
6// ["a", "b", "c", "d", "e", "f"]

join()

该方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

javascript
1const elements = ["1", "2", "3"];
2
3console.log(elements.join());
4// "1,2,3"
5
6console.log(elements.join(""));
7//"123"
8
9console.log(elements.join("-"));
10//"1-2-3"

indexOf() , lastIndexOf()

indexOf 返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回 -1。

lastIndexOf 返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找。

javascript
1//indexOf
2const arr = ["1", "2", "3"];
3
4console.log(arr.indexOf("2"));
5// 1
6
7console.log(arr.indexOf("0"));
8//-1
9
10//lastIndexOf
11
12const arr = ["1", "2", "3", "1"];
13
14console.log(arr.lastIndexOf("1"));
15//  3
16
17console.log(arr.lastIndexOf("2"));
18// 1

slice()

返回截取后的新数组,截取数组中的一部分,从开始到结束,截取原则是,包括开始索引不包括结束索引值.

第二个参数可选:不写或大于数组的 length,取将从开始索引到最后一个参数

javascript
1let a = [1, 2, 3, 4, 5];
2let b = a.slice(1, 2);
3b; //2
4
5let a = [1, 2, 3, 4, 5];
6let b = a.slice(1, 1);
7b; //undefined
8
9let a = [1, 2, 3, 4, 5];
10let b = a.slice(1);
11b; //[2, 3, 4, 5]

entries()

返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键/值对。

javascript
1const array1 = ["a", "b", "c"];
2
3const iterator1 = array1.entries();
4
5console.log(iterator1.next().value);
6// [0, "a"]
7
8console.log(iterator1.next().value);
9// [1, "b"]

keys()

返回一个包含数组中每个索引的 Array Iterator 对象。

javascript
1const arr = ["a", "b", "c"];
2const iterator = arr.keys();
3
4for (const key of iterator) {
5  console.log(key);
6}
7
8//  0
9//  1
10//  2

values()

返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值

javascript
1const array1 = ["a", "b", "c"];
2const iterator = array1.values();
3
4for (const value of iterator) {
5  console.log(value);
6}
7
8// "a"
9// "b"
10// "c"

every()

测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

若收到一个空数组,此方法在一切情况下都会返回 true。

javascript
1const check = (currentValue) => currentValue < 40;
2
3const arr = [1, 30, 39, 29, 10, 13];
4
5console.log(arr.every(check));
6
7// true  数组元素都<40

filter()

创建一个新数组,返回符合条件的元素。

javascript
1const arr = [1, 2, 3];
2
3const result = arr.filter((item) => item > 1); //过滤方法,条件 值长度>6
4
5console.log(result);
6// [2, 3]

forEach()

对数组的每个元素执行一次给定的函数,但传入的回调里是可以更改原数组的。当然不推荐这样做。

javascript
1const array1 = [{ a: 100 }];
2
3array1.forEach((element) => {
4  element.a = 200; //不推荐,此处应该是一个纯函数
5});
6
7console.log(array1);
8// [Object { a: 200 }]

includes()

用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false。

javascript
1onst array1 = [1, 2, 3];
2
3console.log(array1.includes(2));
4// true

some()

检测数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean。

javascript
1const array = [1, 2, 3, 4, 5];
2
3const even = (element) => element % 2 === 0; //是否能整除 2
4
5console.log(array.some(even));
6//  true

reduce()

相当于一个累加器,第一个参数表示上一次累计的返回值,第二个参数表示当前元素值

javascript
1const arr = [1, 2, 3, 4];
2const reducer = (sum, currentValue) => sum + currentValue;
3
4console.log(arr.reduce(reducer));
5// 10
6
7console.log(arr.reduce(reducer, 5));
8// 15

map()

返回一个新数组,新数组的结果是旧数组中的每个元素是调用一次提供的函数后的返回值。

javascript
1let a = [1, 2, 3, 4, 5];
2let b = a.map((item) => item * 2);
3
4a; //[1, 2, 3, 3, 5]
5b; //[2, 4, 6, 8, 10]

find() , findIndex()

find: 返回数组中满足提供的过滤函数的第一个元素的值。否则返回 undefined。

findIndex: 和 find 方法功能一致,但返回的是元素的索引

javascript
1//find
2const arr = [5, 12, 8, 130, 44];
3
4const found = arr.find((item) => item > 10);
5
6console.log(found);
7//12
8
9//findIndex
10const arr = [5, 12, 8, 130, 44];
11const found = arr.findIndex((item) => item > 10);
12console.log(found);
13//1

flat()

返回一个扁平化的新数组,接收一个数组(这个数组中的某些 item 本身也是一个数组),返回一个新的一维数组 (如果没有特别指定 depth 参数的话返回一维数组)。

javascript
1const arr = ["a", ["b", "c"], ["d", ["e", "f"]]];
2// .flat() 接收一个可选的深度参数
3
4const reuslt = arr.flat(2);
5console.log(reuslt);
6
7// [ "a", "b", "c", "d", "e", "f" ]

for...in, Object.keys(), Object.getOwnPropertyNames()

for...in

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

The loop will iterate over all enumerable properties of the object itself and those the object inherits from its prototype chain (properties of nearer prototypes take precedence over those of prototypes further away from the object in its prototype chain).

A for...in loop only iterates over enumerable, non-symbol properties. Objects created from built–in constructors like Array and Object have inherited non–enumerable properties from Array.prototype and Object.prototype, such as Array's indexOf() method or Object's toString() method, which will not be visited in the for...in loop.

The traversal order, as of modern ECMAScript specification, is well-defined and consistent across implementations. Within each component of the prototype chain, all non-negative integer keys (those that can be array indices) will be traversed first in ascending order by value, then other string keys in ascending chronological order of property creation.

The variable part of for...in accepts anything that can come before the = operator. You can use const to declare the variable as long as it's not reassigned within the loop body (it can change between iterations, because those are two separate variables). Otherwise, you can use let. You can use destructuring or an object property like for (x.y in iterable) as well.

js
1const obj = {
2  a: {
3    b: 1,
4  },
5};
6
7for (obj.a in obj) {
8  // 相当于 obj.a = 'a';
9  console.log(obj.a); // a
10}

A legacy syntax allows var declarations of the loop variable to have an initializer. This throws a syntax error in strict mode and is ignored in non–strict mode.

Object.keys()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

Object.keys() returns an array whose elements are strings corresponding to the enumerable string-keyed property names found directly upon object. This is the same as iterating with a for...in loop, except that a for...in loop enumerates properties in the prototype chain as well. The order of the array returned by Object.keys() is the same as that provided by a for...in loop.

If you need the property values, use Object.values() instead. If you need both the property keys and values, use Object.entries() instead.

Object.getOwnPropertyNames()

Object.getOwnPropertyNames() returns an array whose elements are strings corresponding to the enumerable and non-enumerable properties found directly in a given object obj. The ordering of the enumerable properties in the array is consistent with the ordering exposed by a for...in loop (or by Object.keys()) over the properties of the object. The non-negative integer keys of the object (both enumerable and non-enumerable) are added in ascending order to the array first, followed by the string keys in the order of insertion.

In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. In ES2015, a non-object argument will be coerced to an object.

js
1Object.getOwnPropertyNames("foo");
2// TypeError: "foo" is not an object (ES5 code)
3
4Object.getOwnPropertyNames("foo");
5// ["0", "1", "2", "length"]  (ES2015 code)

Conclusion

Object.keys will return a list of enumerable own string properties, while Object.getOwnPropertyNames will also contain non-enumerable ones.

for...inObject.keys(), Object.getOwnPropertyNames() 对比,后两者不会获取继承自其原型链的属性
for...in, Object.keys()Object.getOwnPropertyNames() 对比,后者会包含不可枚举属性,前两者只返回可枚举属性

  • Object.keys() = for...in + Object.hasOwnProperty
  • 使用 for...in 迭代,遍历出自身以及原型链上的可枚举的属性,通过 hasOwnProperty 进行筛选能遍历出自身可枚举属性
  • Object.keys 直接遍历出的自身可枚举属性组成的数组
  • 使用 getOwnPropertyNames 可以访问自身可枚举属性与不可枚举属性

一些常用方法的总结

padStart

padStart 是一个在 JavaScript 中用于字符串的方法,它用于在当前字符串的开始处添加填充字符,直到字符串达到指定的长度。如果原始字符串已经等于或超过这个长度,则返回原始字符串。

基本语法

javascript
1str.padStart(targetLength [, padString])
  • targetLength:目标字符串的长度。
  • padString:(可选)填充字符串。如果没有提供或为空字符串,则默认使用空格填充。

示例

使用空格填充
javascript
1const str = "5";
2const paddedStr = str.padStart(3, '0');  // "005"
3console.log(paddedStr);

在这个示例中,字符串 "5"padStart 方法填充,使其长度达到 3,填充字符为 '0'

不足以填充的情况
javascript
1const str = "Hello";
2const paddedStr = str.padStart(3, '0');  // "Hello"
3console.log(paddedStr);

在这个例子中,由于 "Hello" 的长度已经超过了 3,padStart 方法不会添加任何填充字符。

应用场景

padStart 方法通常用于格式化输出,如确保数字具有固定的显示长度(例如时间、日期、编号等)。

javascript
1const number = "9";
2const formattedNumber = number.padStart(2, '0'); // "09"
3console.log(formattedNumber);  // 通常用于时间或日期格式化

在这个应用场景中,padStart 用于确保数字 9 显示为两位数 "09",这在格式化时间或日期时非常有用。