1.获取最大值
方法一
方法二
const arr = [6, 4, 1, 8, 2, 11, 23];
console.log(Math.max(...arr))
1.去重
// 传统方式
function unique(arr) {
const res = []
arr.forEach(item => {
if (res.indexOf(item) < 0) {
res.push(item)
}
})
return res
}
数组或者字符串去重
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
上面代码也展示了一种去除数组重复成员的方法。// 使用 Set (无序,不能重复)
// 去除数组的重复成员
[...new Set(array)]
上面的方法也可以用于,去除字符串里面的重复字符。
[...new Set('ababbc')].join('')
// "abc"
1.解析url
2.打平数组
function flat(arr) {
// 验证 arr 中,还有没有深层数组 [1, 2, [3, 4]]
const isDeep = arr.some(item => item instanceof Array)
if (!isDeep) {
return arr // 已经是 flatern [1, 2, 3, 4]
}
const res = Array.prototype.concat.apply([], arr)
return flat(res) // 递归
}
const res = flat( [1, 2, [3, 4, [10, 20, [100, 200]]], 5] )
console.log(res)
1.手写深拷贝
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// 保证 key 不是原型的属性 hasOwnProperty(propertyName)方法 是用来检测属性是否为对象的自有属性,如果是,返回true,否者false;
if (obj.hasOwnProperty(key)) {
// 递归调用!!!
result[key] = deepClone(obj[key])
}
}
// 返回结果
return result
}
1.js如何判断值的类型
数据结构和类型
数据类型
最新的 ECMAScript 标准定义了 8 种数据类型:
- 七种基本数据类型:
- 布尔值(Boolean),有 2 个值分别是:
true
和false
. - null,一个表明 null 值的特殊关键字。JavaScript 是大小写敏感的,因此
null
与Null
、NULL
或变体完全不同。 - undefined,和 null 一样是一个特殊的关键字,undefined 表示变量未赋值时的属性。
- 数字(Number),整数或浮点数,例如:
42
或者3.14159
。 - 任意精度的整数 (BigInt) ,可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。
- 字符串(String),字符串是一串表示文本值的字符序列,例如:"Howdy" 。
- 代表(Symbol)( 在 ECMAScript 6 中新添加的类型).。一种实例是唯一且不可改变的数据类型。
- 布尔值(Boolean),有 2 个值分别是:
- 以及对象(Object)。
1.几种判断数据类型方式的弊端:
typeof的弊端:只能区分基本类型,如果数据类型为 null、array、object ,使用 typeof 判断都会统一返回 ‘’object‘’ 字符串
console.log(typeof(function() {})) //function
console.log(typeof(null)) //object
console.log(typeof([1,2,3])) //object
console.log(typeof({a: 'b'})) //object
null、undefined 没有 constructor 属性,不能用来判断
推荐用这种Object.prototype.toString.call() 判断数据类型
console.log(Object.prototype.toString.call(1)) //[object Number]
console.log(Object.prototype.toString.call('a')) //[object String]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(function() {})) //[object Function]
console.log(Object.prototype.toString.call(null)) //[object Null]
console.log(Object.prototype.toString.call([1,2,3])) //[object Array]
console.log(Object.prototype.toString.call({a: 'b'})) //[object Object]
/**
* 获取详细的数据类型
* @param x x
*/
export function getType(x: any): string {
const originType = Object.prototype.toString.call(x) // '[object String]'
const spaceIndex = originType.indexOf(' ')
const type = originType.slice(spaceIndex + 1, -1) // 'String'
return type.toLowerCase() // 'string'
}
// // 功能测试
// console.info( getType(null) ) // 'null'
// console.info( getType(undefined) )
// console.info( getType(100) )
// console.info( getType('abc') )
// console.info( getType(true) )
// console.info( getType(Symbol()) )
// console.info( getType({}) )
// console.info( getType([]) )
// console.info( getType(() => {}) )
1.如何判断数组:
console.log([1,2,3] instanceof Array) //true
console.log(ary.constructor == Array) //true
console.log(Object.prototype.toString.call([1,2,3])) //[object Array]
1.Map 和 Object的区别
1.Set 和 Array 区别
1.数组 reduce 的用法(数组求和)
// 传统
function sum(arr) {
let res = 0 // 需要新定义一个变量
arr.forEach(n => res = res + n)
return res
}
// const arr = [10, 20, 30, 40, 50]
// const res = arr.reduce((sum, curVal, index, arr) => {
// // console.log('reduce function ....')
// // console.log('sum', sum)
// // console.log('curVal', curVal)
// // console.log('index', index)
// // console.log('arr', arr)
// return sum + curVal // 返回值,会作为下一次执行时的第一个参数 sum 的值
// }, 0)
const res = arr.reduce((sum, curVal) => sum + curVal, 0)
console.log('res', res)
1.数组 reduce 的用法(计数)
const arr = [10, 20, 30, 40, 50, 10, 20, 30, 20]
const n = 30
const count = arr.reduce((count, val) => {
return val === n ? count + 1 : count
}, 0)
console.log('count', count)
1.输出字符串
// 输出字符串
const arr = [
{ name: '张三', age: '20' },
{ name: '李四', age: '21' },
{ name: '小明', age: '22' },
]
// const str = arr.map(item => {
// return `${item.name} - ${item.age}`
// }).join('\n')
// console.log(str)
const str = arr.reduce((s, item) => {
return `${s}${item.name} - ${item.age}\n`
}, '')
console.log(str)
---------------------------------------------------------------------------------------------------------------------------------
forEach 和 map 遍历数组的区别,谁更快
forEach
和 map
都是用于遍历数组的方法,但它们有一些区别。
forEach
方法是遍历数组的每一个元素,并为每个元素执行一个回调函数。它不会返回一个新数组,而是在原始数组上执行操作。因此,它通常用于执行一些副作用,如打印数组的内容或修改原始数组。
map
方法与 forEach
类似,但它会返回一个新数组,其中包含通过对每个元素应用回调函数所生成的新值。这使得 map
方法更适合将一个数组转换为另一个数组,而不是执行副作用。
在执行相同的操作时,map
方法通常比 forEach
方法更快,因为它可以使用内部优化来创建一个新数组,而 forEach
方法需要手动创建一个新数组。但是,这取决于具体的实现和操作。在一些简单的情况下,forEach
方法可能比 map
方法更快。
总之,forEach
和 map
都有各自的用途,需要根据具体的场景选择使用哪种方法
---------------------------------------------------------------------------------------------------------------------------------
时间复杂度
---------------------------------------------------------------------------------------------------------------------------------
O(n)
o(n^2)
---------------------------------------------------------------------------------------------------------------------------------
时间复杂度
---------------------------------------------------------------------------------------------------------------------------------
请解释一下数据结构中的栈是什么?
栈是一种线性数据结构,它可以被视为一组元素的集合,其中元素可以通过两个主要操作进行访问:压入和弹出。这些操作可以用来添加和删除元素,但是只有栈顶的元素可以被访问或删除。
栈通常被描述为一种具有后进先出(LIFO)行为的数据结构,这意味着最后被压入的元素将是第一个被弹出的元素。当元素被压入栈中时,它们被放置在栈顶,而弹出操作则从栈顶移除元素。
相当于一个桶
JavaScript中栈的应用示例:
- 函数调用栈:
当我们在JavaScript中调用一个函数时,JavaScript引擎会使用栈来跟踪函数调用的顺序。每个函数调用都会在栈中创建一个新的栈帧,用于存储函数的参数、局部变量和执行状态等。当函数执行完成后,它的栈帧将被弹出,控制权将返回到上一层调用的函数。例如:
在上面的示例中,当我们调用main()
函数时,JavaScript引擎会创建一个新的栈帧,用于存储main()
函数的参数、局部变量和执行状态等。在main()
函数中,我们先调用add()
函数,将其返回值存储到变量z
中,然后再调用multiply()
函数,将其返回值存储到变量w
中。最终,JavaScript引擎会将main()
函数的栈帧弹出,程序结束执行。
---------------------------------------------------------------------------------------------------------------------------------
数据结构中的队列是什么?
数据结构中的栈是什么?队列是一种常见的数据结构,它具有“先进先出”(First In First Out,FIFO)的特性。类似于排队购买电影票或在餐厅等待服务,先到达的人先被服务,后到达的人则需要等待。在队列中,新的元素被插入到队列的末尾,而已存在于队列中的元素则被移动到更靠近队列的前端。当需要删除元素时,队列中最靠近前端的元素首先被删除,而最靠近末尾的元素则保持不变。
队列的基本操作包括入队(Enqueue),即将新元素添加到队列的末尾;出队(Dequeue),即从队列的前端删除元素并返回该元素;以及查看队列的前端元素(Front)和查看队列是否为空(IsEmpty)。队列还可以实现一些其他操作,如查找元素(Search)、计算队列中元素的数量(Size)和清空队列(Clear)等。
队列在计算机科学中有着广泛的应用,例如在操作系统中进行进程调度,以及在网络协议中进行数据包的传输和路由等。
在JavaScript中,队列也是一个常见的数据结构,可以使用数组来实现。以下是JavaScript中队列的一些常见应用:
-
事件队列:JavaScript在执行异步操作时,会将事件加入到事件队列中。例如,当用户点击按钮时,点击事件会被添加到事件队列中。当JavaScript引擎完成当前执行的任务时,它会查看事件队列中是否有事件,如果有则执行相应的事件处理程序。
-
数据缓存:队列可以用于实现缓存机制,例如,将需要处理的数据加入到队列中,然后按照先进先出的顺序逐个处理数据。
-
循环队列:循环队列是一种特殊的队列,它可以通过在队列末尾添加元素来实现循环。例如,在实现滚动消息时,可以使用循环队列来循环显示消息。
-
实现算法:队列也可以用于实现一些算法,例如广度优先搜索和二叉树的层次遍历等。
总之,队列在JavaScript中有着广泛的应用,可以帮助我们实现各种复杂的功能和算法。
---------------------------------------------------------------------------------------------------------------------------------
数据结构中的链表是什么?
当涉及到链表时,最常见的两种类型是单向链表和双向链表。下面是它们的图示:
单向链表:
+---+ +---+ +---+ +---+ +---+
| 1 | -> | 2 | -> | 3 | -> | 4 | -> | 5 |
+---+ +---+ +---+ +---+ +---+
双向链表:
+---+ +---+ +---+ +---+ +---+
| 1 | <-> | 2 | <-> | 3 | <-> | 4 | <-> | 5 |
+---+ +---+ +---+ +---+ +---+
在上述示例中,每个节点都由一个值和指向下一个节点的指针组成。对于双向链表,还有一个指向前一个节点的指针。链表中的第一个节点称为“头”节点,最后一个节点称为“尾”节点。
--------------------------------------------------------------------------------------------------------------------------------
树
--------------------------------------------------------------------------------------------------------------------------------
二叉树