1.关于防抖/节流题目要求很明确,要求最终输出“searchText1”,并且在500ms后输出“searchText7”,很明显就是关于同一个函数在短时间内重复调用,如何限制其调用频率的功能实现 。
1function throttle(action, threshold) { 2// TODO: 3} 45let timer = true; 6const triggerScroll = throttle((val) => { 7console.log(val); 8}, 300); 9 10triggerScroll("searchText1");11triggerScroll("searchText2");12triggerScroll("searchText3");13triggerScroll("searchText4");14triggerScroll("searchText5");15triggerScroll("searchText6");16 17setTimeout(() => {}, 500);18 19// 期望输出结果:20// searchText121// 500ms 后输出 searchText7首先,拿到题目后我们先运行一下,运行后报错,显示“triggerScroll is not a function”;由于题目中throttle函数没有返回值,所以triggerScroll接收到的throttle返回值为undefined,首先我们要在throttle函数中return一个函数,也就是throttle在调用时传进去的第一个参数 。
1function throttle(action, threshold) {2return action3}这时再运行,控制台打印“searchText1-6”;这时我们只需要把防抖的通用模板套进去就可以实现了,我这里用的防抖,其实使用节流函数也是可以实现的,原理相同,我这里就不展示了,完整代码如下:
1function throttle(action, threshold) { 2return action 3} 45let timer = true; 6const triggerScroll = throttle((val) => { 7if (timer) { 8timer = false; 9setTimeout(() => {10timer = true;11console.log(val);12}, 300)13} else {14return false;15}16}, 300);17 18triggerScroll("searchText1");19triggerScroll("searchText2");20triggerScroll("searchText3");21triggerScroll("searchText4");22triggerScroll("searchText5");23triggerScroll("searchText6");24 25setTimeout(() => {26triggerScroll("searchText7");27}, 500);另附上防抖和节流的通用模板:
//防抖let timeid = null;function debounce() {if (timeid) {clearTimeout(timeid);}timeid = setTimeout(() => {//这里写操作console.log(Math.random());}, 500);}window.onscroll = debounce;//窗口滚动事件防抖//节流let timeid = null;function debounce(func, wait = 0) {if (!timeid) {timeid = setTimeout(() => {console.log(Math.random());timeid = null;}, 500);}}window.onscroll = debounce; 2.js预编译以及运行流程最终输出结果为“1 1 2 0” 。这一题也会涉及到闭包,作用域等知识点 。
1 var i = 0; 2 function fn() { 3i = 1; 4console.log(i); 5var i; 6return function () { 7console.log(i); 8i += 1; 9}10 }11 12 var fun = fn();//113 fun();//114 fun();//215 console.log(i);//0首先我们需要了解js运行流程:首先进行语法解析;先通篇的检查js语法,若语法有误,则报错 。其实进行预编译;即发生在代码执行之前,为代码的执行做的准备工作,一般表现于变量提升,即把变量的声明提前,但是赋值还是在响应位置赋值,再者就是把整个函数声明提前 。最后js运行流程进入最后一步即解析执行 。
搞懂js运行流程再区分作用域,即全局作用域和函数作用域,全局作用域顾名思义就是全局声明的变量或函数等 。函数作用域也就是函数内部的作用域,在函数内部中声明的变量或函数是不会传到全局作用域的 。
搞懂这两个概念这一题就能够迎刃而解了,首先全局声明了一个变量i并赋值为0,在声明一个fun接受fn执行后的返回值,所以fn会执行一次,局部变量i在fn函数中重新声明,变量提升,这时函数fn中使用的i都为函数作用域中声明的i,并且重新赋值为1,输出结果1 。这里不会影响到全局变量i的值 。再观望整体代码,全局变量i未被重新赋值,所以最后一行i输出为0.
再往下走,fu函数的返回值也是一个函数,所以fun接收到的是一个函数,fun函数被执行两次,注意到在fn函数中,i被重新声明过,所以这里的返回值函数即fun函数的作用域为局部作用域,使用的变量i为局部变量,即再fn函数中声明的i,所以输出1 。输出之后i自增1,即 i = i+1,局部作用域i的值在fun函数弟一次执行后变为2,再次执行后,输出i为2 。
3.值类型和引用类型这一题主要涉及到值类型和引用类型的存储方式,即堆内存和栈内存 。
1 function fn(obj) {2obj.name = "name";3obj = new Object();4obj.name = "newName";5 }6 var xt = new Object();7 fn(xt);8 console.log(xt.name);//name首先题目中声明了一个函数fn和一个对象xt,调用fn函数,并把xt传入函数 。这是第二行的obj和xt都为引用类型,新增了obj的属性name值也为name 。由于此时obj和xt指向的同一片内存空间,所以xt也会新增name属性,并设置值为name 。故最后一个输出name 。
在第三行中可以看到obj被重新赋值,即重新开辟了一片内存空间,这时obj依然为新增name属性而不是修改name属性,并将name属性设置为newName,所以这是obj新增的属性不会影响到对象xt的属性 。
4.同步和异步这一题主要是考察异步代码和同步代码执行的先后顺序以及js任务队列 。
1for (let index = 0; index < 5; index++) { 2setTimeout(() => { 3console.log(index); 4}, 200); 5} 67for (let j = 0; j < 5; j++) { 8setTimeout(() => { 9console.log(j);10}, 200);11}首先可以看到题目中有两个循环体,两个循环体中分别有两个延时200ms的延时器 。做题之前我们应该先了解到JavaScript对于同步代码和异步代码的处理方式,js会先执行同步代码,遇到异步代码(例:延时器、计时器、Promise等)会先放置任务队列,等待触发条件依次执行 。这个概念了解清楚后这题就能够迎刃而解了 。
首先两个循环体为同步代码,会先执行 。此时第一个循环体会将循环出的五个延时器放置任务队列,等待200ms后执行 。第二个循环体也是如此,所以输出为“0 1 2 3 4 0 1 2 3 4” 。
5.宏任务和微任务此题主要是考察对于同步异步,以及宏任务和微任务的理解 。
//写出执行结果setTimeout(() => {console.log(1);}, 0);new Promise((res) => {console.log(2);for (var index = 0; index < 1000; index++) {index = 9999 && res()}console.log(3);}).then(() => {console.log(4);})console.log(5);此题最终输出结果为“2 3 5 4 1”;
解答此题我们需要先了解到Promise的特性 。Promise是异步编程的一种解决方案,是解决恐怖回调/回调噩梦的一种方案,其就相当于一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果 。
创建promise对象,function就相当于容器,用于存放异步代码(不仅限于异步,同步也可以),此函数在页面加载时会正常执行,同步代码会进入主线程执行,异步代码会进入任务队列,未来才会得到结果 。并且Promise有三种状态,进行时(pending默认值),已成功(fulfilled/resolved),已失败(rejected)一旦状态改变,就不会再变,任何时候都可以得到这个结果,成功后会调用.then()方法,then方法接受两个参数,皆为回调函数,第一个函数promise状态变为已成功时触发的,第二个函数promise状态变为已失败时触发 。
了解了Promise后,我们还需要搞清楚宏任务和微任务的概念 。在上面我们提到过,js会见异步代码放置任务队列,宏任务是由宿主(Node、浏览器)发起的,常见的就是计时器和延时器;而微任务是由js引擎发起的,常见的就时Promise;执行顺序为微任务先执行,宏任务后执行 。
这时我们就可以来解答这个题目了,首先遇到延时器,为宏任务,放入任务队列,其实遇到promise,先执行promise的同步代码,输出2,再进入循环,第一次进入循环index被重新赋值为9999,并且将promise的状态改为已成功,再往下走输出3;
此时promise状态为已成功,触发then方法的第一个函数,但是promise响应为异步响应 。并且为微任务,放置任务队列,排在宏任务之前 。再往下走就输出5 。
此时同步代码执行完毕,开始执行异步代码,先执行微任务,输出4,在执行延时器代码 。输出5 。
【前端常见面试题】好啦 。以上就是小谭今天分享的内容啦,也欢迎各位一起来讨论技术呀!文章中有不足的地方小谭也欢迎各位指正探讨,不胜感激!
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
