每天6道JavaScript手写 - day 3

87 阅读2分钟

1、千分位分隔,支持任意位数分割

 function format(n, cut=3) {
     let num = n.toString()
     let decimals = ''
     // 考虑小数
     num.indexOf('.') > -1 ? decimals = '.'+num.split('.')[1] : decimals
     let len = num.length
     let formatted = ''
     
     if(len <= cut) {
         return num + decimals
     }else{
         let remainder = len % cut
         // 不是3的整数倍
         if(remainder) {
             // 正则的创建方式是一个需要注意的点
             formatted = num.slice(0, remainder)+'.'+num.slice(remainder, len).match(new RegExp('\d{'+cut+'}','g')).join(',') + decimals
         }else{
             formatted = num.slice(0, len).match(new RegExp('\d{'+cut+'}','g')).join(',') + decimals
         }
     }
     return formatted
 }

image.png

2、解析 URL Params

 function parseUrlParams(url) {
     // 拿到第一个问号之后的部分
     let matchRes = /(?<=?)(.*)/.exec(url)
     let paramsObj = {}
     if(matchRes){
         // 拿到query
         const quertParams = matchRes[1]
         // 拿到query数组
         const paramsArr = quertParams.split('&')
         // 提取query
         paramsArr.forEach((param) => {
             if(param.includes('=')) {
                 // 有值的参数
                 let [key, val] = param.split('=')
                 //解码
                 val = decodeURIComponent(val) 
                 if(paramsObj.hasOwnProperty(key)) {
                     // 如果已经存在相同的 key,则将值组成数组
                     paramsObj[key] = [].concat(paramsObj[key], val)
                 }else{
                     // 否则直接赋值
                     paramsObj[key] = val
                 }
             }else{
                 // 没值的参数给个null
                 paramsObj[param] = null
             }
         })
     }
     return paramsObj
 }

image.png

3、Promise实现图片异步加载

 function async(url) {
     return new Promise((resolve, reject) => {
         let img = new Image()
         img.src = url
         img.onLoad = () => {
             resolve(img)
         }
         img.onError = (err) => {
             reject(err)
         }
     })
 }
 ​
 imageAsync('url')
     .then(() => {
         console.log('load success')
     })
     .catch((err) => {
         console.log('load error')
     })

4、打印红蓝绿

红灯 3s 亮一次,绿灯 1s 亮一次,黄灯 2s 亮一次;如何让三个灯不断交替重复亮灯?

递归callback

顾名思义,打印下一个灯就是上一个的回调,最后一个回调触发递归

 function print(delay, color, callback) {
     setTimeout(() => {
         console.log(color)
         callback()
     }, delay)
 }
 function step() {
     print(3 * 1000, 'red', () => {
         print(1 * 1000, 'green', () => {
             print(2 * 1000, 'yellow', step)
         })
     })
 }

image.png

Promise

Promise方法自然就是写到then里了,最后一个then触发递归就行

 function print(delay, color) {
     return new Promise((resolve, reject) => {
         setTimeout(() => {
             console.log(color)
             resolve()
         }, delay)
     })
 }
 function step() {
     print(3 * 1000, 'red')
     .then(() => print(2 * 1000, 'green'))
     .then(() => print(2 * 1000, 'yellow'))
     .then(step)
 }

image.png

async / await

更简单了

 function print(delay, color) {
     return new Promise((resolve) => {
         setTimeout(() => {
             console.log(color)
             resolve()
         }, delay)
     })
 }
 async function step() {
     await print(3 * 1000, 'red')
     await print(1 * 1000, 'green')
     await print(2 * 1000, 'yellow')
     return step()
 }

image.png

5、Promise封装一个AJAX

 const xhr = new XMLHttpRequest();
 const baseURL = 'baseURL'
 /**
  * Promise浅浅封装一下
  * @param method 
  * @param url 
  * @returns 
  */
 function request(method='GET', url){
     return new Promise((resolve, reject) => {
         xhr.onreadystatechange = () => {
             if (xhr.readyState === 4) {
                 if (xhr.status === 200) {
                     resolve(JSON.parse(xhr.responseText))
                 } else {
                     reject(xhr.status)
                 }
             }
         }
         let completeURL = baseURL + url
         xhr.open(method, completeURL, true)
         xhr.send()
     })
 }
 ​
 export default request

6、使用setTimeout实现setInterval

 function mySetInterval(fn, delay) {
     const timer = { flag: true }
     // 定时器是每隔一段时间执行一次
     function interval() {
         if(timer.flag) {
             fn && fn()
             // 递归一下就行了
             setTimeout(interval, delay)
         }
     }
     setTimeout(interval, delay)
     return timer
 }

image.png