头条

格式化发布时间

类似于微信朋友圈里面的发布时间,其中发布时间有几种特殊情况:

  • 小于 1 min,则显示 刚刚
  • 小于 1 h,则显示 x 分钟前
  • 小于 1 天,则显示 x 小时前
  • 小于 1 个星期,则显示 x 天前
  • 否则显示具体时间。
    declare function i18n(s: string): string
    
    function format(date: number): string {
      const MIN = 60 * 1000
    	const HOUR = 60 * MIN
      const DAY = 24 * HOUR
      const WEEK = 7 * DAY
      
      if(date < MIN) return i18n('刚刚')
      if(date < HOUR) return Math.floor(date / MIN) + i18n('分钟前')
      if(date < DAY) return Math.floor(date / HOUR) + i18n('小时前')
      if(date < WEEK) return Math.floor(date / DAY) + i18n('天前')
      return new Date(Date.now() - date).toLocaleString()
    }
    
    console.log(format(60 * 1000 - 1)); // 59 秒 999
    console.log(format(60 * 1000)); // 1 分
    
    console.log(format(60 * 1000 * 59 + 59 * 1000 + 999)); // 59 分 59 秒 999
    console.log(format(60 * 1000 * 60)); // 1 小时
    
    console.log(format(60 * 1000 * 60 * 23 + 60 * 1000 * 59 + 59 * 1000 + 999)); // 23 小时 59 分 59 秒 999
    console.log(format(60 * 1000 * 60 * 24)); // 1 天
    
    console.log(format(60 * 1000 * 60 * 24 * 6)); // 6 天
    console.log(format(60 * 1000 * 60 * 24 * 7)); // 7 天
    
    console.log(format(1554111847534)); // 发布时的时间戳

格式化数字

为数字添加都好,使用正则和非正则实现

    // 方法1:使用内置api
    // 缺点:小数部分会保留三位小数
    var num = 12345
    console.log(num.toLocaleString()) // '12,345'
    num = 12345.6789
    console.log(num.toLocaleString()) // '12,345.679'
    
    // 方法2:使用数组
    function format(num: number): string {
      if(typeof num !== 'number') return num
      
      const [first, last] = `${num}`.split('.')
      const len = first.length
    	const temp = first.split('').reverse().reduce((pre, cur, index) => {
        if((i + 1) % 3 === 0 && i !== flen - 1) pre.push(cur, ',')
        else pre.push(cur)
      }, []).reverse().join('')
      
      return last ? `${temp}.${last}` : temp
    }

一面

实现 js ES5 数据类型的深拷贝

    function deepClone<D>(data: D): D {
      const isObj = (v: D) => Object.prototype.toString.call(v).slice(8, -1) === 'Object'
      
      function _deepClone(val: any): D {
        if(Array.isArray(val)) {
    			const source = val as any[]
          return source.reduce((res, item) => {
            res.push(_deepClone(item))
            return res
          }, [])
        }
        
        if(isObj(val)) {
          const source = val as object
          return Object.keys(source).reduce((res, key) => {
            res[key] = _deepClone(source[key])
            return res
          }, {})
        }
        
        return val
      }
      
      return _deepClone(data)
    }

二面

实现简易 MVVM

    interface Handlers {
        get(val): void
        set(newVal, oldVal): void
    }
    
    class Observer<T extends object = {}> {
        private data: T
    
        constructor(data: T) {
            this.data = data
            this.proxyData()
        }
    
        private proxyData(): void {
            const keys = Object.keys(this.data)
            for (const key of keys) {
                Object.defineProperty(this, key, {
                    get: () => {
                        return this.data[key]
                    },
                    set: (val) => {
                        this.data[key] = val
                    }
                })
            }
        }
    
        observe(key: keyof T, handlers: Handlers): void {
            const value = this.data[key]
    
            Object.defineProperty(this.data, key, {
                get: () => {
                    handlers.get(value)
                    return value
                },
                set: (val) => {
                    if (val === value) return
                    handlers.set(val, value)
                    this.data[key] = val
                }
            })
        }
    }

三面

顺序发送4个请求a,b,c,d,要求按顺序输出

    function getData(urls: string) {
      return new Promise<object[]>((resolve, reject) => {
        const len = urls.length
        const res: object[] = []
        
        urls.forEach((url, index) => {
          fetch(url)
            .then(res => res.json())
          	.then(data => {
            	res[index] = { data, printed: false }
            	let flag = true // 用来判断所有请求是否都已经跑完
              for(let i = 0; i < len && flag; i++) {
                if(res[i]) { 
                  if(!res[i].printed) { // 循环内,所以去掉已经打印的
                    console.log(res[i].data)
                    res[i].printed = true
                    i === len - 1 && resolve(res.map(v => v.data)) // 当最后一个打印完成后,结束promise
                  }
                } else {
                  flag = false
                }
              }
          	}, reject)
        })
      })
    }
Last Updated:
Contributors: leeguooooo