前端基础面试题

1-1. var let const 区别

  • var 是es5语法,有变量提升
  • let const是es6语法, 有块级作用域
  • var let 是变量,可修改;cosnt是常量,不可修改

2-1. typeof返回哪些类型

  • 值类型:undefined string number boolean symbol
  • 引用类型: object,注意:typeof null === 'object'
  • function
  1. 列举强制类型转换和隐式类型转换
  • 强制:parseInt parseFloat toString等
  • 隐式:if、逻辑运算、==、 +拼接字符串

2-2. 手写深度比较,模拟lodash isEqual

const obj1 = {
  a:100,
  b: {x:100,y:200}
}
const obj2 = {
  a:100,
  b: {x:100,y:200}
}

// 判断是否是对象、数组
function isObject(obj){
  return typeof obj === "object" && obj !== null  
}

function isEqual(obj1,obj2){
  if(!isObject(obj1)||!isObject(obj2)){
    // 值类型 (参加equal的一般不是函数)
    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的value  -- 递归
    const res = isEqual(obj1[key],obj2[key])
    if(!res){
      return false
    }
  }
  // 3. 全相等
  return true
}
console.log(isEqual(obj1,obj2)) // true
  1. split()和join() 区别
  • '1-2-3'.split('-') // [1,2,3]
  • [1,2,3].join('-') // 1-2-3

2-3. 数组的pop push unshift shift 区别

pop push unshift shift
功能 删除最后一个 在最后加一个 在开头加一个 删除开头一个
返回值 最后一个数 数组长度 数组长度 开头的一个数
  • 是否会对原数组造成影响

// 纯函数: 1. 不改变原数组(没有副作用); 2. 返回一个数组
const arr = [10,20,30,40]

// concat
const arr1=arr.concat([50,60,70])
// map
const arr2 = arr.map(num=>num*10)
//filter
const arr3 = arr.filter(num=>num>25)
// slice 类似一个深拷贝
const arr4 = arr.slice()

// 非纯函数
// push pop shift unshift
// forEach
// some every
// reduce

3-1. 数组slice(切片)和splice(剪接)区别:

  • 参数和返回值
  • 是否是纯函数,slice是纯函数
slice splice
}返回值
是否是纯函数

3-2. [10,20,30].map(parseInt)

返回[10,NaN,NaN]
等同写法:

[10,20,30].map((num,index)=>parseInt(num,index))
// parseInt 按照index进制格式化num

3-3. ajax请求get和post区别

  • get用于查询,post用于提交
  • get参数拼接在url上,post参数在请求体内,且更大
  • 安全性:post更易于防止CSRF

4-1. 函数call和apply的区别

  • 第二个参数不同
  • fn.call(this,p1,p2,p3...)
  • fn.apply(this,[p1,p2,p3...])

4-2. 事件代理(委托)是什么

const p1 = document.getElementById('p1')
const body = document.body
bindEvent(p1,'click',e=>{
  e.stopPropagation() // 注释掉这一行,可以体会到事件冒泡
  alert('激活')
})

bindEvent(body,'click',e=>{
  alert('取消')
})

4-3. 闭包是什么?有何特性?有何影响?

image.png
image.png
image.png
  • 影响:常量常驻内存,得不到释放。闭包不可乱用

5-1 如何阻止事件冒泡和默认行为?

  • event.stopPropagation()
  • event.preventDefault()

5-2 查找、添加、删除、移动dom节点的方法?

  • 查找:document。getElementById/TagName/ClassName/ querySelectorAll(xx)
  • 新建: document.createElement('xx ')
  • 插入: div.appendChild(xx)
  • 移动:先获取,再插入
  • 删除子元素: parentDiv.removeChild(xx)

5-3 如何减少dom操作

  • 缓存DOM查询结果
  • 多次Dom操作,合并到一次插入
const list = document.getElementById('list')

// 创建一个文档片段,此时还没有插入到DOM结构中
const frag = document.createDocumentFragment()

for(let i=0; i<20; i++){
  const li = document.createElement('li')
  li.innerHTML = "item ${i}"
  // 先插入文档片段中
  frag.appendChild(li)
}
// 都完成之后,统一插入到 DOM结构中
list.appendChild(frag)

6-1: 解释jsonp原理,为何不是真正的ajax

  • 浏览器的同源策略(服务端没有同源策略)和跨域
  • img、script、标签可以绕过跨域
  • 不走xmlhttp 接口,需要服务端支持
<script>
  window.abc = function(data){
    console.log(data)
  }
</script>

// 把function abc作为回调函数传给后端
<script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script>

// 后端 jsonp.js 处理:
abc{
  {name:'jsonp666'}
}

6-2. document load 和 ready 的区别

window.addEventListener('load',function(){
  // 页面的全部资源加载完才会执行,包括图片、视频等
})

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

6-3. == 和 === 的区别

  • ==会尝试进行类型转换
  • === 严格相等
  • 只有判断==null或undefined 时才用==

7-1 函数声明和函数表达式的区别

  • 函数声明 function fn(){...}
  • 函数表达式 const fn = function(){...}
  • 函数声明会在代码执行前预加载(类似变量提升),函数表达式不会

7-2 new Object() 和 Object.create() 区别

  • {}等同于new Object(), 原型Object.prototype
  • Object.create(null),没有原型
  • Object.create({...}), 将原型对象指向{...}
  • obj1 === obj2时,两个对象的地址是一样的

7-3 this传统场景题

  • this的值在执行时决定

8.1 作用域和自由变量1

let a = 100;
function test(){
  alert(a)
  a = 10 
  alert(a)
}

8.2 判断字符串以字母开头,后面字母数字下划线,长度6-30

  • const reg = /^[a-zA-Z]\w{5,29}$/
  • ^ xx开头
  • \w: 字母、数字、下划线
  • $: 结尾
  • \d:数字
    • : 一次到多次
  • 用户名:/^[a-zA-Z\w{5,17}]/
  • 简单ip地址: /\d+.\d+.\d+/
  • 日期(2019.12.1):/^\d{4}-\d{1,2}- \d{1,2}$/

9-1 手写trim并保证浏览器兼容性

String.prototype.trim = function(){
  // 直接放到原型上有点暴力,其实应该先判断一下,原型上是否有,没有再整
  // 通过正则解决兼容性问题
  return this.replace(/^\s+/,'').replace(/\s+$/,'')
}

9-2 获取最大值

function max(){
  const nums = Array.prototype.slice.call(arguments); // 变为数组
  let max = 0;
  nums.forEach(n=>{
    if(n>max){
      max = n
    }
  })
  return max;
}

Math.max([1,2,3,4,5])

9-3 如何用js实现继承

  • class
  • prototype

10-1 如何捕获js中的异常?

// 高风险的地方
try{
  // todo
}catch(ex){
  console.error(ex) // 手动捕获 catch
}finally{
  // todo
}

// 自动捕获
window.onerror = function(message,source,lineNum,colNum,error){
  //1. 对跨域的js,如 cdn,不会有详细的报错信息
  // 2. 对于压缩的js,还要配合sourceMap反查到未压缩代码的行、列

10-2 什么是JSON

  • JSON是一种数据格式,本质是一段字符串
  • json格式和js对象结构一致(键值对),对js语言更友好,但是json中只能用双引号
  • window.JSON是一个全局对象:JSON.stringify JSON.parse

10-3 获取当前页面的URL参数

  1. 传统方式:location.search
function query(name){
  const search = location.search.substr(1) // substr(1)是为了取消?,类似array.slice()
  // search:‘a=10&b=20&c=30’
  const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`,'i')
  const res = search.match(reg)
  if(res === null){
    return null
  }
  retrun res[2]
}
  1. 新api:URLSearchParams,兼容性需要做处理
function query(name){
  cosnt search = location.search;
  const p = new URLSearchParams(search);
  return p.get(name)
}

11-1 将url参数解析为js对象

// 方法1
function queryToObj(){
  const res = {}
  const search = location.search.substr(1)
  search.split('&').forEach(paramStr=>{
    const arr = paramStr.split('=')
    cosnt key = arr[0]
    const val = arr[1]
    res[key] = val
  })
  return res;
}

// 方法2
function queryToObj(){
  const res = {  }
  const pList = new URLSearchParams(location.search)
  plist.forEach((val,key)=>{
    res[key] = val
  })
  return res;
}

11-2 手写数组flatten,考虑多层级

// arr = [1,[2,3,[4,5,[6.7],8],9]
function flat(arr){
// 验证arr中,是否有深层数组
const isDeep = arr.some(item=>item instanceof Array)
is(!isDeep){
return arr // 平的,直接返回
}
const res = Array.prototype.concat.apply([],arr)
return flat(res) // 递归
}
const res = flat(arr)

// 不考虑层级,可以用concat(只能拍平一层)
arr2 = [1,2,[3,4],5]
Array.prototype.concat.apply([],arr2)
Array.prototype.concat.call([],...arr2)
[].concat(...arr2)

11-3 数组去重

  1. 传统方法
function unique(arr){
  const res = []
  arr.forEach(item=>{
    if(res.indexOf(item)<0){
      res.push(item)
    }
  })
  return res
}
  1. 使用 es6 Set(无序,不允许有重复),不需要遍历,效率高于传统方式
function unique(arr){
  const res = new Set(arr)
  return [...res]
}

12-1 手写深拷贝

注意:Object.assign 不是深拷贝,且有副作用
[图片上传失败...(image-7a8477-1615010278126)]

12-2 RAF requestAnimationFrame

  • 想要动画流畅,更新频率要60fps/s,即16.66ms更新一次视图
  • setTimeout 要手动控制频率,而RAF浏览器会自动控制(根据屏幕刷新率)
  • 后天标签或隐藏iframe中,RAF会暂停,而setTimeout依然会执行

[图片上传失败...(image-32c1af-1615010278126)]

let curWidth = 100;
const maxWidth = 640;
function animate(){
  curWidth = curWidth + 3;
  $div1.css('width',curWidth)
  if(curWidth < maxWidth){
    window.requestAnimationFrame(animate)
  }
}
animate()

12-3 性能优化

  • 原则:多使用内存、缓存,减少计算、减少网络请求
  • 方向:加载页面,页面渲染,页面操作流畅度
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容