JavaScript 常见面试题分析(四)

2024-03-19 11:52:58 浏览数 (1)

强制类型转换和隐式类型转换

强制:parseIntparseFloattoString

隐式:if、逻辑运算、==、 拼接字符串

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

代码语言:javascript复制
// Object.create(null) // 没有原型
// Object.create({}) // 可指定原型

const obj1 = {
  a: 1,
  b: 2
}
const obj2 = new Object(obj1)
const obj3 = Object.create(obj1)

obj2 === obj1 // true
obj3.__proto__ === obj1 // true

描述事件冒泡的流程

基于 DOM 树形结构,事件会顺着触发元素往上冒泡,应用场景:代理

xhr.status

2xx - 表示成功处理信息,如 200 - 成功处理请求,204 - 成功处理请求但没有返回内容

3xx - 需要重定向,浏览器直接跳转,如 301 - 永久重定向,302 - 临时重定向,304 - 网页未修改,不会返回内容

4xx - 客户端请求错误,如 403 - 拒绝请求, 404 - 找不到请求网页

5xx - 服务端错误

Promise加载图片

代码语言:javascript复制
function loadImg(src) {
  return new Promise(
    (resolve, reject) => {
      const img = document.createElement('img')
      img.onload = () => {
        resolve(img)
      }
      img.onerror = () => {
        const err = new Error(`图片加载失败 ${src}`)
        reject(err)
      }
      img.src = src
    }
  )
}

loadImg(url1).then(img1 => {
  console.log(img1.width)
  return img1 // 普通对象
}).then(img1 => {
  console.log(img1.height)
  return loadImg(url2) // promise 实例
}).then(img2 => {
  console.log(img2.width)
  return img2
}).then(img2 => {
  console.log(img2.height)
}).catch(ex => console.error(ex))

如何减少DOM操作

代码语言:javascript复制
const list = document.getElementById('list')

// 创建一个文档片段,此时还没有插入到DOM结构中
const frag = document.createDocumentFragment()
for (let i = 0; i < 20; i  ) {
  const li = document.createElement('li')
  li.innerHTML = `List item ${i}`
  // 先插入文档片段中
  frag.appendChild(li)
}

list.appendChild(frag)

split() 和 join() 的区别

代码语言:javascript复制
'1-2-3'.split('-') // [1, 2, 3]
[1, 2, 3].join('-') // '1-2-3'

函数 call 和 apply 的区别

代码语言:javascript复制
fn.call(this, p1, p2, p3)
fn.apply(this, arguments)

window.onload 和 DOMContentLoaded 的区别

代码语言:javascript复制
// 页面的全部资源加载完才会执行,包括图片、视频等
window.onload = function() {}
window.addEventListener('load', function() {})

// DOM 渲染完即可执行,此时图片、视频还可能没有加载完
document.addEventListener('DOMContentLoaded', function(){})
$(document).ready(function(){})

函数声明和函数表达式的区别

函数声明会在代码执行前预加载,而函数表达式不会

获取多个数字中的最大值

代码语言:javascript复制
function max() {
  const nums = Array.prototype.slice.call(arguments)
  let max = 0
  nums.forEach(n => {
    if(n > max) {
      max = n
    }
  })
  return max
}

// 方法2
Math.max(10, 30, 20, 40)

解析 URL 参数

代码语言:javascript复制
function query(name) {
    const search = location.search.substr(1) // 类似 array.slice(1)
    // search: 'a=10&b=20&c=30'
    const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i')
    const res = search.match(reg)
    if (res === null) {
        return null
    }
    return res[2]
}
query('d')

// URLSearchParams
function query(name) {
  const search = location.search
  const p = new URLSearchParams(search)
  return p.get(name)
}
console.log( query('b') )

手写字符串 trim 保证浏览器兼容性

代码语言:javascript复制
String.prototype.trim = function() {
  return this.replace(/^s /, '').replace(/s $/, '')
}

数组去重

代码语言:javascript复制
function unique(arr) {
  const res = []
  arr.forEach(item => {
    if (res.indexOf(item) < 0) {
      res.push(item)
    }
  })
  return res
}

// 方法2
Array.from(new Set(arr));

深度比较 isEqual

代码语言:javascript复制
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
  
  // 两个都是对象或数组,且不相等
  // 1. 先取出 obj1 和 obj2 的 keys ,比较个数
  const obj1Keys = Object.keys(obj1)
  const obj2Keys = Object.keys(obj2)
  if (obj1Keys.length !== obj2Keys.length) {
    return false
  }
  // 2. 以 obj1 为基准,和 obj2 依次递归比较
  for (let key in obj1) {
    // 比较当前 key 的 val —— 递归!!!
    const res = isEqual(obj1[key], obj2[key])
    if (!res) return false
  }
  // 3. 全相等
  return true
}

数组降维 flat

代码语言:javascript复制
function flat(arr) {
  // 验证 arr 中,还有没有深层数组 [1, 2, [3, 4]]
  const isDeep = arr.some(item => item instanceof Array)
  if (!isDeep) {
    return arr // 已经是 flatern [1, 2, 3, 4]
  }
  const res = Array.prototype.concat.apply([], arr)
  return flat(res) // 递归
}

单线程和异步

单线程:同一时间只能做一件事,两段 JS 不能同时执行

原因:避免 DOM 渲染的冲突,浏览器渲染 DOM,JS 可以修改 DOM,当 JS 执行的时候,浏览器 DOM 渲染会暂停

JS 实现异步的具体解决方案——Event-Loop 事件轮询

同步代码,直接执行;异步函数先放在异步队列中,待主进程的同步函数执行完毕,轮询执行异步队列的函数

代码语言:javascript复制
$.ajax({
  url: './data.json',
  succcess: function() {
    console.log('a')
  }
})

setTimeout(function(){
  console.log('b')
}, 1000)

setTimeout(function(){
  console.log('c')
})

console.log('d')

// 输出结果取决于success所用的时间

0 人点赞