目录
1.Math
- Math.abs:求绝对值;Math.sign:判断正负,求数值符号
- Math.ceil:向上取整; Math.floor:向下取整; Math.round:四舍五入
- Math.max:求最大值;Math.min:求最小值
- Math.pow:求幂;Math.sqrt:求平方根;Math.random:生成0-1之间的随机数
// 判断素数
const isPrime = num => {
if(num <= 1) return false
for(let i = 2; i <= Math.sqrt(num); i++) {
if(num % i === 0) return false
}
return true
}
// n以内的素数
function *sieve_primes(n) {
let arr = Array.from({length: n - 2}, (item, index) => index + 2)
while(arr.length > 0) {
let prime = arr[0]
yield prime
arr = arr.filter(num => num % prime !== 0)
}
}
const it = sieve_primes(100)
// console.log('100以内的素数=================');
// console.log([...it]);
2.数组
常用方法
-
Array.length:长度
-
Array.from:类数组转数组、创建数组
-
Array.isArray:是否为数组
-
Array.includes:是否包含某元素
-
Array.indexOf:获取元素序号
-
Array.concat:合并数组(元素),返回新数组
-
Array.slice:截取数组,返回新数组
-
Array.splice:删除、插入、替换,操作原数组
-
Array.push/pop/shift/unshift:入栈、出栈、出队、入队,操作原数组
-
Array.join:数组转字符串,返回字符串
-
Array.reverse:数组反转,操作原数组
-
Array.sort:数组排序,操作原数组
-
Array.filter:创建一个新数组,筛选过滤出通过回调函数的所有元素。
-
forEach:遍历数组,对数组的每个元素执行一次回调函数。
-
map:映射 1对1,创建一个新数组,该数组中每个元素是调用一次回调函数后的返回值。
-
reduce:累加聚合,多对1。数组中每个元素执行回调函数进行累加汇总为单个返回值。
-
Array.reduceRight:从右往左
-
Array.some:是否有满足
-
Array.every:是否全部满足
// 数组替换
const arr1 = [1,2,3,4,5,6,7]
// console.log('splice测试=================');
// console.log(arr1.splice(2,2,'x')); // [3,4]
// console.log(arr1); // [1,2,'x',5,6,7]
// console.log(arr1.splice(2,1)); // ['x']
arr1.splice(2,0,'y')
// console.log(arr1); // [1,2,'y',5,6,7]
const students = [
{
id: 1,
name: "Alice",
score: 92,
groupId: 1,
},
{
id: 2,
name: "Bob",
score: 55,
groupId: 2,
},
{
id: 3,
name: "Charlie",
score: 88,
groupId: 1,
},
{
id: 4,
name: "David",
score: 76,
groupId: 3,
},
{
id: 5,
name: "Eva",
score: 62,
groupId: 2,
}
];
const groups = [
{ id: 1, name: "Math Group" },
{ id: 2, name: "Science Group" },
{ id: 3, name: "History Group" }
];
// 投射
const studentWithGrade = students.map(student => {
return {
...student,
grade: student.score >= 60 ? '及格' : '不及格'
}
})
// console.log('投射测试=================');
// console.log(studentWithGrade);
// 过滤
const passedStudents = students.filter(student => student.score >= 60)
// console.log('passedStudents 测试=================');
// console.log(passedStudents);
const group1Students = students.filter(student => student.groupId === 1)
// console.log('group1Students 测试=================');
// console.log(group1Students);
// 分组
const studentInGroups = students.reduce((groups, student) =>{
groups[student.groupId] = [...(groups[student.groupId] || []), student]
return groups
},{})
// console.log('studentInGroups 测试=================');
// console.log(studentInGroups);
// 联合
const studentWithGroupInfo = students.map(student => {
return {
...student,
groupInfo: groups.find(group => group.id === student.groupId)
}
})
// console.log('studentWithGroupInfo 测试=================');
// console.log(studentWithGroupInfo);
// 排序 Array.prototype.sort 方法会对原数组进行排序
const sortedByScoreAsc = students.slice().sort((a, b) => a.score - b.score);
// console.log('sortedByScoreAsc 测试=================');
// console.log(sortedByScoreAsc);
const sortedByScoreDesc = students.slice().sort((a, b) => b.score - a.score);
// console.log('sortedByScoreDesc 测试=================');
// console.log(sortedByScoreDesc);
const nameArr = ['张三','李四','王五'].sort((a,b) => a.localeCompare(b, 'zh'))
// console.log('nameArr 测试=================');
// console.log(nameArr);
数组去重
-
使用Set:利用Set的自动去重特性,将数组转换为Set,再转换回数组。
const unique = arr => [...new Set(arr)]
-
使用indexOf、includes:遍历数组,检查当前元素是否已在结果数组中出现过。
-
使用Map:利用Map对象的键是唯一的特性,遍历数组,将数组元素作为键存入Map,再从Map中获取所有键组成的数组。
笛卡尔积
例如:[1,2] X ['a', 'b'] = [[1, 'a'], [1, 'b'], [2, 'a'], [2,'b']]
function cartesianProduct(...Matrix) {
if(Matrix.length ===0) return []
if(Matrix.length === 1)return Matrix[0]
return Matrix.reduce((A,B) => {
const product=[]
for(let i=0; i<A.length; i++){
for(let j=0; j<B.length; j++){
product.push(Array.isArray(A[i]) ? [...A[i], B[j]] : [A[i], B[j]])
}
}
return product
})
}
result = cartesianProduct([1, 2], ['a', 'b']);
console.log(result); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
3.常见数据结构
集合
ES6引入的新的数据结构,用于存储任何类型的唯一值,无论是原始值还是对象引用。
特性:
- 唯一性:成员值唯一,无重复
- 无序性:元素没有特定顺序,不能像数组那样通过索引访问
- 类型敏感性:对于原始值,即使值相同但类型不同(如5和'5'),也会被视为不同元素存储
常用方法
- new Set([...arr])
- add(value):向Set中添加一个新元素,如果该元素已存在,则不添加。
- delete(value):删除Set中某个值,删除成功返回true,否则返回false。
- has(value):判断Set中是否存在某个值,存在返回true,否则返回false。
- clear():清除Set中的所有元素,没有返回值。
- size:返回Set中元素的个数。
- keys():返回 Iterator 对象,该对象包含Set对象中每个元素的键。对于Set,键和值相同。
- values():返回 Iterator 对象,该对象包含Set对象中每个元素的值。与keys()相同。
- entries():返回 Iterator 对象,该对象包含Set对象中每个元素的[value, value]数组。
应用场景
- 数组去重:利用Set的唯一性特性,可以快速去除数组中的重复元素。
- 数据重组:在处理数据时,可以使用Set来存储唯一值,简化后续数据处理逻辑。
- 数据储存:在某些场景下,需要存储一系列不重复的值时,可以使用Set来实现。
注意事项
- 类型转换:向Set添加值时,不会发生类型转换,如5和'5'被视为两个不同的值。
- NaN处理:在Set中只能存储一个NaN。
- 对象引用:如果Set中存储的是对象,那么比较的是对象的引用而非对象的内容。
与其他数据结构的比较
- 与Array比较:Set是无序的,且不允许重复值;数组则是有序的,可以包含重复值。
- 与Map比较:Set只存储值,而Map存储键值对,且键可以是任意类型。
// 子数组和整除
// 写一个函数solve(arr, N),判断数组arr中某一项,或任意多项的和,是否被另一个整数N整除
// 例如:solve([1,2,3,4,5], 7) => true
// 求数组全部组合后求余数
const solve = (arr, N) => {
const s = new Set()
for(let i = 0; i <= arr.length; i++) {
for (let j = i + 1; j <= arr.length; j++) {
const remain = arr.slice(i, j).reduce((a,b) => a + b, 0) % N
s.add(remain)
}
}
return s.has(0)
}
// 子问题结构思想
const solve2 = (arr, N) => {
const s = new Set()
while (arr.length > 0) {
const ak = arr.pop()
s.add(ak)
s.forEach(item => {
s.add((item + ak) % N)
})
}
return s.has(0)
}
// console.log('子数组和整除 测试=================');
// console.log(solve2([1,2,3,4,5], 7));
// console.log(solve2([3,9], 9));
Map
- 定义:Map 是一种集合(Collection),它存储了键值对(key-value pairs),其中每个键都映射到其对应的值。
- 特点:
- Map中的键可以是任意类型(对象、函数等),不仅仅是字符串或数字。
- Map记住了键的原始插入顺序。
- Map中的键是唯一的。
Map的实现原理
- 内部实现:不同的JavaScript引擎(如V8)可能以不同的方式实现Map,但一般来说,Map是基于哈希表实现的,这允许快速的插入、删除和查找操作。
- 哈希冲突解决:当两个键的哈希值相同时,Map内部会采用某种策略(如链表法、红黑树等)来解决冲突。
与类似数据结构的比较
- 与Object的比较:
- Object的键只能是字符串或Symbol,而Map的键可以是任意类型。
- Object的键是无序的,而Map保持插入顺序。
- Object的大小(属性数量)不能通过length或size属性直接获取,而Map可以通过
size
属性获取。
- 与Set的比较:
- Set仅存储唯一的值,不存储键值对。
- Set的迭代顺序是元素被添加到集合中的顺序。
使用场景
- 需要保持键值对插入顺序时。
- 键类型非字符串或数字时。
- 需要频繁进行插入、删除和查找操作时。
特定方法的理解
set(key, value)
:向Map中添加或更新键值对。get(key)
:根据键获取对应的值,如果不存在则返回undefined。has(key)
:检查Map中是否存在某个键。delete(key)
:从Map中删除指定的键及其对应的值。clear()
:清除Map中的所有键值对。size
:返回Map中键值对的数量。
高级话题
- Map与WeakMap的区别:
- WeakMap的键只能是对象或函数,且是弱引用,如果没有其他引用指向键的对象,则该对象可以被垃圾回收。
- WeakMap没有
size
属性,因为它不保证能随时提供准确的大小。 - WeakMap不可迭代,没有
keys()
、values()
和forEach()
方法。 - WeakMap主要用于避免内存泄漏,适用于缓存场景。
- HashMap、TreeMap、LinkedHashMap等(Java):
- 在Java中,Map接口有多种实现,如HashMap(基于哈希表)、TreeMap(基于红黑树,可以自然排序或自定义排序)、LinkedHashMap(保持插入顺序)。
- 这些实现各有特点,HashMap适合快速查找,TreeMap适合需要排序的场景,LinkedHashMap适合需要保持插入顺序的场景。
线性表:数组、链表(单向链表、双向链表、循环链表)。
栈与队列:后进先出(LIFO)和先进先出(FIFO)的数据结构。
// 括号匹配
const is_balance = str => {
const [first, ...others] = str
const stack = [first]
while (others.length > 0) {
const n = others.shift()
const c = stack[stack.length - 1]
const ifMatch = (c === '(' && n === ')') || (c === '[' && n === ']') || (c === '{' && n === '}')
ifMatch ? stack.pop() : stack.push(n)
}
return stack.length === 0
}
树与二叉树:二叉查找树、平衡二叉树(如AVL树、红黑树)、堆等。
图:用于表示多对多关系的数据结构,包括有向图和无向图。
4.设计模式
-
单例模式:确保一个类仅有一个实例,并提供一个全局访问点。
-
工厂模式:创建对象时不直接指定具体类,而是通过调用共同的接口来指定创建哪种类的实例。
-
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
Promise.all的实现:
function PromiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
value => {
results[index] = value;
if (++count === promises.length) {
resolve(results);
}
},
error => {
reject(error);
}
);
});
});
}
Event Emitter的实现(简化版):
class EventEmitter {
constructor() {
this.listeners = {};
}
on(event, callback) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
}
emit(event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach(callback => callback(...args));
}
}
}