一. 判断一个字符串是否是回文串
// 回文串:字符串正着读和反着读是一样的
// 思路:
// 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);