JS常见算法

一. 判断一个字符串是否是回文串

// 回文串:字符串正着读和反着读是一样的
// 思路:
// 1. 将字符串分割成数组,并将数组翻转
// 2. 将新数组再拼接成字符串
// 3. 判断原字符串和新字符串是否一样,一样返回true证明是回文串,否则返回false证明不是回文串。
const checkPlalindrome=(str)=>{
    const newArr=str.split('').reverse().join('');
    // 或者:const newArr = [...str].reverse().join('');
    return newArr==str;
}
console.log(checkPlalindrome('mamamredivider'))    // false

二. 数组去重

// 方法一:indexOf去重,内存小,速度慢
// 思路:新建一个数组,从原数组中遍历,判断这个元素是否在新数组中,如果不在把这个元素push进新数组。最后得到的新数组就是去重之后的数组。
const arr=[1,1,2,4,5,6,6,7,9,1];
const SetArrIndexOf = (arr)=>{
    const setArr=[]   // 去重之后的数组
    for(let i of arr){
        if(setArr.indexOf(i)===-1){
            setArr.push(i)
        }
    }
    return setArr
} 
console.log(SetArrIndexOf(arr));   // [1, 2, 4, 5, 6, 7, 9]

// 方法二:哈希去重,内存大,速度快
// 思路:把每一个数字当做成键名,键是不可以重复的。
const arr=[1,1,2,4,5,6,6,7,9,1];
const SetArrHash = (arr)=>{
    const setArr = [];
    const obj = {};
    for (let i of arr){
        if(!obj[i]){    
            setArr.push(i)
            obj[i]=true
        }
    }
    return setArr
}
console.log(SetArrHash(arr));   // [1, 2, 4, 5, 6, 7, 9]

// 方法三:es6 includes
// 思路:和Indexof差不多
const arr=[1,1,2,4,5,6,6,7,9,1];
const SetArrInclude = (arr) => {
    const setArr = []
    for(let i of arr){
        if(!setArr.includes(i)){
            setArr.push(i)
        }
    }
    return setArr
}
console.log(SetArrInclude(arr));    // [1, 2, 4, 5, 6, 7, 9]

// 方法四:set去重
// 思路:利用es6中Set()的唯一性
// 注意:new Set()之后是一个伪数组,需要把伪数组转化为真正的数组。
const SetArrSet = (arr)=>{
    // const setArr = [...new Set(arr)]
    const setArr = Array.from(new Set(arr))
    return setArr
}
console.log(SetArrSet(arr));

三. 统计数组或者字符串中每个元素出现的次数

// 方法一:传统for循环
// 思路:
// 1. 新建一个对象,遍历数组或者字符串
// 2. 将数组或者字符串中的每一项作为对象的键
// 3. 统计键对应的值,如果没有置为1,如果有每次在原基础上加一
// 4. 返回这个对象,键为每一个元素,值为对应出现的次数
const arr = ['杨幂','杨颖','杨洋','杨洋','杨迪','杨颖','杨颖']
const str = 'wangjiajiawwwjiajiawwwww'
// 传统for循环的办法
function getWordCnt(param){
	const obj = {}  // 定义一个对象用来接收统计结果
	for(let i of param){
		obj[i] = (obj[i] + 1) || 1
	}
	return obj
}
getWordCnt(arr)    // {杨幂: 1, 杨颖: 3, 杨洋: 2, 杨迪: 1}
getWordCnt(str)    // {w:9, a:5, n:1, g:1, j:4, i:4}

// 方法二:reduce()
// 关于reduce()函数的参数和详细用法在本博客的ES6篇中有具体叙说,请读者参考。
// 思路:同方法一。
function getWordCnt(param){
	if(typeof param === 'string'){   // 如果是字符串转化成数组在处理
		param = param.split('')
		// param = [...param]
	}
	return param.reduce((preValue,curValue)=>{
		preValue[curValue] = (preValue[curValue] + 1) || 1
		return preValue
	},{})
}
getWordCnt(arr)    // {杨幂: 1, 杨颖: 3, 杨洋: 2, 杨迪: 1}
getWordCnt(str)    // {w:9, a:5, n:1, g:1, j:4, i:4}

四.求一个数组的最大差值

// 思路:找到这个数组的最大值和最小值,最大值减去最小值。
// 方法一:通用循环法:
arr = [1,2,3,6,16]
function findMaxDiff(arr){
  let max=arr[1],min=arr[1]
  arr.forEach(item => {
    if(item>=max){
      max=item
    }else if(item<=min){
      min=item
    }
  });
  return [max,min,max - min ]
}
console.log(findMaxDiff(arr)[2]);    // 15

// 方法二:Math.Max() + Math.Min()
function findMaxDiff(arr){
    // 找最大值
    // const maxNumber=Math.max(...arr)
    const maxNumber=Math.max.apply(null,arr)

    // 找最小值
    // const minNumber=Math.min(...arr)
    const minNumber=Math.min.apply(null,arr)

	// 求差值
    const diffNumber=maxNumber-minNumber
    return [maxNumber,minNumber,diffNumber]
}
console.log(findMaxDiff(arr)[2]);     // 15

五.随机生成指定长度字符串

可用于随机生成验证码

// 思路:
// 1. 新建一个字符串,用于接受生成的字符串
// 2. 获取str的长度,在这个长度内生成一个随机数
// 3. 根据生成的随机数在str中取到对应的字符。
// 4. 重复步骤三
const str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ9876543210';
const len = str.length;
const randomString = (n)=>{
    let tmp = '';
    for (let i=0;i<n;i++){
        // 生成一个str长度内的随机数
        const randomNumber = Math.floor(Math.random()*len)
        tmp += str[randomNumber]
    }
    return tmp
}
console.log(randomString(4));   // 从str中生成长度为4的随机字符串

// 注:生成指定范围内的随机整数
const getRandomNum = (min,max)=>{
    const randomNumber = Math.floor(Math.random()*(max-min)) + min
    return randomNumber
}
console.log(getRandomNum(3,8));   

六. 斐波那切数列

// 斐波那锲数列:第一个为1,第二个为1,从第三个数开始每个数等于前两个数字之和。
const Fibonaci=(n)=>{
    if (n===1){
        return 1;
    }else if(n===2){
        return 1;
    }
        return Fibonaci(n-1)+Fibonaci(n-2)    
}
console.log(Fibonaci(12));   // 144

七.求阶乘

// 方法:递归
// 思路:n的阶乘等于n乘以n-1的阶乘
function factorial(n){
	if(n===1){
		return 1
	}
	return n * factorial(n-1)
}
factorial(5)    // 120

八. 创建1-100的数组

const arr=Array.from(Array(100),(value,index)=>index+1)   // [1,2,3,...,100]
const arr2=Array.from({length:100},(value,index)=>index+1)    // [1,2,3,...,100]

九.洗牌算法

// 洗牌算法:随机打乱一个初始数组,使得原数组中的每一个元素在新数组中每一个位置出现的概率相同。
// 思路:
// 1. 新建一个数组用于接收打乱后重新排列
// 2. 在原数组的长度范围内生成一个随机数,将这个随机数作为下标,把数组中对应该下标的值push进新数组中。
// 3. 从原数组中删除刚才push进去的那个值(关键一步)
function shuffle(arr){
	const arrNew=[];  // 打乱后的数组
    const len=arr.length 
    for (let i=len;i>0;i--){
        // 生成一个在0-len之间的随机数
        const rand=Math.floor(Math.random()*i)
        // 从原数组中拿出这个随机下标对应的数放入新数组当中
        arrNew.push(arr[rand]);
        // 从原数组当中删除拿出的这个值
        arr.splice(rand,1)
    }
    return arrNew;
}
console.log(shuffle([1,2,3,4,5,6,7,8,9]));

十. 比较版本数

const compare=(a,b)=>{
    if(a>b){  // 字符串之间可以直接比较大小,会自动按照从左到右的顺序逐一比较
        return '最大版本是:'+a
    }else if(a==b){
        return '两个版本一样大'
    }
    return '最大版本是:'+b
}
console.log(compare('1.4.3','1.5.4'))    // 最大版本是:1.5.4

十一.括号匹配

// 条件:
// 1. 左括号必须用相同类型的右括号闭合
// 2. 左括号必须以正确的顺序闭合(不得出现嵌套)
// 例如:输入:’()’ 输出:true。  输入:’( ) [ ]{ }’ 输出:true。  输入:’{ ]’ 输出:false。  输入:’( [ ) ]’ 输出:false。    输入:’{ [ ] }’ 输出:true    

// 思路:利用栈的先进后出原则
// 1. 看输入的字符串长度是不是奇数,如果是奇数则一定匹配不成功
// 2. 长度是偶数的情况下遇到左符号则放进一个数组中
// 3. 继续遍历字符串,如果遇到右字符串,检测当前数组长度,若为零表示没有左字符串,此时一定匹配不成功,若不为零继续往后面走。
// 4. 同时从数组中弹出一个最后的符号,如果如果当前符号匹配不上则最终匹配不上
// 5. 最终当这个数组长度为零的时候表示匹配成功
function brabket(str){
	if(str.length%2 !==0){   // 余数不等于0表示长度为奇数,必然匹配不成功
        return false
    }else{
        const arrList=[]   // 定义一个栈
        for (let i=0;i<str.length;i++){
            const current=str[i];
            if(current==='(' || current==="[" || current==='{'){
                arrList.push(current)
            }else{
                if(arrList.length===0){    // 若为零表示没有左字符串,此时一定匹配不成功
                    return false
                }else{
                    if(current===')'){
                        if(arrList.pop()!=='(') return false
                    }else if(current===']'){
                        if(arrList.pop()!=='[') return false
                    }else if(current==='}'){
                        if(arrList.pop()!=='{') return false
                    }
                }
            }
        }
        return !arrList.length   // 最终看栈的长度,长度为零表示匹配成功,返回true,否则返回false
    }
}
console.log(brabket('{([)]}'))    // false

十二. 判断链表是否有环

// 方法:快慢指针
// 思路:定义两个指针,一个快指针,一个慢指针。当快指针指向的内存等于慢指针指向的内存的时候表示有环。
var judge=(list)=>{
    if (list===null){
        return false
    }
    // 常见快慢指针
    let fast=list.next.next;
    let slow=list.next;
    while(slow !== null && fast !== null && fast.next !== null){
        if(fast===slow){
            return true
            // return fast  // 环的入口
        }
        fast=fast.next;
        slow=slow.next;
    }
}

十三.连续子数组的最大和

// 思路:动态规划:DP[i]=max(DP[i-1],A[i])
// 方法一:
const maxsumFun=(arr)=>{
    let tempsum=0;
    let maxsum=0;
    for(let i=0;i<arr.length;i++){
        tempsum=tempsum+arr[i];
        if(tempsum<=0){
            tempsum=0;
        }else{
           if(tempsum>maxsum){
               maxsum=tempsum
           }
        }
    }
    return maxsum
}
console.log(maxsumFun([-2,1,3,1,-6]));    // 5

// 方法二:
const maxsumFun=(arr)=>{
    let tempsum=0;
    let maxsum=0;
    for(let i=0;i<arr.length;i++){
        tempsum=Math.max(tempsum+arr[i],arr[i])
        maxsum=Math.max(tempsum,maxsum)
    }
    return maxsum;
}
console.log(maxsumFun([-2,1,3,1,-6]));    // 5

// 方法三:
const maxsumFun= (arr)=>{
    let max = arr[0];
    for (let i=1;i<arr.length;i++){
        arr[i] += arr[i-1]>0 ? arr[i-1] : 0;
        max = Math.max(max,arr[i])
    }
    return max
}
console.log(maxsumFun([-2,1,3,1,-6]));    // 5

// 方法四:
function maxsumFun(array)
{
    let dp = []
    dp[0] = array[0]
    for(let i = 1; i < array.length; i ++){
        dp[i] = Math.max(dp[i -1] , 0) + array[i]
    }
    return Math.max.apply(null,dp)
    
}
console.log(maxsumFun([-2,1,3,1,-6]))    // 5

十四.数组的扁平化

// 扁平化:降低高维数字的维度
// 方法一:
const arr=[1,[2,'3',[4,5,6]]]
const arrFlat=(arr)=>{
    const arrFlat=arr.join(',').split(',').map((item)=>{
        return +item
    })
    return arrFlat
}
console.log(arrFlat(arr));    // [1, 2, 3, 4, 5, 6]

// 方法二:
const arrFlat=(arr)=>{
    const arrFlat=arr.toString().split(',').map((item)=>{
        return +item
    })
    // 这里用String(arr)也行,String(arr).split(',')
    return arrFlat
}
console.log(arrFlat(arr));    // [1, 2, 3, 4, 5, 6]

// 方法三:利用flat属性,
// flat(n) 表示降低n度。
// flat(Infinity) 表示降低到1维数组
const arrFlat=(arr)=>{
    if(arr.length){
        const flatArr=arr.flat(Infinity)
        return flatArr;
    }
}
console.log(arrFlat(arr));    // [1, 2, 3, 4, 5, 6]

十五. 求丑数组成的数列

// 1. 概念:只包含质因子2、3或者5的数称之为丑数
// 2. 思路:
// (1)任何一个丑数一定可以由另一个丑数乘以2或者乘以3或者乘以5得到
// (2)这样一定会有重复的值,所以我们从每一次计算的结果中取最小的值,放进数组中
// (3)定义一个数组用于存放丑数的值
// (4)定义三个指针分别代表乘以2,乘以3,乘以5的丑数的位置

// 方法一:
const UglyNumber = (n)=>{
    if (n<=6) return n;   // 前6个数都是丑数
    let p2 = 0;      // 乘以2的丑数位置
    let p3 = 0;      // 乘以3的丑数位置
    let p5 = 0;      // 乘以5的丑数位置
    let uglyArr=[1]    // 存放丑数的数组
    for (let i=1;i<n;i++){
        let minNumber = Math.min(uglyArr[p2]*2,uglyArr[p3]*3,uglyArr[p5]*5)
        if(minNumber === uglyArr[p2]*2){
            p2++
        }
        if(minNumber === uglyArr[p3]*3){
            p3++
        }
        if(minNumber === uglyArr[p5]*5){
            p5++
        }
        uglyArr.push(minNumber)
    }
    return uglyArr 
}
UglyNumber(8)    // 前八个丑数[1, 2, 3, 4, 5, 6, 8, 9]

十六.如何验证一个数是否是素数

// 素数:一个数只能被1和自身整除,2是最小素数
// 除了2以外,素数都是奇数,奇数不一定是素数例如9
// 思路:
// 1. 1既不是素数也不是合数
// 2. 2是最小的素数
// 3. 用n除以从2到n-1的每一个数,如果有一个能整除的直接返回false,否则返回true。
const FunctionIsPrime = (n)=>{
    let i = 2;
    if(n===1){
        return false 
    }else if(n===2){
        return true
    }else{
        while(n>i){
            if(n % i === 0){
                return false
            }else{
                i++
            }
        }
        return true
    }
}
console.log(FunctionIsPrime(9));     // false
console.log(FunctionIsPrime(11));    // true

十七.求一个数的所有质因数

// 思路:
// 1. 新建一个数组用于存储质因子,这个数记为n,i的初始值记为2,执行while循环。
// 2. 执行n除以i如果能除得尽,将i放进一个数组中。此时将商作为被除数,继续执行除以i的操作。
// 3. 如果除不尽将i自增1,继续执行步骤二,直到最后的商为1。
// 4. 最后得到的数组就是所有质因子构成的数组(可用于判断一个数是不是丑数,如果数组中有除了2,3,5以外的数就不是丑数)

function arrPrime(n){
	t = n
    if(n===1){
        return '1即不是质数也不是合数'
    }else {
        const primeArr = []
        let i = 2
        while(n>=2){
            if(n%i === 0){
                primeArr.push(i)
                n = n/i
            }else{
                i++
            }
        }
        // 判断这个数是不是丑数,看质因数数组里面的数字是否有2、3、5以外的
        // 如果有就不是丑数,没有就是丑数
        let k=0
        const len=primeArr.length
        while(len>k){
            if(primeArr[k]!==2 && primeArr[k]!==3 && primeArr[k]!==5){
                return [primeArr,t + '不是丑数']
            }else{
                k++
            }
        }
        return [primeArr,t + '是丑数']
    }
}
console.log(arrPrime(11));    // [ [ 11 ], '不是丑数' ]
console.log(arrPrime(8));    // [ [2,2,2], '是丑数' ]

十八.找两个数的最大公约数和最小公倍数

// 最大公约数:
// 思路:
// 1. 用大得数除以小的数,如果能除得尽,则这个小数就是最大公约数
// 2. 如果除不尽,将余数作为除数,小数作为被除数
// 3. 递归执行此操作。
const MaxCommonDivisor = (m, n) => {
    let r = m % n // 默认m是较大的那一个数
    if (r === 0) {
        return n
    } else {
        m = n
        n = r
        return MaxCommonDivisor(m, n)
    }
}
console.log(MaxCommonDivisor(20, 8));    // 4

// 最小公倍数:两数相乘除以做大公约数
const MinCommonMultiple = (m, n) => {
    return m * n / MaxCommonDivisor(m, n)

}
console.log((MinCommonMultiple(36, 8)));    // 72

十九. 将json转化为js对象

// json:一种轻量级的前后端数据交换格式,本质上就是字符串
// 方法一:使用JSON.parse
const jsonData = '{"name":"wangjiajia","age":"24"}'
JSON.parse(jsonData)    // {name:'wangjiajia',age:'24'}

// 方法二:使用eval()
// eval():接受一个字符串作为参数,并作为脚本执行
// eval("var a=1");  //声明一个变量a并赋值1。
// eval("2+3");  //执行加运算,并返回运算值。
// eval("mytest()");  //执行mytest()函数。
// eval("{b:2}");//声明一个对象。如果想返回此对象,则需要在对象外面再嵌套一层小括如下:eval("({b:2})");
eval('(' + jsonData + ')')     //  {name:'wangjiajia',age:'24'}

二十. 字符串去重

// 方法一:search 或者 indexOf 这两个在这里一样,归为一类。
// serach()和indexOf()的区别
// 相同点:都是检索字符串中指定的子字符串,如果找到返回子字符串第一次出现的位置,如果没有找到则返回-1。
// 不同点:search()传的参数可以是字符串也可以是正则表达式,indexOf()只能传字符串。
const str = '11223344aabbcc'
const StringDeweight= (str) => {
    let newStr = "";
    for (let i of str) {
        if (newStr.search(i) == -1)
            newStr += i;
    }
    return newStr;
}
console.log(StringDeweight(str))    // 1234abc

// 方法二:set去重
// 思路:
// 1. 先将字符串转化为数组
// 2. 利用数组去重的set方法
// 3. 将去重后的数组拼接成字符串
function StringDeweight(str){
	retun [...new Set(str.split(''))].join('')
	// return [...new Set([...str])].join('')
	// return Array.from(new Set([...str])).join('')
	// return Array.from(new Set(Array.from(str))).join('')
	// 注:这里的写法有很多种,只要能把字符串转化为数组就行
}
console.log(StringDeweight(str))    // 1234abc 

// 方法三:利用对象中键的唯一性
const StringDeweight= (str) => {
    var obj = {};
    var newStr = "";
    for (let i of str) {
        if (!obj[i]) {
            newStr += i;
            obj[i] = 1;
        }
    }
    return newStr;
}
console.log(StringDeweight(str))    // 1234abc

二十一. 数组排序

// 说明:以从小到大排序为例。
// 方法一:冒泡排序
// 思路:
// 1. 两层for循环,从第一数字开始,用后面的每一个数字和他比较,将大的数放到后面。
// 2. 先执行内层循环再执行外层循环
const arr = [2,3,1,9,6,7,5,8]
const BubbleSort = (arr)=>{
    for(let i=0;i<arr.length;i++){
        for(let j=0;j<arr.length-1-i;j++){
            // 从小到大排序
            if(arr[j]>arr[j+1]){
                [arr[j],arr[j+1]] = [arr[j+1],arr[j]]
            }
            // 从大到小排列
            // if(arr[j]<arr[j+1]){
            //     [arr[j],arr[j+1]] = [arr[j+1],arr[j]]
            // }
        }
    }
    return arr
}
console.log(BubbleSort(arr));     //  [1, 2, 3, 5, 6, 7, 8, 9]

// 方法二:快速排序
// 思路:
// 1.先找到中间的元素(向下取整),将这个元素作为基准值。
// 2.定义两个数组,分别用于存储比基准值小的数(左数组)和比基准值大的数(右数组)
// 3.对这两个数组递归执行步骤一和步骤二
// 4.最后将左数组和基准值和右数组拼接成一个完整的数组
// 5.终止条件是直到每个数组的长度都为1
const QuickSort = (arr)=>{
    // 终止条件
    if(arr.length<=1){
        return arr
    }else{
        // 定义左右两个数组
        const leftArr = [];
        const rightArr = [];
        // 计算基准值
        const index = Math.floor(arr.length/2)
        const value = arr.splice(index,1)
        for(let i of arr){
            if(i>value){
                rightArr.push(i)
            }else{
                leftArr.push(i)
            }
        }
        return [...QuickSort(leftArr),...value,...QuickSort(rightArr)]
    }
}
console.log(QuickSort(arr));    //  [1, 2, 3, 5, 6, 7, 8, 9]

// 方法三:插入排序
// 思路:
// 1. 第一个元素默认已经排序
// 2. 取出下一个元素,在前面已经排序好的元素中,从后向前扫描
// 3. 如果该元素(排序好的)大于新元素,则将该元素向后移动一格
// 4. 重复步骤三,直到排序好的元素小于或者等于新元素,将这个元素插在其后
// 5. 重复2-4
const InsertSort = (arr)=>{
    for (let i=1;i<arr.length;i++){
        let  j = i-1,key = arr[i]
        while(arr[j]>key){
            arr[j+1] = arr[j];
            j--
        }
        arr[j+1] = key
    }
    return arr
}
console.log(InsertSort(arr));    //  [1, 2, 3, 5, 6, 7, 8, 9]  

二十二. 手写flat函数

// flat():数组扁平化函数
// 思路:
// 1. 遍历数组中的每一项,如果是一个数组,把它展开放进一个新数组中,如果不是直接放进新数组中。
// 2. 递归执行是数组的这一项
// arguments为函数内部对象,表示传入函数的所有参数,
// arguments.callee代表代表函数名,多用于递归调用
const arr=[1,2,['3',4,[5,6]]]
function flatFun(arr){
    let res = []
    // arr.forEach(item => {
    //     if(Array.isArray(item)){
    //         res.push(...arguments.callee(item))
    //     }else{
    //         res.push(item)
    //     }
    // });
    for(let item of arr){
        if(Array.isArray(item)){
            res.push(...arguments.callee(item))   // 因为使用的arguments所以不能使用箭头函数
        }else{
            res.push(item)
        }
    }
    return res
}
console.log(flatFun(arr));    // [1, 2, '3', 4, 5, 6]

二十三. 手写map,filter函数

const arr=[1,2,3]
const mapAndFilterFunction=(arr,callback)=>{
    if(! Array.isArray(arr) || !arr.length || typeof callback !=='function'){
        return []
    }else {
        let result=[]
        for(let i of arr){
            if(callback(i)){
                result.push(callback(i))
            }
        }
        return result
    }
}
const res = mapAndFilterFunction(arr,(item)=>{
    return item*2
})
const res2 = mapAndFilterFunction(arr,(item)=>{
    if(item%2 === 0){
        return item
    }
})
console.log(res);   // [2,4,6]
console.log(res2);  // [2]

二十四. 手写call,apply,bind()

Function.prototype.mycall = (context)=>{
    if(typeof context === 'undefined' || typeof context === 'null'){
        context = window
    }
    // context = context || window
    context.fn = this
    const args = [...arguments].slice(1)  // 剥离参数
    const result = context.fn(...args)
    delete context.fn
    return result
}


// 2.手写apply
Function.prototype.myapply = (context)=>{
    if(typeof context === 'undefined' || typeof context === 'null'){
        context = window
    }
    // context = context || window
    context.fn = this
    if(arguments[1]){
        result = context.fn(...arguments[1])
    }else{
        result = context.fn()
    }
    delete context.fn
    return result
}

// 3.手写bind
Function.prototype.mybind = (context)=>{
    context = context || window
    const _this = this
    const args = [...arguments].slice(1)
    return function Fun(){
        if(this instanceof Fun){
            return new _this(...args,...arguments)
        }
        return _this.apply(context,args.concat(...arguments))
    }
}

二十五. 通过xhr实现axios的get请求

var Ajax={
    get:function(url){
        return new Promise((resolve,reject)=>{
            var xhr=new XMLHttpRequest();
            xhr.open('get',url,true);
            xhr.onreadystatechange=function (){
                if(xhr.readyState==4 &&  xhr.status==200){
                    fn.call(this,xhr.responseText)
                }
            };
            xhr.send()
        })
    }
}

二十六. 获取url里面参数

// 方法一:split()
// 思路:
// 1. 先根据?分割,然后取出?后面的字符串。
// 2. 将这部分通过&分割,得到一个数组
// 3. 对数组中的每一项用=分割,分割后会得到=前后的两部分内容,新建一个对象将前面的作为键,后面的作为值。
let URL = "http://www.baidu.com?name=caocongyouren&age=25&sex=男&wife=wangjiajia"
function getUrlParams(url){
  let obj = {}
  const urlStr = url.split('?')[1]
  const urlArr = urlStr.split('&')
  // for(let i of urlArr){
    // const tempArr = i.split('=')
    // obj[tempArr[0]] = tempArr[1]
   // }
 // 或者
 const tempArr = urlArr.map(item => item.split('='))
 obj = Object.fromEntries(tempArr)  // 不支持低版本浏览器
  return obj
}
console.log(getUrlParams(URL));   // {name: 'caocongyouren', age: '25', sex: '男', wife: 'wangjiajia'}

// 方法二:
// 思路:
// 1. 使用 new URLSearchParams(url) 方法,返回一个 URLSearchParams 对象,再调用 entries() 方法返回一个可迭代对象(Iterator);
// 2. 使用 Object.fromEntries(iterable) 方法转化为普通对象
function getUrlParams2(url) {
    let urlStr = url.split('?')[1]
    const urlSearchParams = new URLSearchParams(urlStr)
    const result = Object.fromEntries(urlSearchParams.entries())
    return result
}
console.log(getUrlParams2(URL))   // {name: 'caocongyouren', age: '25', sex: '男', wife: 'wangjiajia'}

// 方法三:正则匹配
function getUrlParams3(url){
  // \w+ 表示匹配至少一个(数字、字母及下划线), [\u4e00-\u9fa5]+ 表示匹配至少一个中文字符
  let pattern = /(\w+|[\u4e00-\u9fa5]+)=(\w+|[\u4e00-\u9fa5]+)/ig;
  let result = {};
  url.replace(pattern, ($, $1, $2)=>{
      result[$1] = $2;
  })
  return result
}
console.log(getUrlParams3(URL))   // {name: 'caocongyouren', age: '25', sex: '男', wife: 'wangjiajia'}

// 方法四:引入qs库,一般在项目中会使用,可以看到该方法比上述其他方法简洁明了。
// 说明:
// 1.qs.parse()是将URL解析成对象的形式
// 2. qs.stringify()是将对象序列化成URL的形式,以&进行拼接

 npm install qs
 import qs from 'qs'
 qs.parse(URL)   // {name: 'caocongyouren', age: '25', sex: '男', wife: 'wangjiajia'}

二十六. 手写new操作符

// new执行的步骤:
// 1. 创建一个空对象
// 2. 将this绑定到这个空对象上面
// 3. 执行构造函数
// 4. 返回这个对象
function newFunction(fun,...args){
    const obj={}
    obj.__proto__=fun.prototype
    let res=fun.call(obj,...args)
    if( (res!==null) && (typeof res==='object' || typeof res==='function')) {
        return res
    } 
}
``
## 二十七. 二叉树的深度
```javascript
// 二叉树的深度就是左右子树的最大深度+1 (根结点)
// 思路:递归比较左右子树的深度,去二者的最大值
const TreeDepth = (root)=>{
    if(!root) return 0;
    const depth = Math.max(TreeDepth(root.left),TreeDepth(root.right))+1
    return depth
}

二十八. 重建二叉树

// 已知二叉树的前序遍历和中序遍历,重建二叉树
// 思路:
// 1. 创建根结点root
// 2. 递归创建左子树,右子树
// 3. 返回root
const rebuildTree = (pre,vin)=>{
    if(!pre.length || !vin.length){
        return null
    }
    // 创建根结点
    const root = pre[0]
    // 左子树长度
    const leftLength = vin.indexof(root)

    // 递归创建左子树
    root.left = rebuildTree(pre.slice(1,leftLength+1),vin.slice(0,leftLength))

    // 递归创建右子树
    root.right = rebuildTree(pre.slice(leftLength+1),vin.slice(leftLength+1))
    return root 
}

二十九. 求二叉树的镜像

// 思路:
// 递归执行将二叉树的左子树和右子树调换
const Mirror =(root)=>{
    if(! root){
        return null
    }else{
        let temp = root.left
        root.left = Mirror(root.right)
        root.right = Mirror(temp)
        return root
    }
}

三十. 输出一个直角三角形和一个等腰三角形

// 直角三角形
function rightTriangle(num){
  let str = "";
  // 外层控制三角形的层数
  for (var i = 0; i < num; i++) {
    // 内层控制每一行三角形的个数,每一层的个数等于当前的层数
    for (var j = 0; j < i + 1 ; j++) {
      str += "💗";
    }
    str += "\n";
  }
  return str
}
console.log(rightTriangle(5));   // 💗
💗💗
💗💗💗
💗💗💗💗
💗💗💗💗💗

// 等腰三角形
function equicruralTriangle(num){
  let str = ''
  // i 控制行数
  for(let i=1;i<=num;i++){
    // j 控制前面空格数 空格数 = 总行数减去当前行数
    for(let j=1;j<=num-i;j++){
      str += ' '
    }
    // k 控制每行星星个数 星星个数=两倍当前行数减一 也就是 (2*i-1)
    for(let k=1;k<=2*i-1;k++){
      str += '*'
    }
    str += '\n'
  }
  return str
}
console.log(equicruralTriangle(5));   //     *
   ***
  *****
 *******
*********

三十. 计算排列数和组合数

// 排列数
// An,m表示n的阶乘除以m的阶乘(默认n>m)
function permutation(n,m){
  // 定义一个计算阶乘的函数
  function factorial(n){
    if(n===1){
      return 1
    }
    return n * factorial(n-1)
  }
  return factorial(n)/factorial(m)
}
console.log(permutation(5,2));    // 60


// 组合数
// Cn,m表示n的阶乘除以m的阶乘(默认n>m)除以n-m的阶乘
function combination(n,m){
  // 定义一个计算阶乘的函数
  function factorial(n){
    if(n===1){
      return 1
    }
    return n * factorial(n-1)
  }
  return factorial(n)/(factorial(m) * factorial(n-m))
}
console.log(combination(5,2));    // 10

三十一. 删除对象中值为null,undefined,空字符串的属性

const obj = {
	name:'wangjiajia',
	age:25,
	address:'anhui',
	school:undefined,
	like:'book',
	car:'',
	study:'三国演义',
	sister:null
}

function deleteFun (value){
	if(value === undefined || value === null || value === ''){
		return 
	}
	return true
}

// 方法一:
function preProcessFun(obj){
	const newObj = {}
	Object.keys(obj).forEach(item=>{
		if(deleteFun(obj[item])){
			newObj[item] = obj[item]
		}
	})
	return newObj
}

// 方法二:
function preProcessFun(obj){
	Object.keys(obj).forEach(item=>{
		if(!deleteFun(obj[item])){
			delete obj[item]
		}
	})
	return obj
}

// 方法三:
const newObj = Object.keys(obj).filter(key => obj[key] != null && obj[key] != undefined && obj[key] != '').reduce((init,key) => ({...init,[key] : obj[key]}),{})

// 结果:
{
  name: 'wangjiajia',
  age: 25,
  address: 'anhui',
  like: 'book',
  study: '三国演义'
}

三十二. 替换对象和数组对象中的键值

// 例如把接口返回对象data {id:“11”,name:“张三”} 的key值替换成 {序列:“11”,姓名:“张三” }
// 对象
const obj1 = {
  id:"11",
  name:"张三"
}
const keyMap = {
  id:"序列",
  name:"姓名"
}

const obj2 = Object.keys(obj1).reduce((newData,key)=>{
  const newKey = keyMap[key] || key
  newData[newKey] = obj1[key]
  return newData
},{})
console.log(obj2);  // { '序列': '11', '姓名': '张三' }

// 数组对象
const arr = [
  {
    id:"11",
    name:"张三"
  },
  {
    id:"12",
    name:"李四"
  },
  {
    id:"13",
    name:"王二"
  }
]

const newArr = arr.map(item => {
  return {
    '序列': item.id,
    '姓名': item.name
  }
})
console.log(newArr);  
[
  { '序列': '11', '姓名': '张三' },
  { '序列': '12', '姓名': '李四' },
  { '序列': '13', '姓名': '王二' }
]

三十三. 获取标准时间格式

function getCurrentTime() {
  const now = new Date();
  const year = now.getFullYear();
  const month = now.getMonth() + 1;
  const day = now.getDate();
  const hour = now.getHours();
  const minute = now.getMinutes();
  const second = now.getSeconds();
  return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}
console.log(getCurrentTime())  // 2023-7-19 16:59:43

三十四. 获取所有的children数据,对其操作

const list = [
  {
    id: '1',
    name: '我是1',
    children: [
      {
        id: '1-1',
        name: '我是1-1'
      },
      {
        id: '1-2',
        name: '我是1-2',
        children: [
          {
            id: '1-2-1',
            name: '我是1-2-1'
          }
        ]
      }
    ]
  },
  {
    id: '2',
    name: '我是2',
    children: [
      {
        id: '2-1',
        name: '我是2-1'
      }
    ]
  }
]
function getAllChildrenData(arr, id){
  arr.some(item => {
    if(item.id == id){  // 递归结束条件
      Object.assign(item, {disabled: true})
      return true
    }else if(item.children && item.children.length){
      getAllChildrenData(item.children, id)
    }
  })
}
getAllChildrenData(list, '2-1')
console.log(list);

在这里插入图片描述

  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值