About common js/es tips. Continuously update here.

过滤唯一值

ES6 引入了 Set 对象和延展(spread)语法…,我们可以用它们来创建一个只包含唯一值的数组。

1
2
3
const array = [1, 1, 2, 3, 5, 5, 1];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // Result: [1, 2, 3, 5]

在 ES6 之前,获得同样的数组需要更多的代码!

这个技巧可以支持包含原始类型的数组:undefined、null、boolean、string 和 number。但如果你的数组包含了对象、函数或其他嵌套数组,就不能使用这种方法了。

二分法

二分法最常见的是取到中位数。并且不断地根据中位数更新起点和终点,缩小范围到取得理想值。

一般来说首先设置 start 为 1,end 为数组最大位

1
const start = 0, const end = array.length - 1(or something else)

然后取中点:

1
const mid = Math.floor(start + (end - start) / 2);

通过 while 进行 start 和 end 的比较,直到 start = end 然后结束处理。
进行中位数相关的条件判断, 将 start 或 end 重新代入。
最后在 while 结束循环的时候返回 start。

1
2
3
4
5
6
7
8
9
while (start < end) {
const mid = Math.floor(start + (end - start) / 2);
if (进行中位数相关的条件判断) {
start = mid + 1;
} else {
end = mid;
}
}
return start;

冒泡法

进行乱数数组排列的时候可以用冒泡法。

1
2
3
4
arr = arr.sort((a, b) => {
return a - b;
});
console.log(arr);

取数列中的最大值

1
2
3
4
let piles = [2, 5, 4, 8, 6, 2, 4];
let max = Math.max(...piles);
console.log(max);
// 8

在循环中缓存数组长度

在我们学习使用 for 循环时,一般建议使用这种结构:

1
2
3
for (let i = 0; i < array.length; i++) {
console.log(i);
}

在使用这种方式时,for 循环的每次迭代都会重复计算数组长度。

有时候这个会很有用,但在大多数情况下,如果能够缓存数组的长度会更好,这样只需要计算一次就够了。我们可以把数组长度复制给一个叫作 length 的变量,例如:

1
2
3
for (let i = 0, length = array.length; i < length; i++) {
console.log(i);
}

这段代码和上面的差不多,但从性能方面来看,即使数组变得很大,也不需要花费额外的运行时重复计算 array.length。

短路求值(Short-Circuit Evaluation)

|| 运算符可用于返回表达式中的第一个真值,而&&运算符可用于阻止执行后续代码。

其实有时也可以使用三项演算符.

使用 && 运算符

例:
下面是一个 if-else 语句转换为短路求值的示例。在本例中,我们希望获得用户的显示名。如果 user 对象有 name 属性,我们将使用它作为显示名。否则,我们只会称我们的用户为 Guest。

normal

1
2
3
4
5
6
7
8
9
10
const user = {};

let displayName;

if (user.name) {
displayName = user.name;
} else {
displayName = "Guest";
}
console.log(displayName); // "Guest"

短路求值:

1
2
3
const user = {};
const displayName = user.name || "Guest";
console.log(displayName); // "Guest"

在多个条件判断下也同样适用:
normal

1
2
3
4
5
6
7
8
9
10
11
12
const user = { name: "IU" };
let displayName;

if (user.nickname) {
displayName = user.nickname;
} else if (user.name) {
displayName = user.name;
} else {
displayName = "Guest";
}

console.log(displayName); // "IU"

短路求值:

1
2
3
const user = { name: "IU" };
const displayName = user.nickname || user.name || "Guest";
console.log(displayName); // "IU"

你是否曾经在访问嵌套对象属性时遇到过问题?你可能不知道对象或某个子属性是否存在,所以经常会碰到让你头疼的错误。

假设我们想要访问 this.state 中的一个叫作 data 的属性,但 data 却是 undefined 的。在某些情况下调用 this.state.data 会导致 App 无法运行。为了解决这个问题,我们可以使用条件语句:
normal

1
2
3
4
5
if (this.state.data) {
return this.state.data;
} else {
return "Fetching Data";
}

短路求值:

1
return this.state.data || "Fetching Data";

使用 && 运算符

&& 短路的工作原理有点不同。使用 && 运算符,我们可以确保只有在前面的表达式是真实的情况下才运行后续表达式。这到底是什么意思?让我们看另一个例子!在本例中,如果服务器响应不成功,我们希望在控制台中显示一个错误。首先,我们可以使用 if 语句来实现这一点。

normal:

1
2
3
4
const response = { success: false };
if (!response.success) {
console.error("ERROR");
}

短路求值:

1
2
const response = { success: false };
!response.success && console.error("ERROR");

转换成布尔值

除了标准的布尔值 true 和 false,在 JavaScript 中,所有的值要么是“真值”要么是“假值”。

在 JavaScript 中,除了 0、“”、null、undefined、NaN 和 false 是假值之外,其他的都是真值。

我们可以使用!云算法来切换 true 和 false。

1
2
3
4
5
const isTrue = !0;
const isFalse = !1;
const alsoFalse = !!0;
console.log(true); // Result: true
console.log(typeof true); // Result: "boolean"

快速幂运算

从 ES7 开始,可以使用**进行幂运算,比使用 Math.power(2,3)要快得多。

1
console.log(2 ** 3); // Result: 8

快速取整

我们可以使用 Math.floor()、Math.ceil()或 Math.round()将浮点数转换成整数,但有另一种更快的方式,即使用位或运算符|

1
2
console.log(23.9 | 0); // Result: 23
console.log(-23.9 | 0); // Result: -23

如果 n 是正数,那么 n|0 向下取整,否则就是向上取整。它会移除小数部分,也可以使用~~达到同样的效果。

获取数组最后的元素

数组的 slice()方法可以接受负整数,并从数组的尾部开始获取元素。

1
2
3
4
let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(array.slice(-1)); // Result: [9]
console.log(array.slice(-2)); // Result: [8, 9]
console.log(array.slice(-3)); // Result: [7, 8, 9]

声明和初始化数组

我们可以使用特定的大小来初始化数组,也可以通过指定值来初始化数组内容,大家可能用的是一组数组,其实二维数组也可以这样做,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
const array = Array(5).fill('');
// 输出
(5) ["", "", "", "", ""]

const matrix = Array(5).fill(0).map(() => Array(5).fill(0))
// 输出
(5) [Array(5), Array(5), Array(5), Array(5), Array(5)]
0: (5) [0, 0, 0, 0, 0]
1: (5) [0, 0, 0, 0, 0]
2: (5) [0, 0, 0, 0, 0]
3: (5) [0, 0, 0, 0, 0]
4: (5) [0, 0, 0, 0, 0]
length: 5

求和,最小值和最大值

reduce()方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

1
const array = [5, 4, 7, 8, 9, 2];

求和:

1
array.reduce((a, b) => a + b);

最大值:

1
array.reduce((a, b) => (a > b ? a : b));

最小值:

1
2
array.reduce((a, b) => (a < b ? a : b));
// 输出: 2

将数组中对象的某个属性抽离到另一个数组中:

1
2
3
4
5
6
var primaryColors = [{ color: "red" }, { color: "yellow" }, { color: "bule" }];
var colorsArr = primaryColors.reduce(function (arr, primaryColor) {
arr.push(primaryColor.color);
return arr;
}, []);
console.log(colorsArr); //["red", "yellow", "bule"]

排序字符串,数字或对象等数组

我们有内置的方法 sort()和 reverse()来排序字符串,但是如果是数字或对象数组呢

字符串数组排序:

1
2
3
4
5
6
7
8
const stringArr = ["Joe", "Kapil", "Steve", "Musk"];
stringArr.sort();
// 输出
(4)[("Joe", "Kapil", "Musk", "Steve")];

stringArr.reverse();
// 输出
(4)[("Steve", "Musk", "Kapil", "Joe")];

数字数组排序:

1
2
3
4
5
6
7
8
const array = [40, 100, 1, 5, 25, 10];
array.sort((a, b) => a - b);
// 输出
(6)[(1, 5, 10, 25, 40, 100)];

array.sort((a, b) => b - a);
// 输出
(6)[(100, 40, 25, 10, 5, 1)];

对象数组排序:

1
2
3
4
5
6
7
8
9
10
11
12
const objectArr = [
{ first_name: 'Lazslo', last_name: 'Jamf' },
{ first_name: 'Pig', last_name: 'Bodine' },
{ first_name: 'Pirate', last_name: 'Prentice' }
];
objectArr.sort((a, b) => a.last_name.localeCompare(b.last_name));
// 输出
(3) [{…}, {…}, {…}]
0: {first_name: "Pig", last_name: "Bodine"}
1: {first_name: "Lazslo", last_name: "Jamf"}
2: {first_name: "Pirate", last_name: "Prentice"}
length: 3

JS 中去除数组中的假值(0, 空,undefined, null, false)

1
arr.filter(Boolean);

字符串 or 数组反转

数组反转用reverse()
字符串反转用s.split("").reverse().join("");
用 split 将字符串转换成数组,然后将数组反转,然后再用 join 连接起来.

十进制和二进制互相转换

十进制转二进制:num.toString(2)
二进制转十进制:parseInt(num, 2)

n 进制和 m 进制互相转换

1
2
3
4
5
6
main(num, m, n);
function main(num, m, n) {
const s = num + "";
const result = parseInt(s, m).toString(n);
return result;
}

文字符的 Unicode 编码转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// charCodeAt()方法是返回该字符在Unicode字符集中的编码值。
// 字符串中第一个字符的位置为 0, 第二个字符位置为 1,以此类推。
"ABC".charCodeAt(2);
// 67
"未来".charCodeAt(0);
// 26410

// String.fromCharCode是将Unicode字符集中的编码值转换成文字符
String.fromCharCode(26410);
//'未'

// 文字符的Unicode编码转换成文字符
function shift(c, x) {
let r = c.charCodeAt(0) + x;
return String.fromCharCode(r);
}

两数的最大公约数和最小公倍数

最大公约数

数学上求最大公约数的方法是有两个数 x,y,然后将两数相除(不用在意大小),然后取余数.(x%y)
然后再用被除数除以余数再取余.(y%(x%y))直到余数为 0,最后的被除数就是最大公约数。

1
2
3
function gcd(x, y) {
return x % y == 0 ? y : gcd(y, x % y);
}

最小公倍数
最小公倍数=两数相乘再除以最大公约数

1
2
const x,y;
const result = x * y / gcd(x,y);

将数列展平

当我们想将多构造的数列展平的时候可以用 flat()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 展平的同时将null去掉
const arr5 = [1, 2, , 4, 5];
arr5.flat();
// [1, 2, 4, 5]

const arr1 = [0, 1, 2, [3, 4]];

// 只展开一层
console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]

const arr2 = [0, 1, 2, [[[3, 4]]]];

// 展开两层
console.log(arr2.flat(2));
// expected output: [0, 1, 2, [3, 4]]

数组与链表互转

数组转链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function NodeList(val) {
this.val = val;
this.next = null;
}

function arrayToNodeList(list) {
let header = new NodeList(0);
let current = header;
for (let i = 0; i < list.length; i++) {
current.next = { val: list[i], next: null };
current = current.next;
}
return header.next;
}

链表转数组

1
2
3
4
5
6
7
8
9
function nodeListToArray(node) {
const list = [];
let header = node;
while (header) {
list.push(header.val);
header = header.next;
}
return list;
}

正则去除字符串多余空格,用一个空格替换

一个空格替换多个空格

1
2
str.trim().replace(/\s{2,}/g, ' '));
// 先除去前后多余空格,再用一个空格替换中间大于等于2个的空格

去掉左边空格

1
2
str.replace(/^\s*/g, "");
// ^ 匹配输入字符串的开始位置

去掉右边空格

1
2
str.replace(/\s*$/g, "");
// $ 匹配输入字符串的结尾位置

去掉前后空格

1
2
3
str.replace(/(^\s*)|(\s*$)/g, "");
// or
str.trim();

去掉所有空格

1
str..replace(/\s/g,'');