这是美团前端外包岗的面试,分三次。一次是机试选择题,两次是线上笔试编程题。题目不算难。这里就写我能记起来的
一、箭头函数特性
1. 箭头函数不能被用作构造函数,也无法使用new关键字。箭头函数不能在其主体中使用yield,也不能作为生成器函数创建。
2. 箭头函数中没有arguments,收集入参需要使用剩余参数和解构 ...argu
3. 箭头函数没有独立的this指向。在普通函数中,this通常指向调用方。但箭头函数中的this是在作用域上下文中被确定下来。由此,所有涉及到this指向的,例如call,bind,apply可以使用但不会改变this指向。
4. 但在class中普通函数和箭头函数都指向实例
5. 我更愿意把箭头函数看作一个特殊的对象,但是有函数执行的功能。这样对于判断箭头函数的this可能有帮助
6. 关于箭头函数可以看developer.mozilla.org/zh-CN/docs/… 练习this的指向,可以看juejin.cn/post/684490…
二、ES6中的Set
1. Set是为了解决集合问题。其中的值无论是基本类型还是引用类型都是唯一的。
2. 由于是唯一的,对于引用类型要注意new Set().add({}).add({}) 相当于往Set里面添加了两个值,const a = {} new Set().add(a).add(a) 就是一个值
3. 最常用的就是用Set过滤重复的值。更多Set的方法属性可以看 developer.mozilla.org/zh-CN/docs/…
三、git中如果要把不包括新增的文件推入暂存区要使用什么命令
1. git add -u 更多操作详见blog.csdn.net/wzt001005/a…
四、vue中父子组件生命周期
1. vue中生命周期函数包括 beforeCreate created beforeMount mounted beforeupdate updated beforedestory destoryed
2. 加上父子组件其实也有一套理解方法,vue是一个基于模板的框架,所以它会先解析父组件,当在父组件内发现子组件时,就会触发子组件的解析。子组件执行完后,继续执行父组件剩余内容。依次接力,直到整个组件解析完成。所以对于挂载,是父组件执行到beforemount,开始子组件。子组件mounted成功后,父组件mounted随后触发
3.具体可看 juejin.cn/post/719992…
五、react中setState是异步,它的更新时机
1. react中的setState是异步批量更新,它会将所有需要更新的任务收集起来统一更新渲染
2. setState也可以传入一个函数,在函数内可以获取最新的值
3. 无论是vue还是react,其更新渲染在表现形式上类似于一个微任务。比如在一个点击事件上,要先把其中的同步代码执行完成后,再去更新state和渲染
4. 更多信息可以看juejin.cn/post/726853…
六、react中的fiber
1. 在之前,react的核心是虚拟DOM,在一次更新中把所有的要变动的地方都渲染在页面上,是一个不能暂停的操作。在某些情况下会让用户的操作卡顿。
2. 所以在react18中引入了fiber,核心概念一是要给更新任务设置优先级,二是时间切片,任务是在浏览器绘制一帧画面的剩余时间内执行。为此react重新设计了组件数据结构,类似于链表,每个组件都有一个指向前一个节点和下一个节点的指针。这样在执行更新任务时可以随时中断和重启。
3. 更多信息可看juejin.cn/post/684490…
七、react生命周期
1. 在现在,react是在淡化组件的生命周期这个概念,更强调数据的单向流动,由数据去更新视图。在之前的类组件中有生命周期函数,常见的就是constructor,render componentDidMount等
2. 具体可以看 juejin.cn/post/709613…
八、vue更新机制
1. vue是基于模板的框架,模板会被解析成渲染函数,渲染函数生成虚拟dom,最终依据虚拟dom生成最终的网页。在这期间,vue会追踪需要的响应式依赖
2. vue3采用proxy创建响应式对象,其中有get和set方法,可以在对象属性发生变化时执行对应的副作用函数
3. 详情见vue官网 cn.vuejs.org/guide/extra…
九、虚拟DOM
1. vue和react都把组件转为虚拟dom,一种保存了节点信息的数据结构,具体可看juejin.cn/post/712014…
2. react的diff算法,react使用diff算法来比较更新,这样实现最小改动,一般是同层级比较,同类型比较和key值比较 具体看 juejin.cn/post/740737…
十、数组中可以中断的遍历方法
1. 对于forEach,可以使用try throw catch的方法,抛出一个错误来终止遍历
2. for循环和while可以用break和return的方法终止遍历
3. find,findIndex,indexOf,some,every方法会在找到第一个符合条件的值就返回
十一、如果有一个组件发起了两次请求,结果都是一样的,怎么避免他重复更新组件
1. 避免组件更新就是让组件内的state或者props不发生变化,一是用setState() 传入函数去判断,要不就是React.memo。返回true代表新旧props相同,组件不变化,否则返回false。
十二、防抖和节流
1. 防抖的本质是用定时器延迟执行,再判断如果已经有定时器了就取消再重新创建。简单的实现方法
const debounce = (fn) => { let timer return function () { if (timer) clearTimeout(timer) timer = setTimeout(() => { fn() }, 300) } }
2. 节流就像是把一个很密的梳子变得稀疏,是一段时间内只执行一次。本质是执行完函数后用定时器创建标识,标识结束后再执行
const tro = (fn)=>{ let timer return function () { if (timer) return fn() timer = setTimeout(() => { timer = null }, 1000) }
十三、多维数组展开
1. 实现 flattenByDepth 函数。这个函数会按照指定的深度展开嵌套数组, 可以使用递归或迭代方式 需要考虑 depth 为 0 或负数的情况 注意不要修改原数组。简单实现
const flat = (arr,n)=>{ if(n<=0) return [...arrr] let res = [] arr.forEach(item=>{ if(Array.isArray(item)){ res = [...res,...flat(item,n-1)] }else{ res.push(item) } }) return res }
另一种实现
const flat = (arr,n)=>{ if(n<=0) return arr return arr.reduce((pre,cur)=>{ if(Array.isArray(cur)){ return pre.concat(flat2(cur,n-1)) }else{ return pre.concat(cur) } },[]) }
十四、宏任务微任务执行顺序
1. 题目
console.log('start'); setTimeout(() => { console.log('setTimeout') },0); new Promise((resolve) => {console.log('promise') resolve() }).then(() => {console.log('then1')}).then(() => {console.log('then2') }); console.log('end')
最终顺序是 start promise end then1 then2 setTimeout
需要注意的是promise的then会链式执行,可以理解为,执行完第一个then函数后又往微任务队列里插入一条,为了清空队列就执行下一个微任务,队列完全为空后再执行宏任务
2. 更多练习可以看 juejin.cn/post/684490… https://juejin.cn/post/6844903638238756878
十五、变量提升
1. 题目
showName() var showName = function() { console.log(2) } showName() function showName() { console.log(1) } showName()
最终打印结果是 1 2 2
原因是函数定义提升至最前面 function showName(){} ,之后是var showName 然后代码从上到下执行showName(),之后showName = function(){} 最后执行两个showName()
var定义的变量会在预编译时提升至顶层,设置为undefined。function定义的函数也会被提升至顶层,比var定义的变量更上一层。
2. 具体可看 juejin.cn/post/684490…
十六、原型和原型链
1. 题目
function Person(){} Object.prototype.a = function(){} Function.prototype.b = function(){} let f = new Person() console.log(f.a,f.b)
打印结果是function(){} undefined
原因是实例会从原型链上找对应的属性,需要注意的是Function.prototype不在实例的原型链上
十七、找到数组中两个数加起来符合条件的一组数
1. 答案:
const fn = (arr, n) => { let res = [] for (let i = 0; i < arr.length; i++) { const target = n - arr[i] const index = arr.indexOf(target) if (index !== -1 && index !== i) { return [target, arr[i]] } } return res.length ? res : -1 }
console.log(fn([1, 3, 5, 7, 12], 13)) 打印[12,1]
console.log(fn([1, 3, 5, 7, 12], 24)) 打印-1
这个解法有问题,就是循环太多次了。数据量大时会很耗时。