笔记

182 阅读2分钟

列举强制类型转换

  • 强制:parseInt、parseFloat、toString等
  • 隐式:if、逻辑运算(>=等)、==、+拼接字符串

手写深度比较,模拟 lodash.isEqual (是否想等)

function isObject(obj) {
  return typeof obj === 'object' && obj !== null
}

function isEqual(obj1, obj2) {
  if (!isObject(obj1) || !isObject(obj2)) {
    return obj1 === obj2
  }
  // 如果传入的都是同一个对象
  if (obj1 === obj2) {
    return true
  }
  const objKeys1 = Object.keys(obj1)
  const objKeys2 = Object.keys(obj2)
  if (objKeys1.length !== objKeys2.length) {
    return false
  }

  for (let key in obj1) {
    const res = isEqual(obj1[key], obj2[key])
    if (!res) {
      return false
    }
  }
  
  return true
}

Ps:结束循环

  • for...in和for...of 用break、continue可以结束循环,如果 for...in和for...of 在函数内可以用return结束函数
  • forEach 不管在不在函数内 return 相当于 for 循环的 continue

列举纯函数API

  • 纯函数:1、不改变原数组(没有副作用);2、返回一个数组

    • concat、map、filter、slice
  • 非纯函数

    • push、pop、shift、unshift、forEach、some、every、reduce、splice

[10, 20, 30].map(parseInt)

打印[10,NaN,NaN]

分解一下

[10,20,30].map((item,index) => {
  return parseInt(item, index)
})

其中 parseInt(string, radix)

  • 第一个参数是要要被解析的字符串

  • 第二个参数可选。表示要解析的数字的基数。

    • 该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。

    new Object() 和 Object.create() 的区别

    • {} 等同于 new Object(), 原型 Object.prototype
    • Object.create(null) 没有原型
    • Object.create({...}) 可指定原型

    手写 trim 方法

    String.prototype.trim = function(){
      return this.replace(/^\s+/,'').replace(/\s+$/,'')
    }
    

获取多个数字中的最大值

function max(){
  const nums = [].slice.call(arguments)
  let max = 0
  for(let item of nums){
    max = item >= max ? item : max
  }
  return max
}

或者

Math.max(10, 20, 30, 40)
//还有Math.min()

如何捕获 JS 中的异常

  • 手动捕获
try{

}catch(ex){

}finally{}
  • 自动捕获
window.onerror = function(message, source, lineNum, cloNum, error){
  //第一,对跨域的 js,如 CDN 的,不会有详细的报错信息
  //第二,对于压缩的 js,需要配合 sourceMap 反查到未压缩代码的行、列
}

什么是 JSON

  • json 是一种数据结构,本质是一段字符串
  • json 格式和 js 对象结构一致, 对 js 语言更友好

解析 URL 参数

  • 传统方式: location.search
  • 新 API: URLSearchParams
//假设 URL 是 http://localhost:8080?a=10
function query(name){
  const search = location.search
  const p = new URLSearchParams(search)
  return p.get(name)
}
query('a')  //打印 10

手写数组 flatern (数组扁平化)

// 手写
function flatern(arr, result = []) {
  if (!(arr instanceof Array)) {
    result.push(arr)
    return result
  }
  for (let item of arr) {
    result = flatern(item, result)
  }
  return result
}

更简单的方法(深度超过1层不能拍平 [1,2,3,[4,5,[6,7]]])

Array.prototype.concat.apply([],arr)
[].concat(...arr)

简单方法的拍平所有深度的方法

function flatern(arr){
  let isDeep = arr.some(item => item instanceof Array)
  if(!isDeep){
   return arr
  }
  const res = [].concat(...arr)
  return flatern(res)
}

数组去重

  • 传统方式 双层 for 循环
  • es6 Set
function unique(arr){
  let set = new Set(arr)
  return Array.from(set)
  // 或者用 return [...set] 也可以
}
  • 单层循环
function unique(arr){
  let res = []
  for(let item of arr){
    if(res.indexOf(item) < 0){
      res.push(item)
    }
  }
}

总结:对于性能来说,用 Set 更好,原因是单层循环中 indexOf() 其实也算一种遍历

深拷贝

function deepClone(obj = {}) {
  if (typeof obj !== 'object' || obj == null) return obj
  let result = obj instanceof Array ? [] : {}
  for (let key in obj) {
    // baozhengkey不是原型属性
    if (obj.hasOwnProperty(key)) {
      result[key] = deepClone(obj[key])
    }
  }
}    
  • 关于 obj == null ------>️ obj === null || boj === undefined

  • JSON.parse(JSON.stringify()) 这个也是深拷贝,也可以拷贝方法

const obj2 = JSON.parse(JSON.stringify(obj1))
  • 数组的 slice 方法,当没有参数时是深拷贝数组 const deepCloneArr = arr.slice()

  • es6的解构赋值,只能深拷贝第一层,后面的层数是浅拷贝

const obj2 = {...obj1}
  • Object.assign 同 es6 的解构赋值一样,只拷贝第一层,后面的层数是浅拷贝

介绍一下 RAF(requestAnimationFrame)

  • 要想动画流畅,更新频率要大于 60帧/s,即小于 16.67ms 更新一次视图
  • setTimeout 控制动画时,要手动控制频率,而 RAF 浏览器会自动控制
  • 当后台标签或隐藏 iframe 中,RAF会暂停,而 setTimeout 依然执行
    • 切换窗口等操作时 RAF 会暂停

setTimeout

// 3s 内把宽度从 100px变成 645px,即增加 540px
// 60帧/s  3s -> 180帧  每帧变化 540/180 = 3px
let oDiv = document.querySelector('div')
let curWidth = 100
let maxWidth = 640
function animate() {
  curWidth += 3
  oDiv.style.width = `${curWidth}px`
  if (curWidth < maxWidth) {
    setTimeout(animate, 16.7)  //自己控制时间
  }
}
animate()

RAF

// 3s 内把宽度从 100px变成 645px,即增加 540px
// 60帧/s  3s -> 180帧  每帧变化 540/180 = 3px
let oDiv = document.querySelector('div')
let curWidth = 100
let maxWidth = 640

function animate() {
  curWidth += 3
  oDiv.style.width = `${curWidth}px`
  if (curWidth < maxWidth) {
    window.requestAnimationFrame(animate)
  }
}
animate()