给大家分享一篇面试相关文章,端面希望大家在 2022 年,试题摸鱼时间越来越多,及答薪资越涨越快! 阿里面试题1: 事件循环机制,及答event-loop 。端面包含三部分:调用栈、试题消息队列、及答微任务队列。端面 事件循环开始的试题时候,会从全局一行一行的及答执行代码,遇到函数调用的端面时候,就会压入调用栈中,试题当函数执行完成之后,及答弹出调用栈。 如果遇到 fetch、setInterval、setTimeout 异步操作时,函数调用压入调用栈时,异步执行内容会被加入消息队列中,消息队列中的内容会等到调用栈清空之后才会执行。 遇到 promise、async、await 异步操作时,执行内容会被加入微任务队列中,会在调用栈清空之后立即执行。 调用栈加入的微任务队列会立即执行。源码下载 微任务队列中内容优先执行,所以比消息队列中的内容执行得早。 了解这些知识后,再试一下最前面的那道面试题,应该就没什么问题了。 阿里面试题2: 作用域通俗地讲,就是指一个变量的作用范围。下面分别介绍下全局作用域和函数作用域的概念。 全局作用域 函数作用域(局部) 讲这些概念看完,发现还不会做上边的面试题,接下来就学习学习作用域的预编译,看看函数执行的时候都干了些啥? 函数在被调用的时候会先进行预编译: 全局作用域预编译: 函数作用域预编译: 了解预编译过程之后,我们将上面的面试题进行解析,分析下运行结果是怎么来的? fn 函数调用的时候,先进行预编译, 第一阶段:生成一个 AO 对象 第二阶段:找到形参和实参,作为 AO 对象的属性名,云南idc服务商值为 udefined 。 第三阶段:实参和形参相统一,之后,AO对象改变为: 第四阶段:找到函数声明,将值赋给变量,AO改变为: 这下结合函数的预编译过程以及函数作用域概念,再尝试一下面试题,简单了吗? 这是一个非常常见的实际应用,我们是想要点击元素然后操作对应的元素,但是点击之后发现打印出来的是 undefined 。我们应该能想到 i 变成了 liArr.length ,所以找不到对应元素,这个问题该如何解决呢? 说闭包时,必须介绍作用域。 上面介绍全局作用域和函数作用域,js内部变量的访问是由内向外的,内部可以访问到外部的变量,但是外部无法访问函数内的变量,如果我们在外部访问函数内的变量就需要使用闭包。 闭包就是函数嵌套函数,通过函数内的函数访问变量的规则,实现外部访问函数内的变量。 闭包的特点: 那么上述实例该如何使用闭包解决该问题呢? 闭包优点: 防抖和节流就是闭包的经典应用。 在实际应用中,常见的就是窗口的 resize、输入框搜索内容、scroll 等操作,如果这些操作触发频率太高,就会加重浏览器的负担,同时用户体验也较差。该如何优化该操作呢? 当持续触发事件,一定时间内没有再触发事件,事件处理函数才会执行一次,如果在设定的时间到来之前又触发了事件,就会重新计时。 实例4:我们想要制作一个输入框搜索,计划输入完成后两秒再执行,打印出输入的值。 实际运行结果:我们发现输入之后,延时两秒之后打印出结果。 并非我们想要的结果,这是什么原因呢? 因为函数每次重新调用的时候 timer 会重新创建,调用完成之后就会被销毁,所以每次重新调用函数的时候,clearTimeout 内的 timer 都是 undefined 。所以我们需要把 timer 始终保持在内存当中,所以就需要使用闭包。 使用闭包修改上述实例4: 防抖函数常见的实际应用:使用 echart 的时候,浏览器 resize 时,需要重新绘制图表大小,还有典型的输入框搜索应用。 当持续触发事件的时候,保证一段时间内只调用一次事件处理函数,一段时间内,只允许做一件事情。 防抖和节流主要是用来限制触发频率较高的事件,再不影响效果的前提条件下,降低事件触发频率,减小浏览器或服务器的压力,提升用户体验效果。 这是一个非常常见的面试题,你知道几种方式呢? new Set 返回的数据不是数组,所以使用 Aray.from 方法将类数组转为真正的数组,或把 ...new Set(arr) 放入数组中。 arr.indexOf(item) 返回 item 元素在 arr 数组中第一次出现所在位置的下标。 array.indexOf(item,start) start 表示开始检索的位置。1、端面事件循环机制
2、你对作用域的认识有多少?
3、为什么会有闭包?它解决了什么问题?
实例3:
var liArr = document.getElementsByTagName(li) for(var i=0;i<liArr.length;i++){ liArr[i].onclick = function(){ console.log(liArr[i]) } } 实例3:闭包解决问题
var liArr = document.getElementsByTagName(li) for(var i=0;i<liArr.length;i++){ (function(i){ liArr[i].onclick = function(){ console.log(点击元素,liArr[i]) } })(i) } 4、防抖和节流,你了解多少?
防抖函数是什么呢?
节流函数是什么?
实例5:滚动条实现一段时间内执行一次处理,执行回调。
var throttle = function(func, delay) { var timer = null; return function() { var context = this; var args = arguments; if (!timer) { timer = setTimeout(function() { func.apply(context, args); timer = null; }, delay); } } } function handle() { console.log(执行回调); } window.addEventListener(scroll, throttle(handle, 1000)); 5、数组去重有几种方法?
方法1: Set 方法
return Array.from(new Set(arr)) // 或 return [...new Set(arr)] 方法2:使用两次循环
for(var i=0,len=arr.length;i<len;i++){ for(var j=i+1,len=arr.length;j<len;j++){ if( arr[i]===arr[j] ){ arr.splice(i,1) j--; len-- } } } return arr 方法3:indexOf 实现
方法4:includes 实现
let arr1 = [] for(var i=0;i<arr.length;i++){ if( !arr1.includes(arr[i]) ){ arr1.push(arr[i]) } } return arr1 方法5:filter 实现