本文记录前端面试中的一些常见题型,如果有幸让你看到了这篇文章,欢迎探讨学习!
编程题
实现 call 函数
call
函数的作用,可以改变调用者函数内部的 this
指向,立即执行,第二个参数为 rest
类型参数。如果没有指定第一个参数,则 this
指向 window。
1 | Function.prototype.myCall = function(con) { |
我们在使用 _fn
作为临时属性时,使用的是 Symbol
类型,这是为了避免与上下文环境中的其他属性重复而发生冲突。
实现 apply 函数
apply
函数的作用,可以改变调用者函数内部的 this
指向,立即执行,第二个参数为数组类型。如果没有指定第一个参数,则 this
指向 window。
1 | Function.prototype.myApply = function(con, arr = []) { |
实现 bind 函数
bind
函数的作用,返回新的函数,该函数内的 this
指向 bind
函数的第一个参数对象,第二个参数为传入新函数内的 rest 参数。如果没有指定第一个参数,则 this
指向 window。
1 | Function.prototype.myBind = function(con) { |
对多维数组进行降维(扁平化)
实现的效果类似这样:
1 | let arr = [[1, [2]], [3], [4]]; |
扁平化后,如下所示:
1 | let flatArr = [1, 2, 3, 4]; |
方式 1:
1 | let arr1 = [1, [2, [4, [5]]], 3].flat(Infinity); |
方式 2:
1 | const flattenDeep = arr => { |
方式 3:
使用 generater
函数 和 for ...of
循环 或 使用 扩展运算符 ...
也行。
1 | function* iterArr(arr) { |
实现支持注册、分发和解绑的事件类
1 | // 数组置空的方法: |
实现斐波那契数列
1 | function* fib() { |
利用 Generater
函数 和 for ...of
循环可以很巧妙的实现,注意,generator
函数在被执行后,里面的代码并不会立即执行,需要依靠遍历器驱动 yield
执行。
所以,for(;;){}
并不会有什么性能问题。
实现防抖和节流函数
- 防抖
功能:触发高频事件后 interval 毫秒内函数只会执行一次,如果 interval 毫秒 内高频事件再次被触发,则重新计算时间。
会清除定时器,对于高频率触发的动作,会限制其频率降低。
1 | function debounce(fn, interval = 300) { |
- 节流
功能:高频事件触发,但在 interval 毫秒内只会执行一次,所以节流会稀释函数的执行频率。
不会清除定时器,对于高频率触发的动作,会减少其触发次数。
1 | function throttle(fn, interval = 1000) { |
实现对字符串进行金额格式化的功能函数
显示类似如下的字符串格式转换功能。
1 | let num = 52545455454; |
实现:
1 | function toPriceRight(str, gap, type) { |
对指定数组生成树形结构数据
题目:对于如下数据,pid
表示 父节点的值,如果没有 pid
则表示该对象对象为根节点,请将其格式化为树形数据结构,要求可以达到无限深度。
1 | let origin = [ |
实现:
1 | function tree(arr, ori) { |
实现倒计时功能
1 | const endtime = +new Date("2019/12/15 0:0:0"); //定义结束时间日期 |
给定一个数组,对里面所有的奇数求和
1 | let arr = ["1", "2", "3", 6, 4, -99, -101]; |
函数柯里化
题目:完成 bindLeft 实现函数参数的部分绑定功能。
1 | function bindLeft() { |
使用方法如下:
1 | let fn1 = (a, b, c, d) => a - b * c + d; |
实现:
1 | let fn1 = (a, b, c, d) => a - b * c + d; |
使用冒泡排序对数组中所有正整数排序(非正整数位置保持不变)
1 | let arr = [11, -1, 6, 5, -4, -7, 9, 8]; |
已知一个对象 obj ,在不知道第一个属性键名的情况下,如何获取第一个属性的值
1 | let obj = { a: 1, b: 2 }; |
将数组去除重复项并按降序排列
1 | let arr = [2, 0, 1, 8, 0, 2, 1, 5]; |
看题作答
- 请写出下面程序的打印结果
1 | var p = new Promise((resolve, reject) => { |
对于以上这类型的题,看到 Promsie
和 setTimeout
这样的字眼,就知道肯定考察的是与 js 的运行机制 事件循环
相关的。
ok,我们捋一下上面代码的执行过程:
首先,new Promise()
构造函数被执行,console.log('a')
被率先执行。打印出 a
。
然后,遇到 setTimeout()
函数,其被执行后,回调函数被推入 宏任务
队列中,等待下一轮事件循环时执行。
紧接着,p.then()
被执行,其中的回调函数被推入 微任务
队列中,等到这一轮事件循环的执行栈为空时,再清空 微任务
队列。
接下来,同步代码 console.log('b')
被执行。打印出 b
此时,执行栈空,清空 微任务
队列,console.log('c')
被压入执行栈中执行。打印出 c
。
最后,开始第二轮事件循环,console.log('d')
出队,压入执行栈中执行,打印出 d
。程序结束。
所以最终的打印结果为:
1 | // a b c d |
- 请写出下面程序的打印结果
1 | var x = 0; |
ok!定眼一看,这是一道有关 this
问题的题目。所以,你的脑中应该迅速回忆起 this
相关的知识点。
该题涉及到 3
种 this
指向情况:
普通函数中的
this
对象方法中的
this
被
apply
改变过的this
首先,代码中,在全局定义了 3 个变量:变量x
、test
函数、对象o
。
第一条执行语句,使用 apply
的方式调用了 o.m()
方法。这里只要使用了 apply
函数,没有指定 thisArg
的话,那么 o.m()
方法中的 this
就指向 window
。所以打印出 0
第二条执行语句,test()
被直接调用,其中的 this
指向全局 window
,打印出 0。