1、事件戳排序
var data= [
{
l : [ { id : 1 , ts : '2022-09-10' } , { id : 2 , ts : '2022-09-19' } ]
} ,
{
l : [ { id : 3 , ts : '2022-01-19' } , { id : 4 , ts : '2022-03-20' } , { id : 5 , ts : '2021-08-22' } ]
} ,
{
l : [ { id : 7 , ts : '2009-11-01' } ]
} ,
]
var newarr = [ ]
function sort ( data ) {
data. forEach ( item => {
var minIndex = 0
for ( var i = 1 ; i < item. l. length ; i++ ) {
if ( item. l[ minIndex] . ts >= item. l[ i] . ts) {
minIndex = i
}
}
newarr. push ( item. l[ minIndex] )
} )
return newarr. sort ( ( a, b ) => {
return new Date ( a. ts) - new Date ( b. ts)
} )
}
console. log ( sort ( data ) ) ;
2、求斐波那契数列的第n项的值
1 、动态规划优化
动态规划是一种将复杂问题分解成小问题来解决的算法。在斐波那契数列中,可以使用动态规划来避免重复计算。具体实现如下:
function fibonacci ( n ) {
if ( n === 0 ) return 0 ;
if ( n === 1 ) return 1 ;
const dp = [ 0 , 1 ] ;
for ( let i = 2 ; i <= n; i++ ) {
dp[ i] = dp[ i - 1 ] + dp[ i - 2 ] ;
}
return dp[ n] ;
}
2 、循环优化
使用循环来实现斐波那契数列。这种方法不需要使用递归,也不需要使用额外的空间来存储数组。具体实现如下:
function fibonacci ( n ) {
let a = 0 , b = 1 ;
while ( n > 0 ) {
const c = a + b;
a = b;
b = c;
n-- ;
}
return a;
}
3 、递归优化
var arr= [ ]
function fbnq ( n ) {
if ( n== 1 || n== 2 ) {
return 1
} else {
if ( ! arr[ n- 2 ] ) {
arr[ n- 2 ] = fbnq ( n- 1 )
}
if ( ! arr[ n- 3 ] ) {
arr[ n- 3 ] = fbnq ( n- 2 )
}
return arr[ n- 3 ] + arr[ n- 2 ]
}
}
3、灯泡状态切换
<template>
<!-- <img src="http://d1.realmaster.com/img/download/bulb_on.png"/> -->
<!-- <img src="http://d1.realmaster.com/img/download/bulb_off.png"/> -->
<div class="bulb">
<!-- 通过改变图片的路径来显示不同的图片 两张图片地址不同的地方通过三目运算符判断自定义的数组中的元素的布尔值来进行返回不同的字符串 -->
<img v-for="(item, index) in arr" :key="index" @click="change(index)"
:src="`http://d1.realmaster.com/img/download/bulb_${item ? 'on' : 'off'}.png`">
<div class="countBulb"> {{ '有' + count + '个灯泡是亮的' }} </div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
// 让灯泡产生 并且返回高亮灯泡的个数 组件一挂载(页面一打开)立马执行此函数
// 思路:根据效果图显示
// 1.先产生n个img标签
// 2.在进行每一轮的操作:利用双层for循环 外层控制循环轮数 内层根据灯泡状态切换的当前轮下每个灯泡的状态的变化
//3.统计灯泡高亮的个数
var count = ref(0)
var arr = ref([])
var add=(n,r)=>{
for(var i=0;i<n;i++){
arr.value.push(false)
}
for(var i=1;i<=r;i++){
for(var j=1;j<=n;j++){
if(j%i==0){
arr.value[j-1]=!arr.value[j-1]
}
}
}
return arr.value.filter(item=>item).length
}
var change=(index)=>{
arr.value[index]=!arr.value[index]
}
onMounted(()=>{
count.value=add(100,3)
})
</script>
<style scoped>
.bulb img {
width: 50px;
}
.countBulb {
width: 400px;
height: 50px;
text-align: center;
line-height: 50px;
font-size: 20px;
margin: 20px auto;
background-color: pink;
}
</style>
4、最大数
给定一组非负整数nums,重新排列每个数的顺序 ( 每个数不可拆分) 使之组成一个最大的整数。
function largestNumber ( nums ) {
const sortedArr = nums. map ( num => num. toString ( ) )
. sort ( ( a, b ) => ( b + a) - ( a + b) ) ;
return sortedArr[ 0 ] === '0' ? '0' : sortedArr. join ( '' ) ;
}
const nums = [ 10 , 2 , 5 , 23 , 98 ] ;
const maxNum = largestNumber ( nums) ;
console. log ( maxNum) ;
5、字符串大小写转换
函数内部使用for 循环遍历字符串中的每个字符,判断字符的大小写并进行互换操作。最终将互换后的字符串返回。
function swapCase ( str ) {
let result = '' ;
for ( let i = 0 ; i < str. length; i++ ) {
const char = str. charAt ( i) ;
if ( char === char. toUpperCase ( ) ) {
result += char. toLowerCase ( ) ;
} else {
result += char. toUpperCase ( ) ;
}
}
return result;
}
const str = "Hello World" ;
const swappedStr = swapCase ( str) ;
console. log ( swappedStr) ;
6、给定字符串通过字符出现频率排序
给定一个字符串s,根据字符出现的频率对其进行降序排序。一个字符出现的频率是它出现在字符串中的次数。
返回已排序的字符串。如果有多个答案,返回其中任何一个。
var str = 'aaabbcccddee'
var frequencySort = function ( s ) {
const freq = new Map ( ) ;
for ( let i = 0 ; i < s. length; i++ ) {
freq. set ( s[ i] , ( freq. get ( s[ i] ) || 0 ) + 1 ) ;
}
const sortedFreq = [ ... freq. entries ( ) ] . sort ( ( a, b ) => b[ 1 ] - a[ 1 ] ) ;
let res = '' ;
for ( let i = 0 ; i < sortedFreq. length; i++ ) {
res += sortedFreq[ i] [ 0 ] . repeat ( sortedFreq[ i] [ 1 ] ) ;
}
return res;
} ;
frequencySort ( str)
7、使用map集合统计字符串中每个字符出现的次数
var str = 'abaabbnnaan'
function strCount ( str ) {
const map = new Map ( ) ;
var newStr = '' ;
for ( let i = 0 ; i < str. length; i++ ) {
map. set ( str[ i] , ( map. get ( str[ i] ) || 0 ) + 1 ) ;
}
for ( let key of map) {
newStr += key[ 0 ] + ':' + key[ 1 ] + '次,'
}
return newStr. slice ( 0 , newStr. length - 1 )
}
console. log ( strCount ( str) ) ;
8、编写函数对字符串进行排列组合, 得到所有字符的全排列组合(假设所有字符不重复)
function permute ( str ) {
let result = [ ] ;
if ( str. length == 1 ) {
return [ str] ;
}
for ( let i = 0 ; i < str. length; i++ ) {
let firstChar = str[ i] ;
let charsLeft = str. slice ( 0 , i) + str. slice ( i + 1 ) ;
let innerPermutations = permute ( charsLeft) ;
for ( let j = 0 ; j < innerPermutations. length; j++ ) {
result. push ( firstChar + innerPermutations[ j] ) ;
}
}
return result;
}
var str = 'abc'
console. log ( permute ( str) ) ;
9、不同路径问题
9.1、解法一
function uniquePaths ( m, n ) {
var db = [ ]
for ( let i = 0 ; i < m; i++ ) {
db[ i] = [ ]
for ( let j = 0 ; j < n; j++ ) {
if ( i == 0 || j == 0 ) {
db[ i] [ j] = 1
} else {
db[ i] [ j] = db[ i - 1 ] [ j] + db[ i] [ j - 1 ]
}
}
}
return db[ m - 1 ] [ n - 1 ]
}
console. log ( uniquePaths ( 3 , 7 ) ) ;
9.2、解法二
function uniquePaths ( m, n ) {
var db = new Array ( m) . fill ( 1 ) . map ( ( ) => new Array ( n) . fill ( 1 ) )
for ( var i = 1 ; i < m; i++ ) {
for ( var j = 1 ; j < n; j++ ) {
arr[ i] [ j] = arr[ i - 1 ] [ j] + arr[ i] [ j - 1 ]
}
}
return arr[ m- 1 ] [ n- 1 ]
}
10、为什么arr.map(parseInt)结果为[1, NaN, NaN]
arr = [ '1' , '2' , '3' ] ;
console. log ( arr. map ( parseInt) ) ;
map在执行回调函数会传递三个参数:
parseInt函数用于字符串转数字,只能接收两个参数:
第一个参数为需要被转换的数
第二个参数为需要被转换的数的进制数
进制有:2 进制,8 进制,10 进制,16 进制
以上代码可以转化为:
arr. map ( ( item, index, origin ) => {
console. log ( parseInt ( item, index) ) ;
} )
第一次为:parseInt ( '1' , 0 ) ;
第二次为:parseInt ( '2' , 1 ) ;
第三次为:parseInt ( '3' , 2 ) ;
11、事件轮询机制
11.1、事件轮询机制概念:
JavaScript 事件轮询机制(Event Loop)是指 JavaScript 在单线程上运行时,通过不断地循环查看任务队列中是否有任务来实现异步编程的一种机制。
事件轮询机制的基本流程如下:
首先,执行同步代码,将异步代码加入到任务队列中。
当异步事件触发时,将任务加入到任务队列中。
当任务队列中的任务都执行完毕后,JavaScript 引擎会查看任务队列中是否有任务需要执行。
如果有,则取出任务并执行;如果没有,则等待新的任务加入到任务队列中。
循环执行以上步骤,直到程序结束。
在事件轮询机制中,任务队列分为两种:宏任务(Macro Task)和微任务(Micro Task)。宏任务包括 setTimeout、setInterval、setImmediate、I/O 操作等,而微任务包括 Promise、process.nextTick 等。
在任务执行的过程中,如果遇到微任务,它们会被优先执行,直到微任务队列为空。而在执行宏任务的过程中,如果遇到了新的宏任务,它们会被加入到队列的末尾,等待下一次轮询。
需要注意的是,由于 JavaScript 是单线程执行的,因此如果某个任务的执行时间过长,会阻塞后续任务的执行,导致页面卡顿,因此在编写代码时应该尽量避免出现过长的任务。
11.2、通过案例解释
const promisel = new Promise ( ( resolve, reject ) => {
console. log ( 'Promise1' ) ;
resolve ( ) ;
} )
promisel. then ( ( ) => {
console. log ( 3 )
} )
console. log ( 1 ) ;
const fn = ( ) => {
return new Promise ( ( resolve, reject ) => {
console. log ( 2 ) ;
resolve ( "success" ) ;
} ) ;
} ;
fn ( ) . then ( ( res ) => {
console. log ( res) ;
} ) ;
console. log ( 'start' ) ;
12、选择题数据结构
[
{
题目1 ,
选项 : [
{
text : 选项1
flag : true
} ,
{
text : 选项2
flag : true
}
]
} ,
{
题目2 ,
选项 : [
{
text : 选项1
flag : true
}
]
} ,
]
13、组件通信eventBus的简单封装
class EventBus {
constructor ( ) {
this . events= { }
}
on ( name, callback ) {
if ( ! this . events[ name] ) {
this . events[ name] = [ ]
}
this . events[ name] . push ( callback)
}
off ( name ) {
delete this . events[ name] ;
}
trigger ( name, data ) {
const callbacks = this . events[ name] ;
if ( callbacks) {
for ( let i= 0 ; i< callbacks. length; i++ ) {
callbacks[ i] ( data)
}
}
}
}
const event= new EventBus ( )
event. on ( "click" , function ( data ) {
console. log ( ` clicked ${ data} ! ` ) ;
} )
event. trigger ( "click" , "button" ) ;
event. off ( 'click' ) ;
event. trigger ( "click" , "button" ) ;
14、写一个函数 parseQueryString,它的用途是把 URL 参数解析为一个对象
function parseQueryString ( url ) {
var params = { } ;
var queryString = url. split ( "?" ) [ 1 ] ;
if ( queryString) {
var pairs = queryString. split ( "&" ) ;
for ( var i = 0 ; i < pairs. length; i++ ) {
var pair = pairs[ i] . split ( "=" ) ;
var key = decodeURIComponent ( pair[ 0 ] ) ;
var value = decodeURIComponent ( pair[ 1 ] ) ;
if ( params[ key] ) {
if ( ! Array. isArray ( params[ key] ) ) {
params[ key] = [ params[ key] ] ;
}
params[ key] . push ( value) ;
} else {
params[ key] = value;
}
}
}
return params;
}
15、列表结构转树形结构
方式一:
var arr = [
{ "name" : "分类一" , "id" : 1 , "pid" : 0 } ,
{ "name" : "分类二" , "id" : 2 , "pid" : 0 } ,
{ "name" : "子分类一" , "id" : 3 , "pid" : 1 } ,
{ "name" : "子分类二" , "id" : 4 , "pid" : 1 } ,
{ "name" : "子分类三" , "id" : 5 , "pid" : 2 } ,
{ "name" : "子分类四" , "id" : 6 , "pid" : 2 } ,
{ "name" : "子分类五" , "id" : 7 , "pid" : 3 }
] ;
function listToTree ( arr ) {
var map = [ ] ;
var roots = { } ;
arr. forEach ( item => {
map[ item. id] = { ... item, child : [ ] } ;
} )
map. forEach ( item => {
if ( item. parentId) {
map[ item. parentId] . child. push ( item) ;
} else {
roots[ item. id] = item;
}
delete item. parentId
} )
if ( Object. keys ( roots) . length <= 1 ) {
roots = roots[ Object. keys ( roots) [ 0 ] ]
}
return roots;
}
console. log ( listToTree ( arr) )
方式二:
function arrayToTree ( arr, pid = null ) {
let result = [ ] ;
arr. forEach ( item => {
if ( item. pid === pid) {
let children = arrayToTree ( arr, item. id) ;
if ( children. length) {
item. children = children;
}
delete item. pid;
result. push ( item) ;
}
} ) ;
return result;
}
const data = [
{ id : 1 , pid : null , name : 'a' } ,
{ id : 2 , pid : 1 , name : 'b' } ,
{ id : 3 , pid : 1 , name : 'c' } ,
{ id : 4 , pid : 2 , name : 'd' } ,
{ id : 5 , pid : 2 , name : 'e' } ,
{ id : 6 , pid : 3 , name : 'f' } ,
{ id : 7 , pid : 4 , name : 'f' } ,
{ id : 8 , pid : 4 , name : 'f' } ,
] ;
16、用户权限——菜单过滤
export function getAuthority ( menu : any, permissions : any) {
if ( ! permissions. length) return menu;
var newPermissions = JSON . parse ( JSON . stringify ( permissions) ) ;
newPermissions. map ( ( item : any) => {
if ( ! newPermissions. includes ( item. split ( '-' ) [ 0 ] ) ) {
newPermissions. push ( item. split ( '-' ) [ 0 ] )
return true ;
}
} )
var quanxian = ( menu : any) => {
return menu. filter ( ( item : any) => {
if ( ! item. children) {
return newPermissions. includes ( item. key) ;
}
item. children = quanxian ( item. children) ;
return item. children. length > 0 ;
} )
}
return quanxian ( menu) ;
}
17、数组扁平化
1 、利用递归:
function flattenArray ( arr ) {
var flattened = [ ] ;
for ( var i = 0 ; i < arr. length; i++ ) {
if ( Array. isArray ( arr[ i] ) ) {
flattened = flattened. concat ( flattenArray ( arr[ i] ) ) ;
} else {
flattened. push ( arr[ i] ) ;
}
}
return flattened;
}
2 、利用render方法迭代数组,将数组所有元素按指定规则合并
function flattenArray ( arr ) {
return arr. reduce ( ( result, item ) => {
return result. concat ( Array. isArray ( item) ? flattenArray ( item) : item)
} , [ ] )
}
3 、利用扩展运算符和while 循环
function flattenArray ( arr ) {
var flattened = [ ... arr]
while ( flattened. some ( Array. isArray) ) {
flattened = [ ] . concat ( ... flattened)
}
return flattened
}
18、排序算法
18.1、快排
function quickSort ( arr ) {
if ( arr. length <= 1 ) {
return arr;
}
var pivotIndex = Math. floor ( arr. length / 2 ) ;
var pivot = arr. splice ( pivotIndex, 1 ) [ 0 ] ;
var left = [ ] ;
var right = [ ] ;
for ( var i = 0 ; i < arr. length; i++ ) {
if ( arr[ i] < pivot) {
left. push ( arr[ i] ) ;
} else {
right. push ( arr[ i] ) ;
}
}
return quickSort ( left) . concat ( [ pivot] , quickSort ( right) ) ;
}
18.2、插入排序
function insertionSort ( arr ) {
for ( var i = 1 ; i < arr. length; i++ ) {
var current = arr[ i] ;
var j = i - 1 ;
while ( j >= 0 && arr[ j] > current) {
arr[ j + 1 ] = arr[ j] ;
j-- ;
}
arr[ j + 1 ] = current;
}
return arr;
}
19、数组加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。
函数名 : plusOne
参数 : 非负整数数组
返回值 : 加1 以后的非负整数数组
例如 : plusOne ( [ 1 , 2 , 3 ] ) 返回 [ 1 , 2 , 4 ]
例如 : plusOne ( [ 9 , 9 ] ) 返回 [ 1 , 0 , 0 ]
function plusOne ( arr ) {
var newArr = arr. slice ( 0 ) ;
for ( let i = newArr. length - 1 ; i >= 0 ; i-- ) {
if ( newArr[ i] < 9 ) {
newArr[ i] ++ ;
return newArr;
} else {
newArr[ i] = 0 ;
}
}
newArr. unshift ( 1 ) ;
return newArr;
}
console. log ( plusOne ( [ 9 , 9 , 9 ] ) ) ;